-
1 # 網路圈
-
2 # 光明右使8787
要看應用場景,資料變動頻繁的環境中,使用讀快取是毫無意義的,反而加重系統負荷,因為要花費額外資源維護快取和資料來源的一致性。
其實redis可以當作資料庫的元資料使用,設計好資料結構就是一個簡單的關係型庫,業務資料完全放到redis中執行,MySQL當作後備庫使用。redis也有持久化機制而且很容易做映象,因此可以在很大時間粒度上進行資料同步,比如一天同步一次。而業務層只操作redis,與資料庫完全剝離,即使資料庫掛掉也不會導致業務中斷。
-
3 # 燕之心兒惆悵
對軟體開發同學來說,這個場景太常見了。基本的思路是:mysql資料發生變更的時候,要及時清除redis快取。那究竟要怎樣清除呢?
分兩種情況來說吧。
-
4 # java架構設計
Redis快取和MySQL資料一致性的問題,相信大家在大量使用redis快取進行業務開發的場景下是一定要考慮的問題。
總有運營、產品、測試人員過來問你為什麼我剛剛更新了一條資料,APP上還是原來的資料呢?你總是一句話:“加了快取,等會兒就好”。有可能是1分鐘,有可能是半小時。問你的都屬於關係不錯,不問你直接給你提bug你也沒辦法。
下面就分享一下我個人在工作中對如何解決redis快取和MySQL資料一致性的一些心得:
簡單粗暴大家看了這個圖是不是就知道什麼意思了?一個請求過來查詢資料,我先看看redis有沒有,有直接返回,沒有就去資料庫查出來,順便同步到redis,設定一下過期時間。下次同樣的資料查詢redis快取就可以直接返回了。是不是很簡單很粗暴?在實時性要求不高的場景下,這種方式我估計是大家最常用的一種方式。但是他有幾個問題:
無法保證一致性:資料庫更改了資料,redis裡的資料就和資料庫不一致了,產生髒讀;
快取雪崩:這種方案要求redis裡的快取必須設定有效期,如果在同一時間大面積過期,所有請求壓力都指向資料庫,這個時候資料庫頂不住壓力就會宕機,然後整個世界都安靜了;
快取穿透:查詢一個數據,快取沒有,去查詢資料庫,資料庫也沒有,怎麼辦?這樣的請求多了對資料庫也是壓力,沒有資料的時候也需要在redis快取一個空值。
快取同步針對第一種方案的問題,那麼大多數時候我們會繼續做一個job,去定時同步資料庫裡的資料都redis快取中,我們的業務請求直接查詢redis快取,無論有或者沒有資料都直接返回結果。這樣可以避免快取穿透、快取雪崩等問題,也能緩解redis快取和資料庫不一致的情況,但是還無法徹底解決一致性的問題。在job的間隔期內對資料的修改必須要等到下一次job的執行。
快取同步加強版針對上面的2中方案的問題,我們又搞了第三種方案,簡單概括就是:“實時重新整理、定時同步”八字方案。具體如下:
增加一個cache中介軟體,專門處理各類快取同步事件,採用訊息佇列機制保證每一次資料的操作都能夠重新整理對應的快取資料;
採用elastic-job做定時的增量/全量資料同步;
服務請求大部分走redis,高併發API只走快取,不允許流量進入資料庫層面;
以上三種方案我們都有采用,即使現在更多采用第三種方案,但是前兩種我們依舊在用,不同的場景採用不同的方案。三種方案的結合基本上能滿足我們的業務在資料一致性的需求。
-
5 # 蓮花童子哪吒
在高併發的業務場景下,資料庫的效能瓶頸往往都是使用者併發訪問過大。所以,一般都使用redis做一個緩衝操作,讓請求先訪問到redis,而不是直接去訪問MySQL等資料庫。從而減少網路請求的延遲響應
資料為什麼會不一致這樣的問題主要是在併發讀寫訪問的時候,快取和資料相互交叉執行。
一、單庫情況下
同一時刻發生了併發讀寫請求,例如為A(寫) B (讀)2個請求
A請求傳送一個寫操作到服務端,第一步會淘汰cache,然後因為各種原因卡主了,不在執行後面業務(例:大量的業務操作、呼叫其他服務處理消耗了1s)。
B請求傳送一個讀操作,讀cache,因為cache淘汰,所以為空
B請求繼續讀DB,讀出一個髒資料,並寫入cache
A請求終於執行完全,在寫入資料到DB
總結:因最後才把寫操作資料入DB,並沒同步。cache裡面一直保持髒資料
髒資料是指源系統中的資料不在給定的範圍內或對於實際業務毫無意義,或是資料格式非法,以及在源系統中存在不規範的編碼和含糊的業務邏輯。
二、主從同步,讀寫分離的情況下,讀從庫而產生髒資料
A請求傳送一個寫操作到服務端,第一步會淘汰cache
A請求寫主資料庫,寫了最新的資料。
B請求傳送一個讀操作,讀cache,因為cache淘汰,所以為空
B請求繼續讀DB,讀的是從庫,此時主從同步還沒同步成功。讀出髒資料,然後髒資料入cache
最後資料庫主從同步完成
總結:這種情況下請求A和請求B操作時序沒問題,是主從同步的時延問題(假設1s),導致讀請求讀取從庫讀到髒資料導致的不一致
根本原因:
單庫下,邏輯處理中消耗1s。可能讀到舊資料入快取
主從+讀寫分離,在1s的主從同步時延中。讀到從庫的舊資料入快取
資料最佳化方案一、快取雙淘汰法
先淘汰快取
再寫資料庫
往訊息匯流排esb傳送一個淘汰訊息,傳送立即返回。寫請求的處理時間幾乎沒有增加,這個方法淘汰了快取兩次。因此被稱為“快取雙淘汰法“,而在訊息匯流排下游,有一個非同步淘汰快取的消費者,在拿到淘汰訊息在1s後淘汰快取,這樣,即使在一秒內有髒資料入快取,也能夠被淘汰掉。
二、非同步淘汰快取
上述的步驟,都是在業務線裡面執行,新增一個線下的讀取binlog非同步淘汰快取模組,讀取binlog總的資料,然後進行非同步淘汰。
1.思路:
MySQL binlog增量釋出訂閱消費+訊息佇列+增量資料更新到redis
1)讀請求走Redis:熱資料基本都在Redis
2)寫請求走MySQL: 增刪改都操作MySQL
3)更新Redis資料:MySQ的資料操作binlog,來更新到Redis
2.Redis更新
1)資料操作主要分為兩塊:
一個是全量(將全部資料一次寫入到redis)
一個是增量(實時更新)
這裡說的是增量,指的是mysql的update、insert、delate變更資料。
-
6 # 彼得羅829
非常簡單,開啟binlog,監聽日誌實時重新整理redis。這樣查詢不會有問題,業務寫也不會有問題。而且還超級簡單。管他單點快取還是分散式快取,通通搞定
回覆列表
隨著技術發展,現在專案技術選型不像從前那樣單一的,特別是在高併發場景下的專案,都是多種技術配套著來使用。在以前,對於使用者資料無論是增刪改查,我們都是直接操作資料庫的,但在高併發場景下這樣做顯然是不合理的,於是乎我們在DB層之前加上Cache層,以此來緩解DB層的壓力。
在業界通常是將MySQL作為資料最終落地的儲存方案,而用Redis來快取熱點資料。一般是讀資料是從Redis中讀取,增刪改則是操作MySQL。但是這樣會存在一個問題,即:讀操作和寫操作是併發的,執行順序無法保證,這樣很容易出現快取資料與資料庫中的資料不一致。
舉例說明一下:
假設我們更新了資料庫後,快取一直沒有失效,那我們從快取中讀取的就是髒資料。
假設快取中的資料不存在,我們從資料庫中讀取資料然後存入快取,此時資料庫剛好更新,那在快取期間內,這個快取資料就是髒資料。
如何避免Redis和MySQL中資料一致性問題呢?結合我的經驗給出一些方案供大家參考:
1、首先確定你的業務是否要求快取和資料庫之間是強一致性關係
如果你的業務要求資料庫和快取之間是強一致性,那你要做的就是確保每次更新了MySQL後就同步更新Redis;
如果不需要強一致性,那我們合理控制好快取的TTL即可。
2、藉助MQ訊息來更新快取
大概思路是,資料庫的每一次修改操作後,我們透過MQ來生產一條訊息,然後消費者對應去清理快取Key並重新寫入。