精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

技術派中的緩存一致性解決方案

數據庫 MySQL
這篇文章很基礎,也非常適用,大家可以直接下載技術派項目,里面都有代碼和測試用例,代碼倉庫詳見:https://github.com/itwanger/paicoding

大家好,我是樓仔呀。

之前寫過一篇《高頻面試:如何保障 MySQL 和 Redis 的數據一致性?》,閱讀量直奔 7K,但是里面只有理論,沒有實戰,今天就結合技術派項目,告訴大家如何去實現 MySQL 和 Redis 的一致性。

在講解實戰部分之前,我們還是先回顧一下理論知識,根據網上的眾多解決方案,我們總結出 6 種:

圖片

你可以先想想,技術派會采用哪種方案呢?

理論知識

溫馨提示:如果你對理論知識已經非常清楚,可以直接跳到文章的實戰部分。

不好的方案

1. 先寫 MySQL,再寫 Redis

圖片

圖解說明:

  • 這是一副時序圖,描述請求的先后調用順序;
  • 橘黃色的線是請求 A,黑色的線是請求 B;
  • 橘黃色的文字,是 MySQL 和 Redis 最終不一致的數據;
  • 數據是從 10 更新為 11;
  • 后面所有的圖,都是這個含義,不再贅述。

請求 A、B 都是先寫 MySQL,然后再寫 Redis,在高并發情況下,如果請求 A 在寫 Redis 時卡了一會,請求 B 已經依次完成數據的更新,就會出現圖中的問題。

這個圖已經畫的很清晰了,我就不用再去啰嗦了吧,不過這里有個前提,就是對于讀請求,先去讀 Redis,如果沒有,再去讀 DB,但是讀請求不會再回寫 Redis。 大白話說一下,就是讀請求不會更新 Redis。

2. 先寫 Redis,再寫 MySQL

圖片

同“先寫 MySQL,再寫 Redis”,看圖可秒懂。

3. 先刪除 Redis,再寫 MySQL

這幅圖和上面有些不一樣,前面的請求 A 和 B 都是更新請求,這里的請求 A 是更新請求,但是請求 B 是讀請求,且請求 B 的讀請求會回寫 Redis。

圖片

請求 A 先刪除緩存,可能因為卡頓,數據一直沒有更新到 MySQL,導致兩者數據不一致。

這種情況出現的概率比較大,因為請求 A 更新 MySQL 可能耗時會比較長,而請求 B 的前兩步都是查詢,會非???。

好的方案

4. 先刪除 Redis,再寫 MySQL,再刪除 Redis

對于“先刪除 Redis,再寫 MySQL”,如果要解決最后的不一致問題,其實再對 Redis 重新刪除即可,這個也是大家常說的“緩存雙刪”。

圖片

為了便于大家看圖,對于藍色的文字,“刪除緩存 10”必須在“回寫緩存10”后面,那如何才能保證一定是在后面呢?網上給出的第一個方案是,讓請求 A 的最后一次刪除,等待 500ms。

對于這種方案,看看就行,反正我是不會用,太 Low 了,風險也不可控。

那有沒有更好的方案呢,我建議異步串行化刪除,即刪除請求入隊列

圖片

異步刪除對線上業務無影響,串行化處理保障并發情況下正確刪除。

如果雙刪失敗怎么辦,網上有給 Redis 加一個緩存過期時間的方案,這個不敢茍同。個人建議整個重試機制,可以借助消息隊列的重試機制,也可以自己整個表,記錄重試次數,方法很多。

簡單小結一下:

  • “緩存雙刪”不要用無腦的 sleep 500 ms;
  • 通過消息隊列的異步&串行,實現最后一次緩存刪除;
  • 緩存刪除失敗,增加重試機制。

5. 先寫 MySQL,再刪除 Redis

圖片

對于上面這種情況,對于第一次查詢,請求 B 查詢的數據是 10,但是 MySQL 的數據是 11,只存在這一次不一致的情況,對于不是強一致性要求的業務,可以容忍。(那什么情況下不能容忍呢,比如秒殺業務、庫存服務等。)

當請求 B 進行第二次查詢時,因為沒有命中 Redis,會重新查一次 DB,然后再回寫到 Reids。

圖片

