一 讀寫分離概述
1.1 讀寫分離描述
從應用程序角度來看,使用Replica Set 和使用單台mongo很像。默認的驅動程序會連接primary節點,並且將所有讀寫請求都路由到主節點。但也可以通過設置驅動程序的Read Preferences 配置其他選項,將讀請求路由到其他節點。
通常官網中建議不使用向從節點取數據。原因如下:
- 所有的從節點擁有與主節點一樣的寫入負載,讀的加入會增加其負載;
- 對於分片的集合,在平衡器的關系下,數據的返回結果可能會缺失或者重復某部分數據;
- 相對而言,官方建議使用shard來分散讀寫請;
- 一致性的考慮,對一致性要求比較高的應用程序是不應該從備份節點讀取數據,備份節點通常由於加載問題,網絡等原因,而落后於主節點幾毫秒,幾秒,幾分鍾甚至更多。如果應用程序需要讀取它自己的寫操作(比如,先插入一個文檔,再去查詢它),那么不應該從備份節點去讀取數據,除非針對寫操作,使用Write Concern定義w數值,在復制到所有備份節點之后,再返回執行成功與否。總之,如果從一個落后的備份節點讀取數據,就要犧牲一致性。如果希望寫入操作返回之前被復制到所有的副本集成員,就要犧牲寫入速度。
- 如果路由到的備份節點,其中一台掛了,那么其他節點將承擔其相應的壓力,需要注意此時在線節點的負載壓力。
因此一般是不建議做讀寫分離,通常對於寫操作很少,大量的讀請求的業務,實現讀寫分離來分擔服務器壓力,然后逐步過度到分片模式。
注意:副本集不是為了提高讀性能存在的,在進行oplog的時候,讀操作是被阻塞的;
提高讀取性能應該使用分片和索引,它的存在更多是作為數據冗余,備份;
尤其當主庫本來就面臨着大量的寫入壓力,對於副本集的節點,也同樣會面臨寫的壓力。
1.2 使用的場景
通常官方不推薦使用從節點實現讀寫分離,但可能存在以下場景需要使用讀寫分離:
- 異地的分布式部署
- 故障切換,在緊急情況下向從節點讀數據
1.3 延伸讀寫分離思考
該思考來源:https://github.com/smallnewer/bugs/issues/22
個人總結如下:
主從的寫壓力基本一樣;
- MongoDB從不會受到主寫鎖的影響,可通過mongotop 或者 mongostat查看寫鎖狀態;
- MongoDB從會在主寫鎖后,在恢復oplog時,進行寫鎖;
- 從優先讀,而且讀太多會影響寫;
- 從節點讀的權限比寫鎖優先級高(注:主節點反之,應該是寫貪婪的),建議當從節點的讀太高從而影響了oplog的恢復時,改用分片方案。
因此在以下情景下適合使用讀寫分離:
讀寫比例要大,即讀多寫少。如果寫多讀少,從庫也會有大量寫鎖,阻塞讀。
讀多寫少,從庫雖然有寫鎖,但由於優先讀的原因,讀不受寫鎖阻塞,讀的速度會加快。
不過從庫讀壓力大的時候,只是暫時把寫滯后,如果寫滯后的很多,超過了主的oplog上限,會觸發整體同步,造成主庫壓力過大,產生雪崩。
在從能輕松頂住讀壓力的時候,且讀寫比例是讀多寫少,可以考慮讀寫分離,提高讀的速度。
若從節點不能頂住讀壓力,最好放棄讀寫分離,換用分片,將熱數據分散到不同的機器上。
二 讀寫分離部署
2.1 正常部署副本集
參考《006.MongoDB復制(副本集)》。
2.2 開啟Sencondary可讀狀態
1 [root@mongodb02 ~]# mongo --host 172.24.8.72 -u clusteradmin -p clusteradmin 2 my_rep:SECONDARY> db.getMongo().setSlaveOk() 3 [root@mongodb02 ~]# mongo --host 172.24.8.73 -u clusteradmin -p clusteradmin 4 my_rep:SECONDARY> db.getMongo().setSlaveOk() #分別連接兩個Sencondary節點服務器,設置為可讀狀態
2.3 客戶端設置讀取方式
通過修改客戶端讀取方式實現從節點的讀,具體方式包括:
客戶端演示:略。
參考鏈接:
https://docs.mongodb.com/manual/applications/replication/
https://www.cnblogs.com/magialmoon/p/3268963.html
http://www.gaozhy.cn/blog/2018/01/18/%E5%9F%BA%E4%BA%8E%E5%89%AF%E6%9C%AC%E9%9B%86%E7%9A%84%E8%AF%BB%E5%86%99%E5%88%86%E7%A6%BB/