Mongodb's Replica Set & Sharded Cluster

MongoDB Replication

Primary 接受所有從client傳來的寫入操作

Primary 接受所有從client傳來的寫入操作

Replica set (副本集) 只會有一個 Primary,因為只有一個成員接受寫入操作。副本集提供嚴格的一致性,對所有從 Primary 的讀取。

為了支持複製操作,Primary 記錄其所有對其數據集的操作到他的 oplog (operations log)。

Secondaries 複製 Primary 的 oplog 到自己的數據集。

Secondaries 的數據集印射 Primary 的數據集。

如果 Primary 不能用,Replica set 會選出一個 Secondary 成為 Primary

預設情況下,clients 從 Primary 讀取,但是 clients 可以指定一個喜好的來發送讀取操作到 Secondary。從 Secondaries 讀取返回的資料可能不會反射 Primary 的狀態。

你可以增加一個額外的 mongod 實例作為 replica set的 Arbiter (仲裁者)。它不用來維護數據集,只存在於選舉投票。

一個 Secondary 可能會經由一次選舉變為 Primary

ps:

  • 預設當作primary的server未經initiate()不會被設定為primary,無法在上面進行任何DB操作

  • 作為secondary的server在arbiter未被建立前不會跟primary同步資料

MongoDB Sharding

Sharding 是將儲存資料跨不同機器的方法。

高查詢率會消耗 Server CPU 的能力,大型資料超過單一機器儲存的上限。

為了解決這些問題資料庫有兩種解決方式:

  • Vertical scaling : 垂直擴展,就是增加 CPU、增加 Ram 跟增加更多的儲存資源。
  • Horizontal scaling : 水平擴展,使用 sharding(分片)機制,分割數據集使之可以跨越在多個 Server 中,或shards(碎片)。

每個 shard 都是一個獨立的資料庫,很多個 shards 可以組成單一個邏輯資料庫。

Sharding 減少了每個 Server 需要儲存的資料量。當 Cluster(集群)增長時,每個 Shard 儲存了更少的資料量。

舉例來說,一個資料庫擁有 1TB 的資料數據,分成4個 shards 來存,每個需管理 256GB 的資料量。

假如分配給40個 shards,每個 shard 只需管理 25GB 的資料而已。

一個 MongoDB 的 Sharded Cluster 由以下元件組成 : shardsquery routersconfig servers

  • Shards : 用來儲存資料,為了提高可用性和資料的一致性,在 production 的
    Sharded Cluster 每個 Shard 通常是一個 Replica Set (副本集)。

  • Query Routers : 在 MongoDB 裡稱為 mongos,作為讓 client 端可以直接操作到對應的 shards的一個介面。一個 Sharded Cluster 可以擁有多個 Routers 來分擔 client 發過來的要求。

  • Config servers : 儲存 cluster 的 metadata(用來描述資料屬性)

Data Partitions(資料分割)

Sharding partitions a collection’s data by the shard key.

Shard Keys

要對一個collection做分片(shard),需要選擇 shard key

MongoDB 由 shard key 將資料分割成許多的 chunks 平均分佈在 shards。依據 range based 和 hash based 不同種的 shard key,可以對資料做不同的儲存策略。

Range Based Sharding

Hash Based Sharding

Customized Data Distribution with Tag Aware Sharding

維持分散資料平衡

MongoDB使用兩個背景程式處理確保一個 blanced cluster:splitting & balancer.

  • Splitting

    Splitting,一個背景程式,確保 chunks 的成長不會太大。當一個 chunk 成長為指定的 chunk 大小(specified chunk size)時,會將 chunk 分成兩半。

    MongoDB 預設的 chunk size 為 64 MB,你可以增加或減少 chunks size

    1. 比較小的 chunks,會讓資料更均勻的分佈,但是在資料搬移時花費更多的成本。
    2. 比較大的 chunks,無論是從網路的角度和在內部開銷方面,讓資料做比較少的搬移。但是這些效率可能會造成資料分佈不均的代價。
    3. chunk 的大小,會影響每個 chunk 搬移(migrate)的最大文件數量。

  • Blancing

    Blancer,一個背景程式,來管理 chunks 資料的搬移。Blancer 可以藉由 cluster 任何的 query routers 來被執行。

    Manage Sharded Cluster Blancer

實作練習

使用 MongoDB 這樣做的優點,對延展(scaling)方便資料,並擁有一定的可靠度。當資料儲存空間快不足時,可以對其增加新的 shards,增加 cluster server 的儲存量。

已有三台可用的 server 機,利用這三台機器組成一個 Sharded Cluster Server。

