MongoDB高可用
對於MongoDB,可以支持使用單機模式提供服務,但是在實際的生產環境中,單機模式將面臨很大的風險,一旦這個數據庫服務出現問題,就會導致線上的服務出現錯誤甚至崩潰。因此,在實際生產環境下,需要對MongoDB做相應的主備處理,提高數據庫服務的可用性。
對於提高可用性,一些博文裏提到了使用主從模式(master-slaver)。
WARNING:
Deprecated since version 3.2: MongoDB 3.2 deprecates the use of master-slave replication for components of sharded clusters.
主從模式是高可用的一種方案。然而從上面這段警告中可以知道,在高版本的MongoDB(3.2以上)中,官方已經不推薦使用主從模式,取而代之的,是使用複製集(Replica Set)的方式做主備處理。
IMPORTANT:
Replica sets replace master-slave replication for most use cases. If possible, use replica sets rather than master-slave replication for all new production deployments. This documentation remains to support legacy deployments and for archival purposes only.
因此,本文將介紹如何將已有的單機MongoDB數據庫拓展爲主備模式的複製集,以提高可用性。
複製集 Replica Set
在複製集中,有且只有一個主節點(primary),可以包含一個或多個從節點(secondary),主從節點直接會通過心跳檢測來確定節點是否健康或存活。所有的讀寫操作都是在主節點上進行的,如果要實現讀寫分離,需要進行相應的處理,這個最後會說。從節點會根據oplog(也就是操作日誌)來複制主節點的數據。
除了主從節點外,MongoDB的複製集中還存在着一種叫仲裁者(Arbiter)的角色。一個仲裁者節點是比較輕量級的,因爲它不會去複製主庫的數據,因此也就不會成爲主節點;但是,它的作用是在投票選舉階段——當主節點故障時,仲裁者可以進行投票。一般來說,不建議一個複製集中包含超過一個仲裁者。
當主節點突然故障後,MongoDB有自己的機制,會自動切換,通過選舉,在從節點中選出一個節點作爲新的主節點。
如何使用複製集
首先,需要在MongoDB實例的啓動參數中加入replSet,指定複製集的名稱。
mongod --port 8017 --dbpath /home/work/data/db1 --replSet rstest
對於已有的單機實例,也可以加入該參數並進行重啓。此外,我們還需要另外啓動兩個MongoDB實例作爲從節點,注意replSet參數指定的名稱需要相同。
mongod --port 8016 --dbpath /home/work/data/db2 --replSet rstest
mongod --port 8015 --dbpath /home/work/data/db2 --replSet rstest
然後,需要通過mongo命令連接MongoDB服務,進入主節點進行初始化。
mongo 127.0.0.1:8017
rs.initiate({
_id:"rstest", // replSet指定的名稱
members:[{
_id:0,
host:"127.0.0.1:8017" // 主節點ip與端口
}]
})
需要注意的是,如果是將已有單機拓展爲複製集,要在連接原單機的實例並在其中運行使其作爲主節點。
最後,再將其他兩個從節點加入到該複製集中。
rs.add("127.0.0.1:8016")
rs.add("127.0.0.1:8015")
通過rs.status()
查看效果,可以看到rstest
這個複製集中已經有了三個節點,stateStr
指明瞭節點的類型,health
爲1表明該節點是健康的。
{
"set" : "rstest",
"date" : ISODate("2017-10-31T13:04:16.704Z"),
"myState" : 1,
"members" : [
{
"_id" : 0,
"name" : "127.0.0.1:8017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY", // 節點的類型,主節點
"uptime" : 1508,
"optime" : Timestamp(1509455043, 1),
"optimeDate" : ISODate("2017-10-31T13:04:03Z"),
"electionTime" : Timestamp(1509454568, 2),
"electionDate" : ISODate("2017-10-31T12:56:08Z"),
"configVersion" : 3,
"self" : true
},
{
"_id" : 1,
"name" : "127.0.0.1:8016",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 25,
"optime" : Timestamp(1509455043, 1),
"optimeDate" : ISODate("2017-10-31T13:04:03Z"),
"lastHeartbeat" : ISODate("2017-10-31T13:04:15.657Z"),
"lastHeartbeatRecv" : ISODate("2017-10-31T13:04:15.108Z"),
"pingMs" : 0,
"syncingTo" : "127.0.0.1:8017",
"configVersion" : 3
},
{
"_id" : 2,
"name" : "127.0.0.1:8015",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 13,
"optime" : Timestamp(1509455043, 1),
"optimeDate" : ISODate("2017-10-31T13:04:03Z"),
"lastHeartbeat" : ISODate("2017-10-31T13:04:15.657Z"),
"lastHeartbeatRecv" : ISODate("2017-10-31T13:04:15.661Z"),
"pingMs" : 0,
"configVersion" : 3
}
],
"ok" : 1
}
連接複製集
由於複製集中的切換機制,在主節點故障的情況下,集羣內其他從節點會通過投票方式產生新的主節點,因此,不能像單機情況下那樣,直接連接主節點;否則在MongoDB自動切換主節點時,數據庫訪問就會出問題。因此連接複製集需要特定的連接方式。
在MongoDB的連接字符串(connection url)中可以進行指定。
mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
其中可以指定多個host:port,用英文逗號連接,並在最後的option中支持replicaSet參數,用於指定連接的複製集。例如:
mongodb://127.0.0.1:8017,127.0.0.1:8016,127.0.0.1:8015/books?replicaSet=rstest
這樣就可以連接上覆制集中的books這個數據庫。
總結
MongoDB複製集的故障機制切換是它自身來保障,在部署好上面一系列的服務後,我們可以測試一下當主節點故障時,集羣中的節點狀態與服務可用性。通過kill主節點MongoDB進程,使用rs.status()
可以發現,其中一個從節點已經升級爲了主節點(這部分在從節點的日誌中也有體現)。此外,數據查詢依然可以進行,不會因爲主節點的宕機而導致數據服務不可用。