最近接手的代碼中遇到幾個緩存的問題,存在一些設計原則的問題,這裏總結一下,但願能夠對你有幫助html
對外提供的接口web
List<Shop> getPageShop(final Query query,final Boolean cache);
返回的店鋪信息sql
public class Shop { public static final long DEFAULT_PRIORITY = 10L; /** * 惟一標識 */ private Long id; //省略了店鋪其餘信息 /** * 用戶關注 */ private ShopAttention attention; }
當調用方設置cache爲true時,由於有緩存的存在,獲取不到用戶是否關注的數據。數據庫
SQL緩存
SELECT shop_id, count(user_Id) as attentionNumber FROM shop_attention WHERE shop_id IN <foreach collection="shopIds" item="shopId" separator="," open="(" close=")"> #{shopId} </foreach> GROUP BY shopId
這兩種代碼的寫法都是基於一個基準app
不一樣的地方的緩存策略不同,好比我更新的地方,查找數據時不能緩存,頁面展現的查找的地方須要緩存。 既然服務提供方不知道該不應緩存,那就無論了,交給調用方去管理微服務
這種假設自己沒什麼問題,可是忽略了另一個原則,服務的內聚性。不該該被外部知道的就不必暴露給外部設計
不管是面向過程的C,仍是面向對象的語言,都強調內聚性,也就是高內聚,低耦合。單體應用中應當遵循這個原則,微服務一樣遵循這個原則。可是在實際過程當中,咱們發現作到高內聚並不簡單。咱們必需要時時刻刻審視方法/服務的邊界,只有肯定好職責邊界,才能寫出高內聚的代碼code
第一個問題,從緩存的角度來看,是忽略了數據的更新頻繁性以及數據獲取的不一樣場景。htm
對於店鋪這樣一個大的聚合根,自己包含的信息不少,有些數據可能會被頻繁更改的,有些則會不多更新的。那麼不一樣的修改頻率,是否緩存/緩存策略天然不一樣,使用同一個參數Boolean cache
來控制顯然不妥
第二個問題,這種統計類的需求使用SQL統計是一種在數據量比較小的狀況下的權宜之計,當數據規模增大後,必需要使用離線計算或者流式計算來解決。它自己是一個慢SQL,因此必需要控制號調用量,這種統計的數據量的時效性應該由服務方控制,不須要暴露給調用方。不然就會出現上述的問題,調用方並不清楚其中的邏輯,不走緩存的話就會使得調用次數增長,QPS的增長會致使慢SQL打垮數據庫
緩存更新自己就是一個難解的問題,在微服務化後,多個服務就更加複雜了。涉及到跨服務的多級緩存一致性的問題。
因此對大部分的業務,咱們能夠遵循這樣的原則來簡單有效處理。
以上述店鋪查詢問題改造爲例
擴展:若是後續有case在跨服務的調用時,對數據的過時比較敏感,而且在調用方也作了緩存,那就是跨服務的多級緩存一致性的問題。那就須要服務方告知調用方緩存什麼時候失效,使用消息隊列or其餘方式來實現。
關注【方丈的寺院】,與方丈一塊兒開始技術修行之路
https://martin.kleppmann.com/2012/10/01/rethinking-caching-in-web-apps.html