這里需要滿足 2 個條件:

  • 緩存剛好自動失效;
  • 請求 B 從數據庫查出 10,回寫緩存的耗時,比請求 A 寫數據庫,并且刪除緩存的還長。

對于第二個條件,我們都知道更新 DB 肯定比查詢耗時要長,所以出現這個情況的概率很小,同時滿足上述條件的情況更小。

6. 先寫 MySQL,通過 Binlog,異步更新 Redis

這種方案,主要是監聽 MySQL 的 Binlog,然后通過異步的方式,將數據更新到 Redis,這種方案有個前提,查詢的請求,不會回寫 Redis。

圖片

這個方案,會保證 MySQL 和 Redis 的最終一致性,但是如果中途請求 B 需要查詢數據,如果緩存無數據,就直接查 DB;如果緩存有數據,查詢的數據也會存在不一致的情況。

所以這個方案,是實現最終一致性的終極解決方案,但是不能保證實時性。

幾種方案比較

我們對比上面討論的 6 種方案:

  1. 先寫 Redis,再寫 MySQL
  • 這種方案,我肯定不會用,萬一 DB 掛了,你把數據寫到緩存,DB 無數據,這個是災難性的;
  • 我之前也見同學這么用過,如果寫 DB 失敗,對 Redis 進行逆操作,那如果逆操作失敗呢,是不是還要搞個重試?
  1. 先寫 MySQL,再寫 Redis
  • 對于并發量、一致性要求不高的項目,很多就是這么用的,我之前也經常這么搞,但是不建議這么做;
  • 當 Redis 瞬間不可用的情況,需要報警出來,然后線下處理。
  1. 先刪除 Redis,再寫 MySQL
  • 這種方式,我還真沒用過,直接忽略吧。
  1. 先刪除 Redis,再寫 MySQL,再刪除 Redis
  • 這種方式雖然可行,但是感覺好復雜,還要搞個消息隊列去異步刪除 Redis。
  1. 先寫 MySQL,再刪除 Redis
  • 比較推薦這種方式,刪除 Redis 如果失敗,可以再多重試幾次,否則報警出來;
  • 這個方案,是實時性中最好的方案,在一些高并發場景中,推薦這種。
  1. 先寫 MySQL,通過 Binlog,異步更新 Redis
  • 對于異地容災、數據匯總等,建議會用這種方式,比如 binlog + kafka,數據的一致性也可以達到秒級;
  • 純粹的高并發場景,不建議用這種方案,比如搶購、秒殺等。

個人結論:

  • 實時一致性方案:采用“先寫 MySQL,再刪除 Redis”的策略,這種情況雖然也會存在兩者不一致,但是需要滿足的條件有點苛刻,所以是滿足實時性條件下,能盡量滿足一致性的最優解。
  • 最終一致性方案:采用“先寫 MySQL,通過 Binlog,異步更新 Redis”,可以通過 Binlog,結合消息隊列異步更新 Redis,是最終一致性的最優解。

項目實戰

數據更新

因為項目對實時性要求高,所以采用方案 5,先寫 MySQL,再刪除 Redis 的方式。

下面只是一個示例,我們將文章的標簽放入 MySQL 之后,再刪除 Redis,所有涉及到 DB 更新的操作都需要按照這種方式處理。

這里加了一個事務,如果 Redis 刪除失敗,MySQL 的更新操作也需要回滾,避免查詢時讀取到臟數據。

@Override
@Transactional(rollbackFor = Exception.class)
public void saveTag(TagReq tagReq) {
    TagDO tagDO = ArticleConverter.toDO(tagReq);

    // 先寫 MySQL
    if (NumUtil.nullOrZero(tagReq.getTagId())) {
        tagDao.save(tagDO);
    } else {
        tagDO.setId(tagReq.getTagId());
        tagDao.updateById(tagDO);
    }

    // 再刪除 Redis
    String redisKey = CACHE_TAG_PRE + tagDO.getId();
    RedisClient.del(redisKey);
}

@Override
@Transactional(rollbackFor = Exception.class)
public void deleteTag(Integer tagId) {
    TagDO tagDO = tagDao.getById(tagId);
    if (tagDO != null){
        // 先寫 MySQL
        tagDao.removeById(tagId);

        // 再刪除 Redis
        String redisKey = CACHE_TAG_PRE + tagDO.getId();
        RedisClient.del(redisKey);
    }
}

