2012年9月3日 星期一

MongoDB Replication 簡記

Standard
就在幾天前,MongoDB 邁入了 2.2.0 的穩定版本。我們若回頭來看,MongoDB 一直到了 2.0 前後,比起早期版本,已經有長足的進步,並且支援了相當多的功能,也對規模化和資料庫系統管理下了很多功夫。對於大多數的資料庫應用,已經非常適合。

若你對資料庫相關技術有些了解,就會知道,當資料庫的資料發展一定規模程度,或是要確保系統不當機時,我們就需要用到 Master/Slave 的方式去備份和備援,當主要(Master)伺服器出了問題,次要(Slave)伺服器便即時補上,保持系統運作。但是,既然已經有 Master/Slave 機制,是否可以有更多台備援呢?更或者進一步,將讀寫分開在不同伺服器,以分攤流量和系統負載,並加速讀寫速度。而 Replication 就是這樣的機制,可以用來動態同步多台資料庫伺服器的資料,也可以當主要伺服器因故下線時,讓其他伺服器即時替補主要機器的位置。

在 Debian 上設定 MongoDB 的 Replication 相當容易,首先在想要變成主要(Primary)的機器上,打開設定檔(/etc/mongodb.conf),並為我們的 Replication 群組命名(在 MongoDB 中稱為 ReplSet,一些書籍內翻譯成『複製組』):
replSet = mydb

重新啟動 MongoDB:
$ sudo service mongodb restart

使用指令 mongo,進入 MongoDB 命令模式:
$ mongo

於 MongoDB 命令模式中執行:
# 初使化 replSet
rs.initiate(null)

# 加入自己的 IP 位置
rs.add("192.168.11.1:27017")

若是回應成功,請先稍待數秒鐘,等伺服器偵測和初使化。然後會發現 MongoDB 的命令提示字元從『SECONDARY』變成『PRIMARY』,此時,代表這台機器已經變成 ReplSet(複製組) 中的主要機器。

同樣的,你可以開始為 ReplSet 加入其他次要的資料庫伺服器:
rs.add("192.168.11.2:27017")
rs.add("192.168.11.3:27017")
rs.add("192.168.11.4:27017")
rs.add("192.168.11.5:27017")

這邊要注意一點,如果你的 replSet 中只有兩台 MongoDB (包括 Primary 自己),單單這樣設定,會發生無法判定 Primary 該給誰的問題。因為 MongoDB 的機制,是讓眾伺服器投票決定誰當 Primary,但經測試發現,一個 RelpSet 中只有兩台機器時,常會發生問題,造成整個群組中無 Primary 機器的狀態。所以,這時要加入仲裁者(Arbiter)機器來協助排除。

Arbiter 設定很簡單,你要先準備第三台機器,裝上 MongoDB 和設定 /etc/mongodb.conf 裡的 replSet,接著在 Primary 主機上把這台機器加入到 Arbiter 伺服器清單:
rs.addArb("192.168.11.100:27017")
註:Arbiter 因為不處理資料,所以負載並不高,理論上也可以和原本的資料庫放在同一台機器上,但請注意,如果你要這樣做,需要另外啟動第二個 mongod 服務,並跑在不同的 Port。由於這樣的做法,在 Debian 上沒有標準安裝步驟,就不在本文詳述。此外,如果你只有兩台資料庫主機,記得兩台上面都要架設 Arbiter,這樣,當其中一台當機時,replSet 中還有一個 Arbiter 來決定 Primary 該給誰,不然也會發生整個群組中無 Primary 機器的問題,哪怕只剩一台機器還活著,MongoDB 依然憂柔寡斷的不知道該不該篡位。

最後一步,在其他主機上都將 /etc/mongodb.conf 設定好,並進入 mongo 命令模式初使化,MongoDB 會自動同步 replSet 的設定,然後會把 Primary 上的資料同步並複製過來:
rs.initiate(null)

如果一切沒問題,你可以在 Primary 主機上,進入 mongo 命令模式,然後使用指令看整個 replSet 的狀態:
rs.status()

後記

Replication 設定好後,只要 Secondary 的機器一上線,就會開始同步資料,如果 Primary 主機死掉,也會自動選定一台 Secondary 機器,讓它變成新的 Primary。

過程中,主要可能發生的問題是整個 replSet 選不出 Primary 的狀況,而且在無 Primary 機器時候,你無法去修改並設定 replSet ,造成整個系統不能正常運作。由於 MongoDB 沒有提供強制清除 replSet 設定的功能(至少到目前為止我沒有找到),一個非正式的方法是使用 mongo 去將每一台裡名為『local』的 db 砍掉,然後重啟 Service 並重新設定 replSet 。