0

我試圖用python實現與ndb的強一致性。 而且看起來像我缺少一些東西,因爲我的閱讀表現得像他們不一致。Ndb強一致性和頻繁寫入

查詢是:

links = Link.query(ancestor=lead_key).filter(Link.last_status == 
None).fetch(keys_only=True) 

if links: 
    do_action() 

的關鍵結構是:

Lead root (generic key) -> Lead -> Website (one per lead) -> Link 

我有使用TaskQueue中同時執行多任務,這個查詢在每次任務結束時進行。有時我在更新last_status字段時收到「太多爭用」異常,但我使用重試來處理它。它能破壞一致性嗎?

預期的行爲是當last_status等於None時沒有鏈接而調用do_action()。實際行爲不一致:有時do_action()被調用兩次,有時根本不會調用。

回答

1

使用祖先密鑰獲得強一致性有一個限制:每個實體組的每秒更新次數限制爲一次。解決此問題的一種方法是分割實體組。 Sharding Counters描述了該技術。這是一篇舊文章,但據我所知,建議仍然健全。

+0

感謝您的回答!如果我經常更新實體會發生什麼情況? 'link.put()'需要更多時間,因爲它等待一段時間來保持每秒寫入1次的頻率?或者它立即返回並且隨後的祖先查詢可能會返回過期的結果? – subcoder

+0

我的回憶是,如果你超過了費率限制,你會得到一個例外,但我不知道另一個確切的例外。不過,這是一個簡單的嘗試。正如Dan所說,這是你需要在部署的應用程序中測試的東西。 –

1

添加到戴夫的答案這是第一件事要檢查。

有一件事沒有很好的文檔記錄,可能有點令人驚訝的是,爭用也可能由讀取操作引起,而不僅僅是寫入操作。

每當事務開始時,被訪問的實體組(通過讀或寫操作,無所謂)都被標記爲這樣。 too much contention錯誤表示太多並行事務同時嘗試訪問同一個實體組。即使沒有任何事務實際嘗試寫入,它也可能發生!

注:這個論點是不通過開發服務器仿真,它只能在GAE上部署的時候看到的,與真實數據存儲!

什麼可以添加到混亂是自動重新嘗試的事務,這可能發生在實際的寫入衝突或只是簡單的訪問爭用。對於最終用戶來說,這些重試可能會顯示爲某些代碼路徑的可疑重複執行 - 我懷疑這可能會解釋您被調用兩次的您的報告do_action()

通常當你遇到這樣的問題時,你必須重新訪問你的數據結構和/或你訪問它們的方式(你的交易)。除了保持強一致性(可能相當昂貴)的解決方案之外,您可能還想重新檢查一致性是否是必須的。在某些情況下,它只是因爲看起來簡化了一些東西而被作爲一個整體要求添加的。根據我的經驗,它不會:)

0

您的示例中沒有任何內容確保您的代碼只被調用一次。

目前,我將假設你的「do_action」函數對鏈接實體做了一些事情,特別是它設置了「last_status」屬性。

如果您沒有在事務內執行查詢和寫入鏈接實體,則可能有兩個不同的請求(任務隊列任務)從查詢中返回結果,然後將其新值寫入Link實體(最後寫入覆蓋前一個值)。

請記住,即使您確實使用了事務,在事務成功完成之前,您也不知道其他人是否嘗試執行寫操作。如果您嘗試在數據存儲的外部執行某些操作(例如,向外部系統發出http請求),這一點很重要,因爲您可能會看到來自事務的http請求,這些請求最終會因併發修改異常而失敗。