一個應用中決定加緩存(Redis,memcached)之前,要考慮的第一個問題就是,引進了緩存之後,會帶來哪些收益(利),付出哪些代價,引起哪些額外的問題(弊)? 任何新的中間件引進,收益和成本都是伴隨的,只有當利大於弊的情況下,能夠容忍其弊端(徹底解決?沒有額外代價又沒有負面影響,是不可能的,那就 ...
一個應用中決定加緩存(Redis,memcached)之前,要考慮的第一個問題就是,引進了緩存之後,會帶來哪些收益(利),付出哪些代價,引起哪些額外的問題(弊)? 任何新的中間件引進,收益和成本都是伴隨的,只有當利大於弊的情況下,能夠容忍其弊端(徹底解決?沒有額外代價又沒有負面影響,是不可能的,那就是不用就行了),才值得引進。 以Redis作為緩存為例,引進之後,其利和弊也是伴隨的。 帶來的收益:加速讀寫,提高併發性,降低後端持久化層資料庫的負載 付出的代價:增加代碼複雜,緩存本身的運維,潛在的數據不一致造成的影響。 數據不一致的存在 引進Redis(或者其他緩存)之後,應用程式和數據持久化層多了一個中間層,部分數據存儲由原來的單一持久化層,變為緩存層和持久化層兩份。 這兩部分數據在相互同步的過程中,在某些時間點上的維度來看,可能會潛在不一致的情況。 其中,潛在的數據不一致,是任何一個引進緩存層之後最面臨的最大的一個問題(當然兩者最終的數據是要保持一致的,這一點是底線)。 首先需要衡量的就是,這種潛在的不一致,會引發什麼樣的問題,帶來的問題是否可以接受範圍之內,或者是否會對應用程式邏輯引起致命的問題。 緩存和持久化層存儲可能會不一致,往往是緩存和持久化層未同步刷新引起的,
具體舉例說明: 第一種情況,比如點贊次數,瀏覽次數等等(讀多寫少的場景,寫MySQL,讀Redis,寫入了資料庫但是尚未同步到緩存層這個間隙)。 不會對業務產生嚴重的邏輯錯誤,這種暫時性的數據不一致是可以忍受的,另外就是,通過刷新等手段,兩者數據最終會達成一致。 第二種情況,比如銀行卡取款取超,導致餘額為負數,緩存和持久化層存儲的不一致造成嚴重的邏輯錯誤,這種是無法忍受的。
就需要考慮這種緩存層本身的設計是否合理? 輕量級做法,代碼邏輯實現 如果對於緩存的合理性沒有問題,且業務邏輯上要求緩存和持久化層強一致,那麼久要實現資料庫的一致性操作。 對於緩存和持久化層數據的一致性實現,個人的話,思路有以下兩種, 輕量級的做法如下: 對於引起數據變化的邏輯,一般都是“寫操作”,比如對數據的update或者delete或者insert操作, 1,首先去delete緩存中對應的數據(而不是去對應的update、delete、insert,為什麼?因為只要delete成功,緩存被清理之後,就消除了不一致的可能性,而非delete就做不到) 2,如果1執行成功,再去操作持久化層的資料庫, 3,最後將寫入成功之後的持久化層數據回寫緩存層(這一步可選,或者其它手段同步)
重量級分散式鎖實現,雙寫實現強一致
雙寫的安全性一般要通過分散式鎖來實現,分散式鎖可以通過zookeeper或者redis實現。
一旦考慮使用分散式鎖,又要考慮分散式鎖的載體的安全性,也即不管是用zookeeper或者redis,要考慮zookeeper或者redis的安全性(集群)。
這樣下去,問題會變得非常複雜,純粹變為解決問題-->引入新的問題-->解決問題的死迴圈。
如果要保持一致,當然雙寫也是一種選擇,不過通過雙寫來確保數據的絕對一致,不但會對整體效率產生負面的影響,實現也是比較困難的,暫時不討論這種方案。
但是不管怎麼樣,緩存層和持久化層,最終的數據是要保持一致的,這一點是底線。
整體來看,引不引入緩存層,是從整體性能、業務邏輯、實現代價、數據一致性的容忍程度等多個方面決定的。