2014-09-04 122 views
0

我一直在使用App Engine幾年,似乎一次又一次與HDR一起彈出的問題是,當您在一個屏幕上更新數據時,您將有時如果只讀請求是在更新的一兩秒內完成的,則會在該屏幕的只讀版本上檢索舊數據。我知道這已被討論herehere。我知道問題是什麼,但我想知道適當的解決方案可能是什麼?這是一個我可以在哪裏陳舊數據的例子。谷歌App Engine保存並避免獲取舊數據

假設您構建購物清單應用程序。

Entity 1: ShoppingList 
Entity 2: ShoppingListItem 

ShoppingList實體上有一個字段,用於保存列表中的總量項目。第二個實體是您的ShoppingListItem。當您添加或刪除ShoppingListItem時,您需要更新ShoppingList上的總數。你有兩種方法來更新總數。

  1. 查詢數據庫並統計ShoppingListItem表中的項目數。
  2. 自動遞增緩存的總字段+/- 1,而不需要統計數據庫。

有了這兩種解決方案,您最終會得到過時的數據。 #1可能已過時,因爲添加/刪除的原始保存可能尚未傳播。因此查詢會錯過新記錄。當您快速連續添加或移除多個項目時,#2將會有過時的數據。總數更新爲保存1但保存2,保存1可能仍在傳播,對於保存2的ShoppingList總計查詢仍將反映保存前的原始狀態1.

所以我的問題是,什麼是正確的方法來解決這個問題對我來說,似乎你有兩種選擇:

  1. 使用緩存總數時總是使用memcached實體。保存不會清除內存緩存,而是直接將更新後的實體注入到內存中。這使memcache保持最新狀態。這當然意味着不會觸及memcache的查詢(例如獲取所有ShoppingList實體的列表)可能仍會返回陳舊的數據。但至少當所有的保存完成後,數據庫中的緩存總數將是正確的。
  2. 處理您將要陳舊的數據,然後找出將來某個時間清理它的方法。可以安排一個TaskQueue重新查詢ShoppingList並在10-30秒內更新總數或者計劃一個每30秒運行一次的Cron Job並查找所有已更新的ShoppingList實體。

我傾向於解決方案#1。思考?

回答

0

我認爲在大多數情況下,@ david-w-smith的回答是正確的。但是,我在他的回答中提到了,使用實體組存在很大的侷限性。該限制是實體組每秒只能處理一次寫入。對於只有少數用戶的應用程序而言,這可能是正確的,但對於社交網絡來說這是不可接受的。

正如Google文檔(https://developers.google.com/appengine/docs/java/datastore/structuring_for_strong_consistency)也提出的那樣,我使用memcache實現了一個相當極端的緩存實現。所有的購物清單查詢結果都存儲在緩存中,當列表被更新,添加或刪除時,我也會更新緩存中查詢結果的狀態。我擔心維護兩個數據副本(數據庫和memcache)的自然複雜性,但這是UnitTests的用處。對?

4

選項3是給https://developers.google.com/appengine/docs/java/datastore/structuring_for_strong_consistencyhttps://developers.google.com/appengine/docs/java/datastore/structuring_for_strong_consistency仔細閱讀。你遇到的是「最終一致性」的典型表現。要特別注意實體組和祖先查詢。

+0

感謝您的建議。不幸的是我不能使用實體組,因爲每秒寫入限制爲1。從文檔:「這種方法通過寫入每個留言簿的單個實體組來實現強大的一致性,但它也將留言簿的更改限制爲每秒不超過1次寫入(支持的實體組限制)」 – dirkoneill 2014-11-12 00:25:08