MongoDB從庫延遲讀取資料問題的解決思路

chenfeng發表於2016-01-14
最近,在網上看到一個朋友的MongoDB遇到效能問題,問題是這樣的:
主庫更新了資料,其中一個從庫時讀取,配置了後發現有延遲,比如更新50條,從庫只能讀取50%的資料,如何解決?

解決思路:

1) 監測一下網路看是否有瓶頸
2) 確認主從配置是否一致 (CPU、記憶體和IO)
3) 使用WriteConcern把資料同步寫到從機


那麼WriteConcern是怎麼資料同步寫到從機的,下面介紹一下MongoDB的WriteConcern引數

首先列一下WriteConcern的幾種丟擲異常的級別引數:
WriteConcern.NONE:沒有異常丟擲
WriteConcern.NORMAL:僅丟擲網路錯誤異常,沒有伺服器錯誤異常
WriteConcern.SAFE:丟擲網路錯誤異常、伺服器錯誤異常;並等待伺服器完成寫操作。
WriteConcern.MAJORITY: 丟擲網路錯誤異常、伺服器錯誤異常;並等待一個主伺服器完成寫操作。
WriteConcern.FSYNC_SAFE: 丟擲網路錯誤異常、伺服器錯誤異常;寫操作等待伺服器將資料重新整理到磁碟。
WriteConcern.JOURNAL_SAFE:丟擲網路錯誤異常、伺服器錯誤異常;寫操作等待伺服器提交到磁碟的日誌檔案。
WriteConcern.REPLICAS_SAFE:丟擲網路錯誤異常、伺服器錯誤異常;等待至少2臺伺服器完成寫操作。

當我們執行如下操作時(將"name"為"lily"的"age"設定為20):

db.update({"name":"lily"},{"$set":{"age":20}})
預設情況下,該操作會使用WriteConcern.NORMAL(僅在網路錯誤時丟擲異常),等同於:

db.update({"name":"lily"},{"$set":{"age":20}},WriteConcern.NORMAL)
使用NORMAL模式引數,可以使得寫操作效率非常高。但是如果此時伺服器出錯,也不會返回錯誤給客戶端,而客戶端會誤認為操作成功。

因此在很多重要寫操作中需要使用WriteConcern.SAFE模式,保證可以感知到這個錯誤,保證客戶端和伺服器對一次操作的正確性認知保持一致。

(根據筆者測試,如果伺服器發生掉電情況,客戶端依然得不到當時操作的錯誤返回,需要特別注意)

另外在很多時候,我們需要確切知道這次寫操作是否成功(或者本次更新操作影響了多少個物件),這時候就需要:

WriteResult ret = db.update({"name":"lily"},{"$set":{"age":20}});
if(ret.getN()>0) //操作影響的物件個數
    return true;
else
    return false;
或者:
WriteResult ret = db.update({"name":"lily"},{"$set":{"age":20}});
if(ret.getLastError() == null)
    return true;
else
    return false;

此時,getLastError()會查詢上次操作結果是否出現錯誤。

更進一步
然後由於mongodb中使用連線池的原因,getLastError()需要再次從連線池中獲取連線,這樣效率會慢一些。可以這樣做:

db.requestStart();
WriteResult ret = db.update({"name":"lily"},{"$set":{"age":20}});
if(ret.getLastError() == null)
    return true;
else
    return false;
db.requestDone();
就可以保證update操作和getLastError()使用同一個連線,並且減少了一次存/取連線的過程。



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/15498/viewspace-1976412/,如需轉載,請註明出處,否則將追究法律責任。

相關文章