走進緩存的世界(二) - 緩存設計

系列文章

 

如何設計緩存

主要考慮三個問題:html

  • 緩存哪些數據
  • 如何緩存
  • 如何保證數據一致性

緩存哪些數據

 系統優化時有一句話必須切記:「優化無止境」,因此若是緩存不是必須的,請果斷去掉,要知道越是業務上覆雜的系統,對Cache的使用反而越簡單,由於對於一個複雜、多變、歷史悠久的系統,在Cache方面作過分設計會讓人深陷其中;緩存的數據越多,系統的維護成本就越高,因此找準須要緩存的點尤其重要。通常狀況下,咱們只會緩存給系統帶來巨大瓶頸的IO操做,在普通應用裏尤爲指由top SQL或者慢 SQL所帶來的DAO查詢;找準須要優化的sql,你能夠找DBA幫忙。redis

如何緩存 

存儲介質的選擇: 你能夠直接緩存在JVM內存裏,也能夠採用阿里雲專門的緩存服務器,如tair、memcache等;sql

DB、文件其實也能夠作緩存,他們通常緩存複雜計算的中間結果,通常不多用到;若是你的緩存是存放在jvm本地,那麼一般是用map實現,若是緩存數據更新比較頻繁且對數據正確性比較高,那麼你須要考慮爲其添加併發控制和失效策略。還有一點比較重要的就是,在集羣環境下想要作到數據一致性比較困難,主動更新比較麻煩並且達不到其下降數據庫IO操做的效果,因此本地緩存適用場景通常是在讀訪問很是高,而寫操做極少,對數據一致性要求不是特別高的場景;若是採用專門的緩存服務器則避免了不少麻煩,阿里雲的緩存系統tair,是咱們常用的緩存中間件,它提供了很好的併發控制和失效機制,另外還提供了不一樣存儲引擎能夠供咱們選擇,如mdb,rdb,ldb;普通的緩存能夠選擇mdb和rdb,二者分別有memcache和redis的影子,其響應時間和高QPS的表現都很是好,但沒有提供持久化,若是要確保數據不丟失能夠採用ldb引擎存儲,它提供了對數據持久化的支持,相反犧牲了一點點性能。數據庫

數據一致性

緩存意味着一樣的數據可能有多份並存,若是你的代碼沒有考慮某種狀況致使了兩份數據不一致就會有問題發生。解決方法很簡單,把你的業務邏輯、代碼觸發狀況都考慮清楚,不要遺留沒有觸底的地方。緩存

多處使用緩存會致使你的代碼邏輯變得異常複雜,這也是爲什麼說在非必要的時候,建議你不要用緩存的緣由。服務器

緩存一致性協議就是爲了解決數據一致性問題而發明的。緩存一致性協議有多種,大多數計算機設備使用的都屬於「窺探(snooping)」協議。併發

「窺探」的基本思想是,內存是共享資源,全部內存I/O傳輸都發生在一條共享的總線上,全部的處理器都能看到這條總線,全部處理器對內存的訪問請求都要通過仲裁(arbitrate):同一個指令週期中,只有一個處理器能夠讀寫內存中的被緩存的數據。窺探協議的思想是,緩存不只僅在作內存傳輸的時候才和總線打交道,而是不停地在窺探總線上發生的數據交換,跟蹤其餘緩存在作什麼。因此當一個緩存表明它所屬的處理器去讀寫內存時,其餘處理器都會獲得通知,以此來使本身的緩存保持同步。只要某個處理器執行寫操做,其餘處理器立刻就知道這塊內存在它們本身的緩存中對應的段已經失效。jvm

在直寫模式下,這是很直接的,由於寫操做一旦發生,它的效果立刻會被「公佈」出去。可是若是混着回寫模式就有問題了。由於有可能在寫指令執行事後好久,數據纔會被真正回寫到物理內存中。在這段時間內,其餘處理器的緩存可能會去寫同一塊內存地址致使衝突。在回寫模型中,簡單把內存寫操做的信息廣播給其餘處理器是不夠的,咱們須要作的是,在修改本地緩存以前,就要告知其餘處理器。oop

搞懂了細節,就找到了處理回寫模式這個問題的最簡單方案。當處理器想寫某個緩存段時,若是它沒有獨佔權,它必須先發送一條「我要獨佔權」的請求給總線,這會通知其餘處理器,把它們擁有的同一緩存段的拷貝失效(若是它們有的話)。只有在得到獨佔權後,處理器才能開始修改數據——而且此時,這個處理器知道,這個緩存段只有一份拷貝,在我本身的緩存裏,這樣一來就能夠巧妙地避免了衝突。性能

相關文章
相關標籤/搜索