2012年5月19日 星期六

MongoDB Replica Sets Problem



最近忙著要讓產品上線,主要的工作就是在調教Production 的環境,還有做整合測試,但是在MongoDB那邊吃足了苦頭,這幾天都是在跟MongoDB 打渾戰,因為遇到了資料在Replica Sets 不同步的問題,在討論這個問題和解法前,先介紹一下MongoDB的特色,以及為什麼要選用他。(因為偷懶吧...)

MongoDB的特色根據官網自己的描述:

  • Document-oriented storage (採用JSON,好改容易理解,但是也容易誤用)
  • Full Index Support (但是很肥)
  • Replication & High Availability (但是還是遇到一堆問題~囧)
  • Mirror across LANs and WANs for scale and peace of mind. (你不會想要讓他cross WAN的...) 
  • Auto-Sharding (號稱最強大的祕密武器~~)
  • Document based Querying (真的要多Try & Error)
  • Fast In-Place Updates
  • Map/Reduce (研究中...)
  • GridFS (研究中..)
之所以會選MongoDB 最主要就是看上它以Replica Sets 的方式達到HA,以及AutoSharding的能力,一個Replica Sets由若干個mongod instance組成,在這個集合中,所有的instance的資料相同,這使得即使有某一台機子當掉了,其它機子還是可以正常運行,而這部分的控制是由Mongo自動完成的,用意在於減少因當機而產生的錯誤及人工處理的部分。(但是我還是遇到問題啊~~~~~~囧rz...)。

首先我的配置是參考了Foursquare的文章 Fun with mongodb replica sets 以及Mongod 官網教學[Upgrading to Replica Sets],一開始啟動了三台Mongod instance,一台是Primary,一台是slave,一台是Arbiter (投票者),設定步驟如下:

1. 分別在三台機器啟動 (/etc/hosts 彼此要看的到對方 ) > mongod --rest --replSet replSetServers
2. 在PRIMARY 那台做以下設定 > rs.initiate()
> rs.add(“replSetServers01”)
> rs.addArb(“replSetServers02”) //(這台是投票用)
3. 移除多餘的Server (Optional) > rs.remove("replSetServers04:27017")
接下來應該就可以正常運作了,一開始的確是用的很開心,但是漸漸的就會遇到一些奇怪的問題,比如說write-concern 的問題,然後我們是用Spring-data來操作mongo,也發現了spring-data的bug,但是這些問題都還算可以解決,最讓我不解的就是同步問題,理論上應該會Eventually Consistency,也就是我們把資料寫入primary,然後mongoDB會自動把資料同步到Slave去,讓其他Client可以讀取。我遇到的問題就是有一筆資料明明在primary已經消失,但是卻一直留在Slave上,然後我等到望眼欲穿,它也不會同步,我也不能手動從slave把它砍掉.......,然後我就在網路上找資料,判斷有可能是以下原因造成資料錯誤:
  • 沒有用正常步驟到mongoDB 裡面下 db.shutdownServer(),而是直接kill process,可能因此造成資料損毀或不同不。
  • 根據以下圖片來解釋,資料同步的方向應該是單向的,也就是primary write to slave,如果這時候primaryA 掛了,slaveB升格成primaryB,這時資料寫到primaryB,結果primaryA又回復,primaryB又變回slaveB,在那這段期間內產生的資料會發生什麼事呢?是不是就會產生孤兒?

好,我先不管發生的原因,我先想解決的方法 (真是不求甚解...囧) ,就在 mongoDB的官網找有無類似的教學,發現幾個可能有用的:

[Durability and Repair] > db.repairDatabase(); 跑了很久....很久....結果...還是一樣.....

[Resyncing a Very Stale Replica Set Member] ,裡面提供了三種建議:
  • Perform a full resync (砍掉重練...)
  • Copy data from another member (也是砍掉重練...)
  • Find a member with older data (還是砍掉重練...)
所以最後只好使用砍掉重練大法....所以心得是,在使用mongoDB上還是要很小心(廢話...)




張貼留言