所以怎麼從代碼層面解決這個問題,是取決於你是如何設計這個系統的。二級緩衝。把資料放在一個失效時間比較長的key裡。雪崩的時候加鎖,保證只有一個php進程訪問資料庫,其餘的看到鎖就不再訪問,直接返回在緩衝裡的資料。效果就是雖然好幾個人沒看到最新的資料,再刷一下就成了。搶到鎖的看到了最新資料。鎖可以用mc的add來實現。在我大渣浪的時候這套東西扛過nba的直播,c好幾十k,資料庫沒事,頻寬才是問題facebook 放過一篇論文《Scaling Memcache at Facebook》有討論過這個問題:
3.2.1 Leases We introduce a new mechanism we call leases to addresstwo problems: stale sets and thundering herds.
其中 "thundering herds" 正是樓主提到的資料庫穿透問題,一個熱的緩衝如果失效,在第一個訪問資料庫的請求得到結果寫入緩衝之前,期間的大量請求打穿到資料庫;然後 “stale set” 屬於資料一致性問題,假如一個執行個體更新了資料想去重新整理緩衝,而另一個執行個體讀 miss 嘗試讀取資料庫,這時兩次緩衝寫入順序不能保證,可能會導致到期資料寫入緩衝。
然後該鍵在寫入之前如果收到 get 請求,將返回一個 hot miss 報錯,用戶端依據它判斷自己要稍後重試,而不向資料庫讀取資料;
如果該鍵收到 delete 請求,那麼會使 lease 失效;持有失效 lease 的 set 請求仍將成功,但後來的 get 請求將得到 hot miss 報錯,並攜帶一個新的 lease;這裡的 hot miss 報錯中帶有最後的值,但認為它處於 stale 狀態,留給用戶端去判斷是否採用它,在一致性要求不嚴格的情境中可以進一步減少資料庫請求;
這一來允許 memcache 服務端協調資料庫的訪問,從而解決這兩個問題。
不過 lease 方案並不完美,因為 1. 需要改 memcache;2. 仍泄露邏輯到用戶端,要求用戶端遵循 lease 和 hot miss 的約定。
在 facebook 後面的論文《TAO: Facebook's Distributed Data Store for the Social Graph》中介紹TAO 系統嘗試解決的問題之一提到:
Distributed control logic: In a lookaside cache architecturethe control logic is run on clients that don’t communicatewith each other. This increases the number offailure modes, and makes it difficult to avoid thunderingherds. Nishtala et al. provide an in-depth discussion ofthe problems and present leases, a general solution [21].For objects and associations the fixed API allows us tomove the control logic into the cache itself, where theproblem can be solved more efficiently.
也就是說,我們並不一定非 look aside cache 不可,如果把緩衝的修改入口封裝起來,走 write though cache,就不需要分布式地去協調所有用戶端,在一個地方排隊就夠了。
References
Scaling Memcache at Facebook
TAO: Facebook's Distributed Data Store for the Social Graph