建立 MongoDB 高可用叢集

高可用是什麼?

新世代的 NoSQL 大都有一項蠻特別的特性,被稱為「高可用 (High Availability)」。

何謂高可用?簡單說來就是讓服務(幾乎)永遠不下線的能力。

用嘴巴說是很簡單啦,但讓一個服務永不下線,背後存在許多問題。比方說下面這些:

  • 伺服器會壞,壞了怎麼辦?
  • 機房意外停電怎麼辦?
  • 硬碟用久會損毀。就算有備份,也需要復原時間。
  • 機器會需要定時更新換代,以便追上新一代電腦的規格。比方說硬碟空間可能不足,需要換成更大顆的。
  • 軟體需要升級的時候怎麼辦。


總之,不管原因為何,我們幾乎總是會碰到停機,這怎樣也避不開。

高可用的解方

為了一勞永逸地解決所有問題,各家提出的終極方案,大都集中在線上備份之上。

  1. 首先搞來多台機器,讓他們插電上線
  2. 所有資料都複製成數份副本,分散在不同的機器裡,並且隨時保持備份被更新到最新狀態
  3. 這些機器全都同時開機,放在線上
  4. 如果一台機器掛了,就向其他機器討要備份


之所以說是「終極方案」,這除了它確實能解決問題之外,還因為它很貴。想想就知,為了滿足隨時有一份副本可用的可用性,用戶必須要準備至少 2n 台甚至更多的機器,而且還得讓他們隨時上線燒電,並佔用數以倍計的硬碟空間。

MongoDB 的 Replica Set

終於進入今天的正題了

MongoDB 是 NoSQL 的一種,如同其他 NoSQL 他也同樣有提供這種高可用性架構。這在 MongoDB 的術語中被稱為 "Replica Set"。

註:老實說在更早期,MongoDB 還有一種叫作 Master Slave 的副本架構,不過那種作法已經過時。讀文件時讀到可以不用理它。

以下講講如何在 Linux 機器上起 Replica Set。

因為是測試用途,所以以下直接起在單台機器上。實際上 Replica Set 的多個服務,當然應該要起在不同的系統上--畢竟是備份嘛,放在同一台機器上沒啥作用。

1. 起服務 x3

mkdir rs01 -p
mongod --replSet "rs0" --dbpath "rs01" --port 27021 --smallfiles --fork --logpath rs01/log.txt
mkdir rs02 -p
mongod --replSet "rs0" --dbpath "rs02" --port 27022 --smallfiles --fork --logpath rs01/log.txt
mkdir rs03 -p
mongod --replSet "rs0" --dbpath "rs03" --port 27023 --smallfiles --fork --logpath rs01/log.txt

注意關鍵參數是 --replSet,想要納入同一個 Replica Set 的服務,這個參數必須保持一致。

其他參數與 Replica Set 無關,隨意就好。

2. 登入

接下來隨意登入一台服務。

mongo localhost:27021

3. 在 Mongo Shell 中進行初始化

然後在 Mongo Shell 中輸入以下指令,進行 Replica Set 的初始化:

rs.initiate()

其實這一步可以直接輸入參數,一次到位,不過參數長長一大串怎樣都背不起來,所以不輸入讓它自行產生,之後再修改。小規模佈署時這樣比較方便。


img1

▲ 初始化前沒有任何訊息。

img2

▲ 初始化後的狀況,目前有一個節點。當然那就是自己。


注意上圖中 name 的地方,這也是 Replica Set 彼此的連線網路位置。

然後使用 rs.add() 加入其他機器。

rs.add("mongolab:27022")
rs.add("mongolab:27023")

如此就佈署完成了。相當簡單。有興趣的話可以故意 kill 掉一個服務,看看系統的處理狀況。


特註

上方指令中,我的機器名字叫 mongolab,您得改成您的機器名字。用 localhost 或 127.0.0.1 是行不通的。因為 Replica Set 只有分散佈署在多台不同的機器上時才有實際意義,所以他會判斷,一名用戶如果寫了 localhost 或 127.0.0.1 就是搞錯了狀況,應該要禁止執行。

除此之外,所有機器當然也都要能存取彼此。網路要通 Replica Set 才能順利建立。如果是指定 hostname 而非 ip 的狀況,每台機器也得能解譯全部的 hostnames 才行。

img3

▲ 企圖用 localhost 闖關是行不通的。

以上,謝謝收看!