前面幾篇文章的分析複製集解決了資料庫的備份與自動故障轉移,但是圍繞資料庫的業務中當前還有兩個方面的問題變得越來越重要。一是海量資料如何儲存?二是如何高效的讀寫海量資料?儘管複製集也可以實現讀寫分析,如在primary節點上寫,在secondary節點上讀,但在這種方式下客戶端讀出來的資料有可能不是最新的,因為primary節點到secondary節點間的資料同步會帶來一定延遲,而且這種方式也不能處理大量資料。mongoDB從設計之初就考慮了上面所提到的兩個問題,引入了分片機制,實現了海量資料的分散式儲存與高效的讀寫分離。複製集中的每個成員是一個mongod例項,但在分片部署上,每一個片可能就是一個複製集。
上面談到了分片的優點,但分片的使用,會使資料庫系統變得複雜。什麼時候使用分片也是需要考慮的問題。mongoDB使用記憶體對映檔案的方式來讀寫資料庫,對記憶體的管理由作業系統來負責,隨著執行時間的推移,資料庫的索引和資料檔案會變得越來越大,對於單節點的機器來說,遲早會突破記憶體的限制,當磁碟上的資料檔案和索引遠大於記憶體的大小時,這個時候作業系統會頻繁的進行記憶體交換,導致整個資料庫系統的讀寫效能下降。因此對於大資料的處理,要時刻監控mongoDB的磁碟I/O效能、可用記憶體的大小,在資料庫記憶體使用率達到一定程度時就要考慮分片了。通過分片使整個資料庫分佈在各個片上,每個片擁有資料庫的一部分資料,從而降低記憶體使用率,提高讀寫效能。
分片部署架構
下面看看一個具體的分片部署架構是什麼,為了後續的研究,先部署一個分片叢集。
分片叢集主要由mongos路由程式、複製集組成的片shards、一組配置伺服器Configure構成,下面對這些模組一一解釋。
分片叢集中的一個片shard實際上就是一個複製集,當然一個片也可以是單個mongod例項,只是在分片叢集的生產環境中,每個片只是儲存整個資料庫資料的一部分,如果這部分資料丟失了,那麼整個資料庫就不完整了,因此應該保證每個片上的資料穩定性和完整性,通過第7章對複製集的分析,複製集能夠達到這樣的要求。因此通過將片配置為複製集的形式,使片shard在預設情況下讀寫都在複製集的primary節點上,每個片同時具有自動故障轉移、冗餘備份的功能,總之複製集所具有的的特性在片上都能得到體現。
mongos路由程式是一個輕量級且非永續性的程式。輕量級表示它不會儲存任何資料庫中的資料,它只是將整個分片叢集看成一個整體,使分片叢集對整個客戶端程式來說是透明的,當客戶端發起讀寫操作時,由mongos路由程式將該操作路由到具體的片上進行;為了實現對讀寫請求的路由,mongos程式必須知道整個分片叢集上所有資料庫的分片情況即元資訊,這些資訊是從配置伺服器上同步過來的,每次程式啟動時都會從configure伺服器上讀元資訊,mongos並非持久化儲存這些資訊。
配置伺服器configure在整個分片叢集中想到重要,上面說到mongos會從配置伺服器同步元資訊,因此配置伺服器要能實現這些元資訊的持久化。配置伺服器上的資料如果丟失,那麼整個分片叢集就無法使用,因此在生產環境中通常利用三臺配置伺服器來實現冗餘備份,這三臺伺服器是獨立的,並不是複製集架構。
下面按照上圖描述來配置一個這樣的分片叢集。
(1)配置複製集rs0並啟動,參考前面關於複製集中介紹的6個步驟。
先建立好rs0中各節點的資料檔案存放路徑、日誌檔案路徑以及配置檔案,其中配置檔案的內容如下:
rs0中primary節點的配置檔案為rs0_0.conf:
dbpath = E:\mongodb-win32-i386-2.4.3\db_rs0\data\rs0_0
logpath = E:\mongodb-win32-i386-2.4.3\db_rs0\logs\rs0_0.log
journal = true
port = 40000
replSet = rs0
rs0中secondary節點的配置檔案為rs0_1.conf:
dbpath = E:\mongodb-win32-i386-2.4.3\db_rs0\data\rs0_1
logpath = E:\mongodb-win32-i386-2.4.3\db_rs0\logs\rs0_1.log
journal = true
port = 40001
replSet = rs0
rs0中arbiter節點的配置檔案為rs0_2.conf:
dbpath = E:\mongodb-win32-i386-2.4.3\db_rs0\data\rs0_2
logpath = E:\mongodb-win32-i386-2.4.3\db_rs0\logs\rs0_2.log
journal = true
port = 40002
replSet = rs0
按照7.1節介紹的步驟啟動複製集rs0。
(2)配置複製集rs1並啟動,步驟與上面相同,這裡給出rs2中各節點對應的配置檔案內容。
rs1中primary節點的配置檔案為rs1_0.conf:
dbpath = E:\mongodb-win32-i386-2.4.3\db_rs1\data\rs1_0
logpath = E:\mongodb-win32-i386-2.4.3\db_rs1\logs\rs1_0.log
journal = true
port = 40003
replSet = rs1
rs1中primary節點的配置檔案為rs1_1.conf:
dbpath = E:\mongodb-win32-i386-2.4.3\db_rs1\data\rs1_1
logpath = E:\mongodb-win32-i386-2.4.3\db_rs1\logs\rs1_1.log
journal = true
port = 40004
replSet = rs1
rs1中primary節點的配置檔案為rs1_2.conf:
dbpath = E:\mongodb-win32-i386-2.4.3\db_rs1\data\rs1_2
logpath = E:\mongodb-win32-i386-2.4.3\db_rs1\logs\rs1_2.log
journal = true
port = 40005
replSet = rs1
按照7.1節介紹的步驟啟動複製集rs0
通過rs.status()檢查並確認上述複製集已啟動且配置正確。
(3)配置configure伺服器
configure伺服器也是一個mongod程式,它與普通的mongod例項沒有本質區別,只是它上面的資料庫以及集合是特意給分片叢集用的,其內容會在後面詳細介紹。三個獨立的配置伺服器對應的啟動配置檔案內容如下:
configure伺服器1的配置檔案cfgserver_0.conf:
dbpath = E:\mongodb-win32-i386-2.4.3\db_configs\data\db_config0
logpath = E:\mongodb-win32-i386-2.4.3\db_configs\logs\db_config0.log
journal = true
port = 40006
configsvr = true
configure伺服器2的配置檔案cfgserver_1.conf:
dbpath = E:\mongodb-win32-i386-2.4.3\db_configs\data\db_config1
logpath = E:\mongodb-win32-i386-2.4.3\db_configs\logs\db_config1.log
journal = true
port = 40007
configsvr = true
configure伺服器3的配置檔案cfgserver_2.conf:
dbpath = E:\mongodb-win32-i386-2.4.3\db_configs\data\db_config2
logpath = E:\mongodb-win32-i386-2.4.3\db_configs\logs\db_config2.log
journal = true
port = 40008
configsvr = true
配置伺服器上的mongod例項啟動時的配置選項與普通的mongod例項差不多,這裡只是多了一個configsvr=true的選擇,說明這個mongod例項是一個configure型別的mongod例項。
啟動上面三個配置伺服器:
>mongod --config E:\mongodb-win32-i386-2.4.3\configs_cfgservers\cfgserver_0.conf
>mongod --config E:\mongodb-win32-i386-2.4.3\configs_cfgservers\cfgserver_1.conf
>mongod --config E:\mongodb-win32-i386-2.4.3\configs_cfgservers\cfgserver_2.conf
(4)配置mongos路由伺服器
其配置檔案cfg_mongos.conf內容為:
logpath = E:\mongodb-win32-i386-2.4.3\mongos\logs\mongos.log
port = 40009
configdb = Guo:40006,GuO:40007,GuO:40008
啟動路由伺服器:
>mongos --config E:\mongodb-win32-i386-2.4.3\mongos\cfg_mongos.conf
例項對應的程式為mongos,路由伺服器只是一個輕量級和非持久化操作的程式,因此上面的配置檔案裡面沒有像其它mongod例項那樣有一個存放資料檔案的路徑選項dbpath。
(5)新增各分片到叢集
上面已經完成了兩個片(複製集)、三個配置伺服器、一個路由伺服器且它已經知道從哪些配置伺服器上同步後設資料(configdb = Guo:40006,GuO:40007,GuO:40008),接下來要做的是將各個片新增到叢集中。
開啟一個mongo客戶端連線到mongos伺服器:
>mongo --port 40009
新增兩個分片
mongos> sh.addShard("rs0/GUO:40000,GUO:40001")
{ "shardAdded" : "rs0", "ok" : 1 }
mongos> sh.addShard("rs1/GUO:40003,GUO:40004")
{ "shardAdded" : "rs1", "ok" : 1 }
這裡新增分片的命令是sh.addShard(),引數是複製集名以及複製集中不包含arbiter型別的所有節點。
(6)最後通過命令sh.status()檢查上面的配置是否正確,正常的話輸出資訊類似下面:
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"version" : 3,
"minCompatibleVersion" : 3,
"currentVersion" : 4,
"clusterId" : ObjectId("521b11e0a663075416070c04")
}
shards:
{ "_id" : "rs0", "host" : "rs0/Guo:40000,Guo:40001" }
{ "_id" : "rs1", "host" : "rs1/Guo:40003,Guo:40004" }
databases:
{ "_id" : "admin", "partitioned" : false, "primary" : "config" }
上面輸出的資訊中clusterId欄位表示此分片叢集的唯一標示;shards為分片叢集中包含的所有片,其中_id為此片的名稱,host為片中的主機的host資訊;databases為叢集中的所有資料庫,其中_id為資料庫名稱,partitioned表示此資料庫是否支援分片;primary表示當資料庫支援分片,此資料庫上所有未分片的集合所在的片。
此時在整個分片叢集中還沒有建立任何其它資料庫,通過路由程式mongos連線叢集,執行命令show dbs可以看到叢集中只有系統預設建立的一個config資料庫,且這個資料庫只存在於三個配置伺服器上,config資料庫中的集合包含了整個叢集的配置資訊,執行命令show collections,可以看到有如下集合:
mongos> show collections
changelog:儲存被分片的集合的任何後設資料的改變,例如chunks的遷移、分割等。
Chunks:儲存叢集中分片集合的所有塊的資訊,包含塊的資料範圍與塊所在的片。
Databases:儲存叢集中的所有資料庫,包含分片與未分片的。
Lockpings:儲存跟蹤叢集中的啟用元件。
locks:均衡器balancer執行時會生產鎖,在此集合中插入一條記錄。
mongos:儲存了叢集中所有路由mongos的資訊。
Settings:儲存分片叢集的配置資訊,如每個chunk的大小(64MB)、均衡器的狀態。
Shards:儲存了叢集中的所有片的資訊。
system.indexes:儲存config資料庫中的所有索引資訊。
Version:儲存當前所有元資訊的版本。
由上所述得知,配置伺服器中的config資料庫的資訊對於整個叢集來說是至關重要的,這也是生產環境中最少需要3個配置伺服器做冗餘備份的原因;同時上面對config資料庫的所有操作,都是通過客戶端連線mongos後再進行的,儘管config資料庫也是在單個mongod例項上,我們可以直接通過客戶端連線到這個例項,然後做操作,但是這樣會出現配置伺服器上的資訊不一致的風險,因此我們隊叢集的所有操作應該是通過客戶端連線mongos來執行。
最好探討一下實際部署的問題,通過上圖和前面的分析可知,一個生產環境的最少需要9個mongod例項程式,一個mongos程式例項,理論上說最少需要10臺機器才能組成。但是這些程式中有些並不需要很多軟硬體資源,它們可以與其它程式共存部署在同一個機器上,如複製集中arbiter程式、mongos程式可以部署到應用程式所在的伺服器,綜合考慮後可以得到下面一個典型的部署:
圖8.2
上圖部署的總體原則是使每一個片(複製集)中的primary節點、secondary節點、arbiter節點分開以及三臺配置伺服器分開,當圖中的四臺機器任何一臺當機後,叢集都能夠正常執行。