但是一直都沒有仔細下去看,因為覺得問題不大,
直到剛好看到這篇
https://kkc.github.io/2020/03/27/cache-note/
裡面大概講到幾種避免的方式:
- 弄個 cronjob/worker 定期去更新,這就犯了一個常見的問題。
- cache 到底是 cache 還是 storage?
- 如果是 cache,那他應該是 on demand 的才對吧?
- cache fail 了,程式應該要知道怎麼 fallback!
- 既然是兩個地方都要處理同樣的邏輯,程式的架構是寫死在一個地方,還是寫成 component?
- lock 機制
- 當大家同時遇到某個 cache expire 了,就用 lock 來搶吧!
- 所以只有搶到 lock 的那個 request 可以真的 query db,其他的就在那邊 sleep!
- 那要等多久?等到天荒地老?要不要設定一個 timeout?如果 timeout 到了,還是沒辦法從 redis 拿到資料該怎麼辦?一樣大家進去操 db?
- xfetch 機制
- 會在 query db 的時候把要花多久存下來(aka delta),之後在每次要 get cache 的時候,一次把 cache value/ttl & delta 都拿出來,先比對 delta 如果 >= ttl 的話,就預先做一次 query db,然後把資料存回來。
- 那如果同時好幾個人都 get cache,然後大家都要去 query db 呢?
- xfetch 用了一個 random 來判斷!
- 沒錯,用 random,所以最差就是大家一起死,不然就是等到大家都 cache expire 了,再一起死!
這些方法,聽起來都好像可以,但是真的實作起來,其實都還是怪怪的。
- cron job 如果程式架構可以,要處理的 hot spot 也夠明確,的確能立即解決問題!
- 但是在 cloud 的時代,每個 instance 都應該是沒有狀態在上面,也不應該在上面跑 cronjob 才對。不然大家都一起跑,還不是一樣大家都戳一次!
- lock 好像也很好,但是在很多 instance 很多 process 的狀況下,該怎麼 lock 呢?
- 有的人會說,redis 有 redlock,對,的確可以用,不過就算 lock/unlock 的時間點抓得夠好,還是會有其他的 request 在那邊等的狀況發生(不過原本 request 在等,有可能是 query db,所以無論如何都在等,無所謂)
- xfetch 看起來是比較聰明的,但是蠢就在,他用 random 去判斷誰該做事,random ㄟ,random ㄟ!沒有更聰明的?
經過一段沈思跟試驗實作之後,我覺得真正簡單又可以動的版本應該是這樣的:
xfetch + lock
要提前 query db,但是又要想辦法讓同時間只有一個 query db 的動作!
那要怎樣做到這些事情?
要感謝 redis 後來有 server side lua 了,可以讓你在 redis 裡面先做一些判斷,
client 只要一個 packet 就可以拿到他要的結果!