目前規劃架構,每台機器各擁有一個 query router server (mongos) ,各一個 config server,這三台機器組成的 cluster server 擁有 3 個 cluster shards,每個 shard 都是一個副本集 (replica set),分散在3台機器裡。

movePrimary

movePrimary命令的妙用

MongoDB The Definitive Guide讀書筆記

紀錄讀MongoDB: The Definitive Guide這本書時,自己認為的重點

DataBase名稱可以用任何 UTF-8 字串,並且符合以下規則

  • 空字串不是有效名稱
  • 不能包含/, \, ., “, *, <, >, :, |, ?, $, (a single space), or \0 (the null character)
  • 名稱有區分大小寫,即使在不分大小寫的檔案系統裡
  • 最大限制 64 bytes

預先留存的DataBase,含有特殊的含義

  • admin : 代表root DataBase,如果一個user被加入此DB,該user自動繼承允許連到其他DB
  • local : 這個DB永遠不會被replicated,慣用於儲存any collections that should be local to a single server
  • config : 用來sharded setup,儲存shard的資訊

mongod預設儲存的資料路徑 /data/db/

預設的port=27017

可以用 —httpinterface 這個參數設定一個簡單的http interface 他的port指定為主要port多1000。以預設port為例,可以連到http://localhost:28017觀看

備份&還原MongoDB資料庫

Command Line Tool

備份資料

mongodump

範例:
將遠端Sever上的MongoDB資料備份 Bet 到本地端 ./tmp/Backup 位置
$mongodump --host 172.16.18.65:27017 --db Bet --out ./tmp/Backup

還原資料

mongorestore

範例:
將本地端 ./tmp/Backup 位置的MongoDB備份資料還原到 localhost:30001
$mongorestore --host localhost:30001 ./tmp/Backup/

經測試可以將single instance server的資料dump出來,restore到cluster server 的 shards

PS:version 3.0.1 測試mongorestore 無法透過mogos上使用

在replica set 上的 primary上可以成功,未initiate的不能使用

部署Mongodb Sharded Cluster

可擴展的MongoDB解決方案

官方文件:http://docs.mongodb.org/manual/tutorial/deploy-shard-cluster/

本地端部署 MongoDB Shard Cluster