@Override
public void operateTag(Integer tagId, Integer pushStatus) {
    TagDO tagDO = tagDao.getById(tagId);
    if (tagDO != null){

        // 先寫 MySQL
        tagDO.setStatus(pushStatus);
        tagDao.updateById(tagDO);

        // 再刪除 Redis
        String redisKey = CACHE_TAG_PRE + tagDO.getId();
        RedisClient.del(redisKey);
    }
}

數據獲取

這個也很簡單,先查詢緩存,如果有就直接返回;如果未查詢到,需要先查詢 DB ,再寫入緩存。

我們放入緩存時,加了一個過期時間,用于兜底,萬一兩者不一致,緩存過期后,數據會重新更新到緩存。

@Override
public TagDTO getTagById(Long tagId) {

    String redisKey = CACHE_TAG_PRE + tagId;

    // 先查詢緩存,如果有就直接返回
    String tagInfoStr = RedisClient.getStr(redisKey);
    if (tagInfoStr != null && !tagInfoStr.isEmpty()) {
        return JsonUtil.toObj(tagInfoStr, TagDTO.class);
    }

    // 如果未查詢到,需要先查詢 DB ,再寫入緩存
    TagDTO tagDTO = tagDao.selectById(tagId);
    tagInfoStr = JsonUtil.toStr(tagDTO);
    RedisClient.setStrWithExpire(redisKey, tagInfoStr, CACHE_TAG_EXPRIE_TIME);

    return tagDTO;
}

測試用例

/**
 * @author Louzai
 * @date 2023/5/5
 */
@Slf4j
public class MysqlRedisService extends BasicTest {

    @Autowired
    private TagSettingService tagSettingService;

    @Test
    public void save() {
        TagReq tagReq = new TagReq();
        tagReq.setTag("Java");
        tagReq.setTagId(1L);
        tagSettingService.saveTag(tagReq);
        log.info("save success:{}", tagReq);
    }

    @Test
    public void query() {
        TagDTO tagDTO = tagSettingService.getTagById(1L);
        log.info("query tagInfo:{}", tagDTO);
    }
}

我們看一下 Redis:

127.0.0.1:6379> get pai_cache_tag_pre_1
"{\"tagId\":1,\"tag\":\"Java\",\"status\":1,\"selected\":null}"

以及結果輸出:

圖片

后記

這篇文章很基礎,也非常適用,大家可以直接下載技術派項目,里面都有代碼和測試用例,代碼倉庫詳見:https://github.com/itwanger/paicoding。

后面我會把 RabbitMQ、ES、Nacos、MongoDB 和 prometheus 都集成到技術派項目,不為其它的,存粹為了自娛自樂。

責任編輯:武曉燕 來源: 樓仔
相關推薦

2022-12-14 08:23:30

2021-06-06 12:45:41

分布式CAPBASE

2020-11-02 07:09:24

緩存服務器異構

2010-05-24 11:35:11

WCDMA

2023-06-07 08:10:29

2020-05-12 10:43:22

Redis緩存數據庫

2023-06-29 08:00:59

redis數據MySQL

2020-06-01 22:09:48

緩存緩存同步緩存誤用

2025-02-04 15:48:21

悲觀鎖數據庫應用

2022-09-06 15:30:20

緩存一致性

2017-07-25 14:38:56

數據庫一致性非鎖定讀一致性鎖定讀

2019-09-20 21:50:47

數據庫緩存

2024-12-26 15:01:29

2019-03-27 13:56:39

緩存雪崩穿透

2025-08-08 07:09:58

2025-11-12 00:25:00

2021-12-01 08:26:27

數據庫緩存技術

2023-11-01 10:11:00

Java分布式

2024-05-28 00:50:00

RedisMySQL緩存

2020-10-26 19:25:23

CPU緩存Cache
點贊
收藏

51CTO技術棧公眾號

