2016-09-07 53 views
1

對於特定的數據庫表,我們需要內存緩存中的數據始終與數據庫同步。我目前的嘗試是將更改寫入after_commit鉤子中 - 這樣我們就不會將任何更改寫入緩存,以便以後恢復。確保將數據緩存在after_commit掛接時的一致性

然而,這種策略很容易受到以下情形:

  1. 線程A的鎖和更新記錄,保存的價值1
  2. 線程A提交了更改
  3. 線程B的鎖和更新記錄,商店值2
  4. 線程B提交更改
  5. 線程B運行after_commit掛接,因此緩存現在的值爲2
  6. 線程A運行after_commit掛鉤,所以緩存目前擁有價值1但應該有值2

我說得對不對這個問題,一個是如何解決這個問題?

回答

1

我們提出的解決方案是鎖定緩存以讀取/寫入before_commit並在after_commit中解鎖。這似乎有伎倆。

2

你是對的這個問題。

有一個after_save回調,在同一個事務中運行。您可能想要使用該工具,而不是交易後運行的after_commit掛鉤。

但是,您將需要自己處理回滾事務。

或者您可能希望以不依賴特定實例的方式編寫緩存方法。但是首先通過重新加載數據庫中的記錄來緩存數據庫中找到的最新版本。

但甚至:多線程系統很難保持同步。而且你甚至不能確定是否存儲發送到緩存的第一個或第二個更新,因爲緩存系統也可能是多線程的。

您可能想要了解有關different consistency models的更多信息。

+0

感謝您的見解。由於緩存涉及整個樹結構,因此在那裏處理回滾實際上意味着要爲緩存重新實現類似db的事務處理。只需使緩存無效並稍後重新加載它也是一種解決方案,但對於樹結構而言非常複雜。這種問題沒有解決方案嗎? – Remo

+1

記錄更改的頻率如何?你多久閱讀一次記錄?緩存中的結構有多複雜?也許有可能優化你的數據庫模式的閱讀,而不是依靠緩存來閱讀? – spickermann

+0

記錄可以經常更改,它是一個50-100k記錄的樹形結構,所以我認爲這不是讀取(每個請求)沒有緩存的選項。該查詢是一個嵌入式查詢,大約需要1.4秒,我沒有看到很多優化潛力。 – Remo

相關問題