( 2 Router Server, 3 Config Server, 3 Shard Server )的shell script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/bin/bash
#參考 http://docs.mongodb.org/manual/tutorial/deploy-shard-cluster/
##################################################################################################################
# WARNING
# Sharding and “localhost” Addresses
#
# If you use either “localhost” or 127.0.0.1 as the hostname portion of any host identifier,
# for example as the host argument to addShard or the value to the --configdb run time option,
# then you must use “localhost” or 127.0.0.1 for all host settings for any MongoDB instances in the cluster.
# If you mix localhost addresses and remote host address, MongoDB will error.
##################################################################################################################
_redColor='\033[0;31m'
_yellowColor='\033[1;33m'
_greenColor='\033[0;32m'
_noColor='\033[0m' # No Color
#設定執行目錄
DB_ROOT_PATH=~/data
#Shard Server設定
SHARD_PATH_1=$DB_ROOT_PATH'/shard1'
SHARD_PORT_1=10001
SHARD_PATH_2=$DB_ROOT_PATH'/shard2'
SHARD_PORT_2=10002
SHARD_PATH_3=$DB_ROOT_PATH'/shard3'
SHARD_PORT_3=10003
#Config Server設定
CONFIG_PATH_1=$DB_ROOT_PATH'/config1'
CONFIG_PORT_1=20001
CONFIG_PATH_2=$DB_ROOT_PATH'/config2'
CONFIG_PORT_2=20002
CONFIG_PATH_3=$DB_ROOT_PATH'/config3'
CONFIG_PORT_3=20003
#Router Server設定
ROUTER_PORT_1=30001
ROUTER_PORT_2=30002
# echo "kill 舊的 process"
# kill $(ps aux | grep mongo | awk -F" " '{print $2}')
echo -e "${_greenColor}開始本地部署 mongodb sharded cluster in localhost...${_noColor}"
#清空DB資料
echo -e "${_greenColor}清空DB資料...${_noColor}"
echo -e "${_yellowColor} -> ${DB_ROOT_PATH}${_noColor}"
rm -rf $DB_ROOT_PATH
#建立DB目錄
echo -e "${_greenColor}建立DB目錄...${_noColor}"
echo -e "${_yellowColor} -> ${SHARD_PATH_1}${_noColor}"
echo -e "${_yellowColor} -> ${SHARD_PATH_2}${_noColor}"
echo -e "${_yellowColor} -> ${SHARD_PATH_3}${_noColor}"
echo -e "${_yellowColor} -> ${CONFIG_PATH_1}${_noColor}"
echo -e "${_yellowColor} -> ${CONFIG_PATH_2}${_noColor}"
echo -e "${_yellowColor} -> ${CONFIG_PATH_3}${_noColor}"
mkdir -p $SHARD_PATH_1 $SHARD_PATH_2 $SHARD_PATH_3 $CONFIG_PATH_1 $CONFIG_PATH_2 $CONFIG_PATH_3
echo -e "${_greenColor}Set 3 Config Server...${_noColor}"
echo -e "${_yellowColor} -> localhost:${CONFIG_PORT_1}${_noColor}"
echo -e "${_yellowColor} -> localhost:${CONFIG_PORT_2}${_noColor}"
echo -e "${_yellowColor} -> localhost:${CONFIG_PORT_3}${_noColor}"
mongod --dbpath $CONFIG_PATH_1 --port $CONFIG_PORT_1 --fork --logpath $DB_ROOT_PATH'/config1.log'
mongod --dbpath $CONFIG_PATH_2 --port $CONFIG_PORT_2 --fork --logpath $DB_ROOT_PATH'/config2.log'
mongod --dbpath $CONFIG_PATH_3 --port $CONFIG_PORT_3 --fork --logpath $DB_ROOT_PATH'/config3.log'
#講解 --fork http://chenzhou123520.iteye.com/blog/1634676
echo -e "${_greenColor}Set 2 Router Server...${_noColor}"
echo -e "${_yellowColor} -> localhost:${ROUTER_PORT_1}${_noColor}"
echo -e "${_yellowColor} -> localhost:${ROUTER_PORT_2}${_noColor}"
mongos --configdb localhost:$CONFIG_PORT_1\
,localhost:$CONFIG_PORT_2,\
localhost:$CONFIG_PORT_3 \
--port $ROUTER_PORT_1 --fork --logpath $DB_ROOT_PATH'/router1.log'
mongos --configdb localhost:$CONFIG_PORT_1\
,localhost:$CONFIG_PORT_2,\
localhost:$CONFIG_PORT_3 \
--port $ROUTER_PORT_2 --fork --logpath $DB_ROOT_PATH'/router2.log'
echo -e "${_greenColor}Set 3 Shard Server...${_noColor}"
echo -e "${_yellowColor} -> localhost:${SHARD_PORT_1}${_noColor}"
echo -e "${_yellowColor} -> localhost:${SHARD_PORT_2}${_noColor}"
echo -e "${_yellowColor} -> localhost:${SHARD_PORT_3}${_noColor}"
mongod --dbpath $SHARD_PATH_1 --port $SHARD_PORT_1 --nojournal --fork --logpath $DB_ROOT_PATH'/shard1.log'
mongod --dbpath $SHARD_PATH_2 --port $SHARD_PORT_2 --nojournal --fork --logpath $DB_ROOT_PATH'/shard2.log'
mongod --dbpath $SHARD_PATH_3 --port $SHARD_PORT_3 --nojournal --fork --logpath $DB_ROOT_PATH'/shard3.log'
#講解 --nojournal http://blog.chinaunix.net/uid-15795819-id-3381684.html
echo -e "${_greenColor}Add Shard Node...${_noColor}"
mongo localhost:$ROUTER_PORT_1 --eval 'printjson(sh.addShard("localhost:'$SHARD_PORT_1'"))'
mongo localhost:$ROUTER_PORT_1 --eval 'printjson(sh.addShard("localhost:'$SHARD_PORT_2'"))'
mongo localhost:$ROUTER_PORT_1 --eval 'printjson(sh.addShard("localhost:'$SHARD_PORT_3'"))'
# echo -e "${_greenColor}### Setup Finished!!! ###${_noColor}"
echo -e "${_greenColor}Enable Sharding for a Database...${_noColor}"
mongo localhost:$ROUTER_PORT_1 --eval 'printjson(sh.enableSharding("Cluster_DB"))'
echo -e "${_greenColor}Enable Sharding for a Collection...${_noColor}"
mongo localhost:$ROUTER_PORT_1 --eval 'printjson(sh.shardCollection("Cluster_DB.users", {"_id": "hashed"} ))'
echo -e "${_greenColor}MongoDB Shell${_noColor}"
mongo localhost:$ROUTER_PORT_1

Gist:https://gist.github.com/miles990/f06d123a1afc1aa86c95