Devops通常不多時間會花在數據庫的部署上,只有到了不起不去考慮的狀況下,纔會去考慮如何調整數據庫,以適應業務的發展。mongodb自己就很適合Devops,大部分狀況下,部署基本按照說明操做一下便可。但實際操做起來,其實還有會有一些坑,好比Resync。mongodb
mongo副本集,在正常工做的狀況下,是以一種不斷的、異步的方式進行同步。每一個副本都會不斷的記錄本身進行的操做進入到oplog表裏;Secondary副本就會不斷的從Primary副本那裏同步最新的操做,從而完成整個副本集的同步。固然Secondary的副本也能夠選擇從其餘的Secondary副本同步,由於每一個副本都會記錄oplog。詳細的描述能夠參考官方文檔Replica Set Data Synchronization。數據庫
Oplog是一個特殊的固定大小的collection,固定大小意味着,新的操做記錄的寫入會致使最老的操做記錄的刪除,以保證oplog的大小。這個值若是不去設置,mongo會自動根據硬盤大小的5%來設定。大部分狀況下沒有什麼問題,但有一個很是重要的設(da)定(keng):網絡
oplog一旦大小固定,那麼只能經過重啓+配置來進行修改架構
爲何這會是一個坑,後面會繼續討論。異步
副本集之間通常經過網絡鏈接,副本集之間的性能也有可能有差別(固然最好不要有),因此同步操做有可能出現毫秒級別的延遲,甚至到1s以上,這個能夠經過在任意一個副本集上執行性能
rs.status()
來查看全部副本集的同步狀態。這個打印出的各個副本的optime,就是這個副本最後一條操做執行的時間,Secondary和Primary之間optime的時間差,其實就是同步延遲。阿里雲
同步延遲通常狀況下,頂多也就一兩秒,可是一些異常狀況,例如宕機、長時間過載overload,可能會致使這個時間愈來愈長。這裏,咱們的oplog的巨大做用就顯現出來了!spa
Secondary和Primary之間的同步差,最大不能超過Primary的oplog能存儲的條數操作系統
注意!由於Secondary是從Primary同步oplog,因此,這裏只與Primary的oplog大小有關,與Secondary自身記錄的oplog無關!固然,若是Secondary是從其餘的Secondary同步數據,那麼至於同步目標的oplog有關。日誌
爲了幫助用戶直觀的理解oplog裏面存儲了多少條操做,mongo還額外提供了兩個數據:
tFirst 第一條oplog的時間
tLast 最後一條oplog的時間
這兩個數據,能夠經過在primary上執行:
db.getReplicationInfo()
得到。tLast - tFirst就是mongo同步機制所容許你進行停機同步數據的最大時間,固然這個時間不是固定的,若是當前的負載很低,至關於相同的oplog表能夠存更長時間內的操做數據,就會給你留更多的停機操做時間。
上圖中,Secondary落後於Primary,也就是說,同步延遲有10分鐘(兩個optime相減),但此時,Primary上存有最近20分鐘的oplog,那麼Secondary經過獲取這些oplog,仍然可以在短期內遇上Primary的進度。
可是,一旦optime的差距超出了Primary的tFirst,狀況就不妙了,以下圖:
此時,自動的同步已經沒法完成同步了(stale),必須執行手動操做Resync。並且Secondary已經降級爲Recovering,將沒法接受請求,以及不能變成master。
Resync機制官網有詳細的介紹,基本思路就是把數據拷貝過來,再進行上面的oplog的同步。例如:
使用磁盤快照,把快照的數據庫文件直接覆蓋到Secondary上,重啓Secondary
使用Initial Sync,把Secondary的數據清空,讓mongo自動從0開始,從新同步全部數據
磁盤快照看起來很美好,可是是mongo的數據存儲是分配後就不返回的,也就是說實際佔用的磁盤空間要比真實數據的大小要大,使用操做系統的scp也好rsync也好,這些無用的空間也會被複制,耽誤複製的時間。除此以外,創建快照自己也須要耗時,反正在阿里雲上建快照並不快,200G的數據大約要1小時多。
而Initial Sync是mongo之間拷貝表數據,拷貝完了就地重建索引,因此至關於只傳輸了真實的表數據,連索引數據都不用傳輸,從總體的複製時間來看更加節省,可是會對拷貝對象Primary有一些性能影響,但畢竟只是讀,並且不須要Primary停機。
不管使用上面的哪一種Resync機制,思路都是一致的,經過某種快速的方式同步更多的數據,而後剩下的使用oplog彌補在執行操做時的新操做。看起來很美好,而實際的執行過程當中,若是操做的時間,要大於oplog所記錄的時間,怎麼辦?將永遠沒法不停機Resync成功!
這裏Initial Sync爲何也不能成功呢?其實在Initial Sync的日誌中,就能夠看出來,在STATUP2的狀態,就是一張表一張表的拷數據,也就是說,就算拷貝過程當中的數據已經同步過去了,當拷貝下一張表時,上一張表的數據其實已通過期了。而當數據量很大的狀況下(其實不須要太大,幾百G),整個拷貝過程也要持續數小時,此時若是oplog的記錄時間低於STARTUP2所須要花費的時間,恭喜你,你中獎了。
固然,若是你能有一臺正常同步數據的Secondary,新的機器指向這臺也是能夠的,可是你的架構是一臺Arbiter一臺Primary一臺Secondary的話……就沒辦法了,只能期望Primary了。別問我爲何知道,我就是知道。(╯‵□′)╯︵┴─┴
遇到這種狀況怎麼辦?
半夜Primary停機,同步數據。這對於DBA也都不奇怪,只是在用了mongo集羣后沒享受到mongo的便利。固然,到了半夜負載降低,至關於oplog容許的操做時間變長了,也許不用停機。
若是有不少冗餘數據、日誌數據什麼的,能夠刪除,從而下降Initial Sync花費的時間,那也是很值得嘗試的!
上面的坑,其實主要是在於oplog的值相對於數據量太小的時候會出現。通常默認狀況下,oplog取磁盤大小的5%彷佛沒太大問題。坑在哪呢?
磁盤擴容
高負載
一開始我就提到,oplog的存儲大小一旦肯定是不會改的,也就是說,一旦隨着業務的發展,進行了磁盤擴容,或者移動到了一塊更大的硬盤上,oplog的大小不會隨之改變!
一旦兩件巧合的事情遇到了一塊兒:磁盤曾經擴容且沒有額外考慮oplog;須要新增副本或者副本stale了;此時正常的機器只有一臺Primary;就會變成一件解決起來不那麼輕鬆的事情了。
而高負載也是潛在的另一個可能,因爲負載太高,雖然oplog存儲很大,可是實際上oplog所支持的停機操做時間變少了,此時也會遇到相同的狀況。
總結一下,在用mongo副本集羣的時候,隨着數據的增加、磁盤的擴容,一方面在考慮sharding的同時,必定要注意當前的oplog存儲是否夠用,提早爲下一次部署策略更換準備好,給下一次的操做留夠時間。特別是Devops,平時沒時間管的,必定要未雨綢繆呀。