2021 iThome 鐵人賽 MongoDB披荊斬棘之路
DAY18 MongoDB Replication 實戰
本篇我們要使用 Dcoker compose
方式實作 MongoDB replication,又快速又方便,如果不太熟的可以去參考之前文章 DAY2 安裝與使用 MongoDB。
上一篇文章有提到(怎麼又是之前文章啊?這樣代表我的文章有連貫性啊) MongoDB replication 至少需要有三個實體。
首先我們建立一個 yml 檔案 docker-compose.yml
,開始寫我們計劃中的設定。
替這次 replication 取個名字叫做 ith2021-rs
三個節點名稱與port分別為
- mongo_node1 : 27666
- mongo_node2 : 27667
- mongo_node3 : 27668
再拿之前的範例來修改就完成了!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| version: '3' services: mongo_node1: container_name: mongo_node1 image: mongo ports: - 27666:27666 command: mongod --port 27666 --bind_ip_all --replSet ith2021-rs mongo_node2: container_name: mongo_node2 image: mongo ports: - 27667:27667 command: mongod --port 27667 --bind_ip_all --replSet ith2021-rs mongo_node3: container_name: mongo_node3 image: mongo ports: - 27668:27668 command: mongod --port 27668 --bind_ip_all --replSet ith2021-rs
|
我們可以看到這次啟動的指令多了 --replSet ith2021-rs
,就是指定 replica set 的名稱。
設定 replica set
透過上面的 yml 啟動後確實可以看到三個實體,但它們三個還不認識彼此,這時候就必須進行 replica set 初始化的動作,這時候直接執行會出現…
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| > rs.initiate() { "info2" : "no configuration specified. Using a default configuration for the set", "me" : "17dca5869ff9:27666", "ok" : 1, "$clusterTime" : { "clusterTime" : Timestamp(1631433581, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1631433581, 1) }
|
它會告訴你沒有任何設定檔,所以用預設值來設定。這時候就很麻煩,需手動敲指一個一個節點加進去 replica set。
懶惰如我,我們把這段用指令方式放進 docker compose 的 healthcheck
方式自動執行,這樣就可以省掉一個動作了。(注意啊~這是本機方便快速測試用才會這樣做,部署到其他環境還是要抽出到正確的職責位置)
完整的 yml
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
| version: '3' services: mongo_node1: container_name: mongo_node1 image: mongo ports: - 27666:27666 command: mongod --port 27666 --bind_ip_all --replSet ith2021-rs mongo_node2: container_name: mongo_node2 image: mongo ports: - 27667:27667 command: mongod --port 27667 --bind_ip_all --replSet ith2021-rs mongo_node3: container_name: mongo_node3 image: mongo ports: - 27668:27668 command: mongod --port 27668 --bind_ip_all --replSet ith2021-rs healthcheck: test: ["CMD","mongo","--host","mongo_node3","--port","27668", "--eval", 'rs.initiate( { _id : "ith2021-rs", members: [{ _id: 0, host: "mongo_node1:27666" }, { _id: 1, host: "mongo_node2:27667" }, { _id: 2, host: "mongo_node3:27668" }]})'] interval: 10s
|
啟動後隨便連入一台 MongoDB 看看,再次輸入 rs.initiate()
會出現什麼…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| ➜ source git:(master) ✗ mongo --host 127.0.0.1 --port 27666 MongoDB shell version v4.0.3 connecting to: mongodb:
ith2021-rs:SECONDARY> rs.initiate() { "ok" : 0, "errmsg" : "already initialized", "code" : 23, "codeName" : "AlreadyInitialized", "$clusterTime" : { "clusterTime" : Timestamp(1631434164, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1631434164, 1) } ith2021-rs:SECONDARY>
|
會告訴你已經初始化完成了。
驗證資料同步
要如何驗證資料同步呢?最簡單方式就是寫入一筆資料,確認次節點有沒有同步就可以了。還記得我們提到僅有主節點能夠執行資料修改內容,於是我們先隨便連進一台,接著查看 Primary
節點是哪一台。
尋找 Primary
指令是 rs.status()
不過內容太多了,我們只需要查看這個 rs 內的會員即可。
rs.status().members
不過內容細節還是很多,我就不在這貼出來佔版面,可以使用一點 js 語法來撈出我們要看的內容。
1 2 3 4
| ith2021-rs:SECONDARY> rs.status().members.forEach(x=>print(`${x.name}/${x.stateStr}`)) mongo_node1:27666/SECONDARY mongo_node2:27667/SECONDARY mongo_node3:27668/PRIMARY
|
在主節點寫入資料
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ➜ source git:(master) ✗ mongo --host 127.0.0.1 --port 27668 MongoDB shell version v4.0.3 connecting to: mongodb:
ith2021-rs:PRIMARY> use testdb switched to db testdb
ith2021-rs:PRIMARY> db.testcol.insert({field:'iThome 2021 ironman BEST!'}) WriteResult({ "nInserted" : 1 })
ith2021-rs:PRIMARY> exit bye
|
次節點查看
剛剛已經在主節點寫入資料了,讓我們來隨便連到一個次節點看看有沒有這筆資料囉
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
| ➜ source git:(master) ✗ mongo --host 127.0.0.1 --port 27666 MongoDB shell version v4.0.3 connecting to: mongodb:
ith2021-rs:SECONDARY> use testdb switched to db testdb ith2021-rs:SECONDARY> db.testcol.find() Error: error: { "topologyVersion" : { "processId" : ObjectId("613db58d9e315ff6c1c2fe94"), "counter" : NumberLong(4) }, "ok" : 0, "errmsg" : "not master and slaveOk=false", "code" : 13435, "codeName" : "NotPrimaryNoSecondaryOk", "$clusterTime" : { "clusterTime" : Timestamp(1631434784, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1631434784, 1) } ith2021-rs:SECONDARY>
|
沒想到居然跳錯誤,但是也不用太緊張,這是因為 secondary
預設是關閉查詢的,我們只需要打開即可。
1 2 3 4 5
| ith2021-rs:SECONDARY> rs.slaveOk()
ith2021-rs:SECONDARY> db.testcol.find() { "_id" : ObjectId("613db79ea937743f1dc6af82"), "field" : "iThome 2021 ironman BEST!" } ith2021-rs:SECONDARY>
|
就看到這筆資料囉~代表資料真的是有自動同步到次節點。
1 2 3 4
| 我想說的是這指令 rs.slaveOk().. ok 你個頭 其實這指令已經被改為 rs.secondaryOk() 在 MongoDB 裡面逐漸把 Master/Slave 改為 Primary/Secondary 了 不知道什麼時候會完全移除這些指令就是了,所以請記得改用 rs.secondaryOk()
|
建立 replica set 介紹就差不多到這邊了,架設測試用的環境不會遇到太大的困難,後面要加入密碼和key會稍微麻煩一點,不過不在這次的範圍內,也許之後再找時間來發教學文了。
後面開始會講一點維運的東西,跟 oplog
息息相關。