資料庫
指持久化資料庫,如
- mysql
- mongodb
緩存
指記憶體型的資料存儲,如
- redis
- memcached
一個良好的緩存政策需兼顧
- 命中率
- 緩存資料與資料庫資料的一緻性
對命中率的兼顧
多大的命中率是好的?
用數學知識來分析這個問題,先設定幾個關鍵的參數
- T(c):讀一次緩存所需時間
- T(d):讀一次資料庫所需時間
- G:緩存命中率
一次資料讀取所需的時間的期望值為:
T(c)*G + (T(c)+T(d))*(-G)
增加資料庫緩存的目标為提高資料讀取速度,可以歸結為一個表達式
T(c)*G + (T(c)+T(d))*(-G) < T(d)
等同于
T(c) - T(d)*G <
讀取速度提升的比值為
(T(d)*G - T(c))/T(d)
假如,T(d)=50ms,T(c)=10ms,G=0.6,讀取速度提升比值為
(* - )/ =
化為百分比也就是40%。
假如,T(d)=50ms,T(c)=10ms,G的值必須大于
G = T(c)/T(d) =
才能期望讀取速度得到提升。
可以看出
加入緩存不一定能夠提升讀取性能,這取決于緩存讀取速度、資料庫讀取速度以及緩存的命中率。
對資料一緻性的兼顧
這裡隻探讨對資料一緻性有高要求的場景,可以總結為
隻要資料庫有更新,就要使和已更新資料相關的所有緩存失效。
最終的政策
先從緩存的key入手
為了確定緩存資料的唯一性,key的字首可以是這樣的
<server_name>:<db_name>:<table_name>
- server_name 伺服器名稱
- db_name 資料庫名稱
- table_name 表名稱
還要區分簡單查詢與複雜查詢
- 簡單查詢:根據主鍵進行的查詢
- 複雜查詢:除簡單查詢外的都是複雜的
key字首加上查詢類型
<server_name>:<db_name>:<table_name>:<query_type>
舉個例子
對app伺服器上的資料庫做簡單查詢
對應的緩存key
app:homestead:users:simple:{,,}
複雜查詢
對應的緩存key
app:homestead:users:complex:{select * from homestead.users where age > }
緩存失效政策
假定sql-1更新了id為3,4,5的資料庫記錄
#sql-1
update homestead.users set age=age+ where age>
更新完成後需失效的緩存
- 緩存類型為複雜查詢的
- 緩存類型為簡單查詢的,且id包含3、4、5的
緩存選型
以上的政策需要緩存支援key的模糊查詢,例如查詢id包含3的類型為簡單查詢的緩存key。
Redis自1.0.0版本開始支援根據模式查詢緩存中的key,例如
KEYS app:homestead:users:simple:{*,,*}
可以看出,1.0.0及以上版本的Redis滿足該政策的需求。
不夠幸運的是,memcached暫時不滿足需求。