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命令的妙用

Docker使用指南

環境建置步驟

  1. Vagrant下載頁安裝Vagrant
  2. Virtualbox下載頁安裝
    • VirtualBox platform packages
    • VirtualBox Extension Pack
  3. 建立工作目錄
    • $sudo mkdir docker-demo && cd docker-demo
  4. 產生Vagrantfile => ubuntu/trusty64: Ubuntu 14.04 LTS (Trusty Tahr) 64-bit
    • $sudo vagrant init ubuntu/trusty64
  5. 根據Vagrantfile啟動定義好的虛擬機
    • $sudo vagrant up
  6. 登入vagrant
    • $sudo vagrant ssh
  7. 登入vagrant
    • $sudo vagrant exit

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

LoopBack簡介

方便建立 API 和連接後端資料的 Node.js Framework

關於

LoopBack 是一個高度擴展、開源的 Node.js 框架

  • 快速建立動態的 end-to-end REST APIs
  • 連接設備跟瀏覽器的數據跟服務
  • 採用 AndroidIOSAngularJS 軟件開發工具包能夠輕鬆地創建客戶端應用程序
  • 附加組件含,推播、檔案管理、第三方登入及地理定位
  • 使用 StrongLoop Arc 做到可視化編輯,部署和監控 LoopBack apps
  • LoopBack API gateway 作為使用 API 的顧客 (clients) 和 API 提供者的中間人達到外部化、安全及管理的 APIs
  • 可運行在本地或雲端

特點

  • 快速建立 model 及創建 REST 的 API

    • 簡單易用的 CLI 精靈
    • 如果你有 schema 的話根據他創建 models
    • 如果沒有則建立動態 models
    • 內置的 API 瀏覽器
  • 簡易的認證跟授權設置

    • 內置基於角色的存取控制
    • oAuth 使用者跟註冊模型
    • 使用 CLI 跟 JSON 格式增加個人設置策略
    • 瀏覽器支援 ( JSONP 和 CORS )
  • 支持模型關係

    • 定義 hasMany,belongsTo,hasAndBelongsToMany 關係
    • 自動生成相應關係的 REST 端點
  • MIT 開源許可

    • 雙許可:MIT 開源許可或 StrongLoop 許可
  • 連接後端數據儲存支援

    • MySQL, Oracle, MongoDB, Postgres 和其他
    • 其他 REST 服務
    • Oracle, MySQL, PostgreSQL 和 SQL Server 探索 APIs
  • 即席查詢支援

    • 裝置上的動態查詢,瀏覽器跟 Server
    • 針對關係資料庫支援 NoSQL 風格的查詢

開始使用

安裝

假設你已經安裝 Node.js
透過 npm 安裝 LoopBack 應用的 StrongLoop 工具

$ npm install -g strongloop

建立 app

建立一個 “Hello World” LoopBack app

npm & package.json

npm - Node Package Manager,Node 官方的組件管理方式,

npm 透過 command line 執行,並使用 package.json 檔案幫 node.js app 管理使用組件依賴關係。
也可以讓使用者安裝已經在 npm 官網註冊的 package。

現在安裝 Node.js 會自帶 npm

查看 npm 版本

$npm -v

更新 npm 到最新的版本

$npm install -g npm@latest

使用 npm 安裝套件

例如安裝 express 包(一個 web framework)
$npm install express

可以在這找到有哪些包可以安裝
https://www.npmjs.com/

或是透過指令搜尋
$ npm search

什麼是Node.js?

Node.js 是一個平台。採用 Chrome 瀏覽器的 Javascript 引擎 - V8,為了可以簡單的建立,快速、可擴展的網路應用。    


Node.js

  • Server - side javascript
  • 單一執行緒事件迴圈 (single-threaded event loop)
  • 使用事件驅動 (event-driven),非阻斷式的 IO(non-blocking I/O) 模型。這讓他輕量並且有效率。
  • 適合在分散式的裝置上,做資料密集、即時的處理程序。

主要元件:

V8

美國Google開發的開源JavaScript引擎,用於Google Chrome中。
執行之前將JavaScript編譯成了機器碼(machine code),而非傳統方式直譯(interpreting)位元組碼(byte code),以此提升效能。
使用了如內聯緩存(inline caching)方法來提高效能。

Wiki - http://en.wikipedia.org/wiki/V8_(JavaScript_engine)



APIs

http://nodejs.org/api/

libuv

Github - https://github.com/libuv/libuv

支援多個平台的非同步I/O Libary,包含:

  • Signal handling
  • Thread pool
  • ANSI escape code controlled TTY
  • File system events
  • Asynchronous file and file system operations
  • Asynchronous DNS resolution
  • Asynchronous TCP and UDP sockets
  • event loop backed by epoll, kqueue, IOCP, event ports
  • High resolution clock
  • Threading and synchronization primitives
  • IPC with socket sharing, using Unix domain sockets or named pipes (Windows)
  • Child processes



安裝 Node.js

到Node.js的官網 http://nodejs.org/download/ 選取要安裝的平台,下載安裝即可。

官方下載連結 - http://nodejs.org/download/


安裝完畢後,開啟終端機模式。
輸入 node -v 指令。
會在畫面顯示目前安裝的 Node.js 版本號,

看到此畫面表示已安裝成功。