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