国产一区二区免费| 亚洲伊人伊色伊影伊综合网| 国产精品亚洲一区二区三区| 天天鲁一鲁摸一摸爽一爽| 在线视频亚洲欧美中文| 天天综合色天天综合色h| 色综合视频二区偷拍在线| 国产老女人乱淫免费| 日韩午夜一区| 久久精品视频在线| 国产又黄又粗又猛又爽的视频| 色天使综合视频| 一区二区三区在线免费播放 | 女人抽搐喷水高潮国产精品| 欧美中文一区二区三区| 超碰成人免费在线| 在线观看免费版| 久久综合中文字幕| 91免费版黄色| 精品国产青草久久久久96| 影音先锋久久| 美女久久久久久久久久久| 法国空姐电影在线观看| 91蝌蚪精品视频| 欧美精品第一页| 成人3d动漫一区二区三区| 欧美videossex| 国产精品乱人伦一区二区| 久久av免费一区| 丰满肉肉bbwwbbww| 国产一区二区不卡老阿姨| 国产精品成人av性教育| 成年人视频在线免费看| 国产精品xvideos88| 日韩小视频在线| 这里只有久久精品| 亚洲精品国产动漫| 亚洲国产精品字幕| 日本美女视频网站| 欧美一区一区| 日韩写真欧美这视频| 奇米影视四色在线| 国产一区二区主播在线| 色综合久久久久综合99| av免费观看大全| 国产乱码在线| 亚洲高清视频中文字幕| 麻豆一区二区三区在线观看| 日本在线看片免费人成视1000| 国产亚洲一区二区在线观看| 久久久久高清| 肉丝一区二区| 久久久久国产成人精品亚洲午夜| 久久久久资源| 日韩有码电影| 久久精品亚洲麻豆av一区二区 | 不卡在线一区二区| 国产亚洲精品美女久久久| 国产小视频自拍| 国产精品一在线观看| 亚洲欧美日韩爽爽影院| av女人的天堂| 欧美精品一区二区三区中文字幕| 亚洲午夜精品久久久久久性色 | 欧美日韩视频| 久久久久久国产精品美女| 久久综合久久鬼| 亚洲激情另类| 人人澡人人澡人人看欧美| 男人的天堂av网站| 久久9热精品视频| 91传媒免费看| 五月天久久久久久| 久久久久久久综合狠狠综合| 水蜜桃亚洲一二三四在线| 亚洲1卡2卡3卡4卡乱码精品| 日韩在线播放中文字幕| 91亚洲成人| 九九精品视频在线| 日韩黄色a级片| 久久av一区二区三区| 国产精品日韩专区| 精品二区在线观看| 91美女片黄在线| 三区精品视频| 日本色护士高潮视频在线观看| 五月天丁香久久| 日韩精品无码一区二区三区免费| 一区在线不卡| 亚洲第一页在线| 中文字幕免费在线看线人动作大片| 国产精品黑丝在线播放 | 成年女人在线看片| 日本黄色一区二区| 中文字幕一二三区| 视频一区欧美| 欧美猛男性生活免费| 狠狠人妻久久久久久| 精品在线你懂的| 激情一区二区三区| 永久免费在线观看视频| 亚洲一区二区三区四区在线免费观看 | 国产精品视频永久免费播放| 99产精品成人啪免费网站| av在线不卡免费看| 青青草原国产免费| 91久久国产综合久久91猫猫| 欧美一区二区三区在线观看| 久久精品一区二区免费播放 | 欧美国产综合色视频| 特大黑人娇小亚洲女mp4| 亚洲国产福利| 精品日本一线二线三线不卡| 波多野结衣一二三四区| 亚洲福利久久| 91在线看www| 波多野结衣在线网站| 亚洲成人激情av| 亚洲色图欧美自拍| 精品理论电影在线| 97人人爽人人喊人人模波多 | 国产视频久久久久| 久久久久久久久艹| 毛片av一区二区| 欧美成人在线免费观看| 麻豆av在线播放| 在线播放中文字幕一区| 亚洲女优在线观看| 亚洲综合激情| 国产视频一区二区三区四区| av在线下载| 777久久久精品| 91麻豆精品国产91久久综合| 国产精品久久久久毛片大屁完整版| 亚洲精品女av网站| 色大18成网站www在线观看| 色丁香久综合在线久综合在线观看| 成人做爰www看视频软件| 中文字幕亚洲综合久久五月天色无吗''| 国产成人自拍视频在线观看| 婷婷五月综合激情| 亚瑟在线精品视频| 四虎精品一区二区| 激情亚洲成人| 国产精品一区在线观看| 成人影院在线播放| 亚洲精品一区二区三区蜜桃下载 | 日韩欧美卡一卡二| 国产女人被狂躁到高潮小说| 国产在线精品一区二区夜色 | a篇片在线观看网站| 欧美一区永久视频免费观看| 亚洲精品久久久久久国| 久久成人免费网站| 最新欧美日韩亚洲| 国产欧美日韩电影| 精品中文字幕在线| 视频二区在线观看| 欧美午夜电影在线| 舐め犯し波多野结衣在线观看| 天堂午夜影视日韩欧美一区二区| 欧美日韩无遮挡| 999国产精品亚洲77777| 日韩视频精品在线| 国产v片在线观看| 精品国产日韩欧美| 欧美丝袜美女中出在线| 大地资源二中文在线影视观看| 亚洲精品社区| 欧美激情第一页在线观看| 欧美性suv| 日韩在线免费观看视频| av一区二区三| 姬川优奈aav一区二区| 天天躁日日躁aaaa视频| 九一九一国产精品| 男人添女荫道口女人有什么感觉| 好吊妞国产欧美日韩免费观看网站| 97视频在线观看成人| 牛牛热在线视频| 欧美日韩一区精品| 久久精品99国产精| 久久综合99re88久久爱| 亚州精品一二三区| 欧美特黄a级高清免费大片a级| 国产欧美日韩一区| 91九色综合| 九九视频直播综合网| 日本福利在线观看| 欧美人狂配大交3d怪物一区| 精品视频一区二区在线观看| 久久精品一区八戒影视| 绯色av蜜臀vs少妇| 六月婷婷一区| 免费人成在线观看视频播放| 蜜桃成人av| 91久久国产综合久久蜜月精品| 欲香欲色天天天综合和网| 日韩在线观看免费全| 五月婷婷六月激情| 欧美精品高清视频| 中文字幕在线播| 亚洲免费三区一区二区| 夜夜春很很躁夜夜躁| 成人在线视频首页| 色乱码一区二区三区在线| 雨宫琴音一区二区在线| 这里只有精品66| 一区二区三区韩国免费中文网站| 亚洲在线免费视频| 素人啪啪色综合| 性亚洲最疯狂xxxx高清| 福利在线视频网站| 一本大道亚洲视频| 天天躁日日躁狠狠躁喷水| 日韩欧美色综合| 一区二区三区在线免费观看视频 | 黄色一级视频免费看| 亚洲精品五月天| 天天干天天操天天拍| 91亚洲资源网| 性农村xxxxx小树林| 国模一区二区三区白浆| 毛葺葺老太做受视频| 亚洲日产国产精品| 久久综合亚洲精品| 偷拍欧美精品| 一本色道久久综合亚洲二区三区| 青青操综合网| 国产一区二区在线网站| 亚洲日本va| 亚洲伊人久久大香线蕉av| 秋霞国产精品| 国产精品扒开腿做爽爽爽视频| 久久久男人天堂| 97国产在线视频| xxxx视频在线| 欧美极品少妇xxxxⅹ裸体艺术| 麻豆系列在线观看| 精品久久久av| 一级日本在线| 北条麻妃久久精品| 91社区在线观看| 色哟哟入口国产精品| 成人亚洲综合天堂| 中文字幕一区日韩电影| 国产福利在线看| 最近2019免费中文字幕视频三| 久久精品蜜桃| 一区二区三区久久精品| 精品推荐蜜桃传媒| 永久免费精品影视网站| 中文字幕在线视频区| 日韩中文娱乐网| 免费看a在线观看| 色综合久久88| 91吃瓜在线观看| 91成人在线观看国产| 在线视频cao| 国产精品久久久久久久久粉嫩av| 亚洲www啪成人一区二区| 国产精品视频免费在线| 亚洲欧美专区| 国产精品久久久久久久天堂第1集| 99精品中文字幕在线不卡 | 国产91在线免费观看| 成人在线视频一区二区| 成人网站免费观看| 亚洲国产精品av| 成年人一级黄色片| 亚洲成人7777| 波多野结衣电影在线播放| 精品视频一区三区九区| 国产三级漂亮女教师| 欧美精品一区二区三区一线天视频 | 美女脱光内衣内裤视频久久影院| 成人不卡免费视频| 神马亚洲视频| 色婷婷激情久久| 夜夜骚av一区二区三区| 日韩一区二区三区免费观看| 殴美一级特黄aaaaaa| 亚洲午夜色婷婷在线| sm国产在线调教视频| 韩国三级日本三级少妇99| 欧美日韩不卡| 999在线观看免费大全电视剧| 香蕉久久99| 99热这里只有精品7| 一本久久综合| www.五月天色| 久久久久久久性| 玖玖爱这里只有精品| 欧美日韩在线免费观看| 亚洲影院一区二区三区| 精品福利一区二区三区免费视频| 人成在线免费视频| 久久九九免费视频| 都市激情亚洲一区| 亚洲伊人久久综合| 精品一区欧美| av一区二区三区免费观看| 三级一区在线视频先锋| 四虎永久免费观看| 国产精品三级视频| 国产污污视频在线观看| 日韩一区二区三区电影| 国模吧精品人体gogo| 久久免费精品日本久久中文字幕| 国产亚洲欧美日韩精品一区二区三区 | 精品视频在线播放一区二区三区 | 一本色道久久hezyo无码| 日本一区二区动态图| 日韩三级视频在线| 欧美一级欧美三级| 啊v视频在线| 欧美亚洲视频一区二区| 97一区二区国产好的精华液| 在线观看成人av| 日韩在线观看一区二区| 最近日本中文字幕| 亚洲精品伦理在线| 在线观看国产一区二区三区| 亚洲免费av网址| 搞黄网站在线看| 91久久精品在线| 久久免费精品视频在这里| 男女激情无遮挡| 国产99精品国产| 欧美成人精品欧美一级| 欧美精选午夜久久久乱码6080| 黄色av免费在线观看| 91高清视频在线免费观看| 一区二区三区亚洲变态调教大结局 | 亚洲婷婷免费| 女同性αv亚洲女同志| 亚洲日穴在线视频| 亚洲在线观看av| 最好看的2019的中文字幕视频| 免费福利视频一区二区三区| 精品一区二区国产| 国产一区二区你懂的| 欧洲一级黄色片| 欧美午夜视频在线观看| 男人天堂手机在线观看| 欧美激情第1页| a级日韩大片| 国产黄色片免费在线观看| 成人激情av网| 日本一区二区不卡在线| 亚洲第一区中文字幕| 99爱在线观看| 久久国产精品99久久久久久丝袜| 99精品热视频只有精品10| 亚洲欧美在线不卡| 精品久久久久久中文字幕| 亚洲欧洲国产综合| 欧美中文字幕精品| 狠狠做六月爱婷婷综合aⅴ | 国产精品原创巨作av| 欧美成人三级在线观看| 精品99一区二区三区| 超碰激情在线| 日韩电影免费观看在| 美腿丝袜亚洲一区| 国产盗摄x88av| 日韩av网站在线| av免费在线一区| 久久免费看毛片| 成人久久久精品乱码一区二区三区 | 99久久综合| 中国特级黄色大片| 色香色香欲天天天影视综合网| 中国日本在线视频中文字幕| 91在线直播亚洲| 亚洲午夜黄色| 亚洲无人区码一码二码三码的含义| 欧美视频一二三区| 91在线中字| 蜜桃日韩视频| 狠狠色综合日日| 日韩欧美高清在线观看| 国产亚洲人成a一在线v站| 91嫩草国产线观看亚洲一区二区| www.好吊操| 中文字幕精品一区二区精品绿巨人| 国产sm主人调教女m视频| 91精品国产乱码久久久久久久久| 日产午夜精品一线二线三线| 黑人巨大猛交丰满少妇| 色哟哟一区二区在线观看| 怡红院在线播放| 蜜桃免费一区二区三区| 国产精品资源网站| 欧美a视频在线观看| 九九精品在线播放| 国产一区二区三区探花| 动漫av在线免费观看| 欧美性高清videossexo| а√天堂8资源中文在线|