精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

日本黄色片视频| 日本888xxxx| 四虎在线视频免费观看| 亚洲美女色禁图| 日韩高清a**址| 啊啊啊一区二区| 国产私人尤物无码不卡| 国产亚洲永久域名| 亚洲人成网站免费播放| 日本成人在线免费视频| 992tv免费直播在线观看| 国产在线不卡一区| 欧美韩国理论所午夜片917电影| 亚洲熟妇一区二区| 999福利在线视频| 久久久久久久久蜜桃| 成人黄色在线播放| 久久精品国产亚洲AV无码麻豆| 欧美韩一区二区| 欧美日韩国产免费一区二区| 女人被男人躁得好爽免费视频| 少妇av在线播放| 日本不卡视频在线| 欧美精品在线免费| 亚洲人人夜夜澡人人爽| 久久夜夜久久| 亚洲大片精品永久免费| www国产亚洲精品久久网站| 欧美日韩中文不卡| h片在线免费| 久久综合九色综合97婷婷| 国产欧美精品一区二区三区介绍| 亚欧精品视频一区二区三区| 亚洲国产欧美国产第一区| 欧美色欧美亚洲高清在线视频| 亚洲欧美丝袜| 国产黄色片免费| 免费亚洲婷婷| 欧美巨猛xxxx猛交黑人97人| 成人免费av片| 久久的色偷偷| 欧美少妇性性性| 日韩欧美视频免费在线观看| 色视频在线看| 国产精品99久久久久| 精品久久国产老人久久综合| 噼里啪啦国语在线观看免费版高清版| 岛国av在线播放| 亚洲免费观看高清| 中文字幕av导航| 成人高清在线| 国产精品人成在线观看免费| 亚洲国产日韩综合一区| 韩日视频在线| 国产午夜亚洲精品理论片色戒| 久久精品日产第一区二区三区精品版 | 精品久久亚洲| 欧美另类久久久品| 天天干天天玩天天操| 成人国产一区| 欧美日韩国产综合一区二区 | 99热播精品免费| 欧美亚洲国产一区二区三区| 男操女免费网站| 久久麻豆视频| 欧美军同video69gay| 岛国av免费在线| 麻豆一区在线| 亚洲国产精品va在看黑人| 日韩aaaaa| 精品一区在线| 少妇精69xxtheporn| 亚洲色图 激情小说| 68国产成人综合久久精品| 久久精品小视频| 强行糟蹋人妻hd中文| 国一区二区在线观看| 国内揄拍国内精品少妇国语| 欧美日韩综合在线观看| 六月婷婷一区| 国产日本欧美视频| 成人av手机在线| 99久久夜色精品国产网站| 精品国产乱码久久久久久蜜柚| 欧美一级特黄aaaaaa| 久久综合久久综合九色| 日韩免费电影一区二区| av中文字幕在线播放| 亚洲一区二区视频在线观看| aⅴ在线免费观看| 日韩深夜福利网站| 亚洲电影免费观看高清| 日韩av一二区| 亚洲成人精选| 欧美在线一区二区三区四| 在线免费观看一级片| 成熟亚洲日本毛茸茸凸凹| 欧美精品一区二区三区在线四季 | 久久国产精品久久国产精品| 日本少妇bbwbbw精品| 视频在线观看一区| 亚洲精品欧美一区二区三区| 日本不卡视频一区二区| 成人免费在线视频| 国产精品wwwww| 日韩一区二区三区在线看| 亚洲日韩欧美视频一区| 美女视频黄免费| 轻轻草成人在线| 国产精品区一区二区三在线播放| 又爽又大又黄a级毛片在线视频| 亚洲综合精品自拍| 在线观看免费黄网站| **国产精品| 亚洲男人av电影| 99热精品免费| 免费在线观看不卡| 韩国成人一区| 调教一区二区| 欧美日本乱大交xxxxx| 国产精品无码专区| 欧美韩日精品| 国产日本欧美在线观看| 三级黄视频在线观看| 一区av在线播放| 岛国av在线免费| 国产综合久久久| 欧美亚洲成人免费| 日本高清视频www| **性色生活片久久毛片| 日日躁夜夜躁aaaabbbb| 中日韩免视频上线全都免费| 午夜精品视频在线| 亚洲精品18p| 亚洲女人的天堂| 亚洲这里只有精品| 国产不卡一二三区| 日本91av在线播放| 三级网站免费观看| 一区二区高清视频在线观看| 亚洲日本黄色片| 色婷婷一区二区三区| 国产精品草莓在线免费观看| 少妇性bbb搡bbb爽爽爽欧美| 性做久久久久久免费观看欧美| 永久av免费在线观看| 婷婷六月综合| 成人性生交xxxxx网站| 又爽又大又黄a级毛片在线视频| 欧美性猛交xxxx黑人交| 免费看污片网站| 日本视频免费一区| 亚洲一卡二卡三卡| 亚洲国产天堂| 欧美成年人视频| www.日韩高清| 亚洲v精品v日韩v欧美v专区| 尤物网站在线观看| 国产精品日韩久久久| 久久久com| 欧美大片高清| 这里只有精品丝袜| 91亚洲国产成人久久精品麻豆| 中文字幕一区二区三中文字幕| 亚洲xxx在线观看| 91久久电影| 成人av资源| 韩日毛片在线观看| 亚洲欧美日韩在线一区| 亚洲精品无码久久久久| 中文av一区二区| 三上悠亚 电影| 在线精品福利| 农村寡妇一区二区三区| 一呦二呦三呦精品国产| 日韩天堂在线视频| 午夜精品久久久久久久爽| 午夜亚洲国产au精品一区二区| av在线网站观看| 人妖欧美一区二区| 欧美大片免费播放| 国产精品毛片av| 国产精品91久久久久久| 久操视频在线播放| 日韩电影在线观看中文字幕| 99re热视频| 亚洲男人天堂一区| 西西大胆午夜视频| 蜜臀av性久久久久蜜臀aⅴ流畅 | 黄大色黄女片18免费| 国产精品资源网| 欧美丰满熟妇bbbbbb百度| 精品国产成人| 动漫精品视频| 日本美女久久| 久久久之久亚州精品露出| 韩国福利在线| 精品日韩99亚洲| 一级特黄免费视频| 一区二区国产视频| 国产黄色录像视频| 成人av网站在线观看免费| 91香蕉视频污版| 在线看片日韩| 亚洲第一精品区| 亚洲自拍电影| 国产精品成人观看视频免费| 国产91亚洲精品久久久| 午夜免费久久久久| 成人ww免费完整版在线观看| 亚洲免费视频在线观看| 风流老熟女一区二区三区| 欧洲精品在线观看| a v视频在线观看| 亚洲欧美一区二区三区极速播放| 性囗交免费视频观看| 韩国成人精品a∨在线观看| 草草久久久无码国产专区| 欧美在线高清| 亚洲一区三区| 国产欧美一区| 精品一区二区三区免费毛片| 久久久久久爱| 国产在线999| jizz亚洲女人高潮大叫| 人九九综合九九宗合| gogo高清午夜人体在线| 欧美情侣性视频| 国产写真视频在线观看| 色综久久综合桃花网| 黄色av免费在线看| 日韩精品在线第一页| 亚洲国产精品久久人人爱潘金莲| 欧美日本在线看| 在线观看日批视频| 在线观看日韩高清av| 久久久久久久久久免费视频| 一区二区三区成人| 欧美国产在线看| 亚洲精品国产第一综合99久久| 久久久久亚洲AV成人无在| 久久久午夜精品理论片中文字幕| 久久一区二区电影| 不卡欧美aaaaa| 欧美大喷水吹潮合集在线观看| 成人免费三级在线| 中文字幕天堂网| eeuss国产一区二区三区| 国产+高潮+白浆+无码| 成人午夜激情在线| 亚洲乱妇老熟女爽到高潮的片| 高清久久久久久| 老司机午夜免费福利| 99在线热播精品免费| 好吊一区二区三区视频| 久久综合狠狠综合久久综合88| 日本黄色网址大全| 中文字幕第一页久久| 国产精品视频在| 最近日韩中文字幕| 九九热国产精品视频| 亚洲第一狼人社区| 国产午夜免费福利| 欧美专区在线观看一区| 一级久久久久久久| 日韩欧美在线不卡| 狠狠人妻久久久久久综合麻豆| 欧美不卡视频一区| 亚洲av片在线观看| 国产一区二区三区日韩欧美| 日本视频在线免费观看| 欧美高跟鞋交xxxxxhd| av资源中文在线天堂| 日韩男女性生活视频| 亚洲国产91视频| 国产伦精品一区二区三区高清| 免费成人结看片| 伊人久久大香线蕉av一区| 欧美88av| 37pao成人国产永久免费视频| 日本欧美一区二区在线观看| 爱情岛论坛亚洲自拍| 99久久精品情趣| 1024手机在线观看你懂的| 亚洲天堂中文字幕| 国产污污视频在线观看| 欧美色涩在线第一页| 亚洲第一页在线观看| 亚洲欧美精品伊人久久| 成人福利在线观看视频| 57pao国产成人免费| 欧美网站免费| 精品国产免费久久久久久尖叫 | youjizz在线视频| 欧美绝品在线观看成人午夜影视| 欧美一级淫片aaaaaa| 中文字幕精品一区二区精品| 丁香花在线影院| 国产精品一区电影| 欧亚精品一区| 加勒比海盗1在线观看免费国语版| 国产精品久久久久久模特 | 影音先锋在线国产| 制服丝袜日韩国产| 国产粉嫩一区二区三区在线观看| 欧美日韩福利在线观看| 本网站久久精品| 久久99精品国产一区二区三区| 亚洲成人日韩| 手机在线免费观看毛片| 91在线免费播放| 免费毛片在线播放免费| 欧美日韩综合一区| 日韩欧美电影在线观看| 久久久久久综合网天天| 亚洲日本免费电影| 日韩精品资源| 免费亚洲婷婷| 黄色污在线观看| 亚洲午夜久久久久久久久电影院 | 在线观看福利一区| 久久久久久一区二区| 91黄色免费视频| 亚洲一区二区三区影院| 国产精品视频一区二区三区,| 国产午夜精品全部视频在线播放| 国产ktv在线视频| 高清一区二区三区视频| 亚洲91中文字幕无线码三区| 中文字幕第38页| 中文字幕av一区二区三区免费看| 在线免费黄色av| 亚洲黄色在线看| 91资源在线观看| 国产精品久久久一区二区三区| 一级欧洲+日本+国产| 色18美女社区| 中文字幕一区免费在线观看 | 另类的小说在线视频另类成人小视频在线| 青青草视频成人| 高潮白浆女日韩av免费看| 天天摸天天干天天操| 1769国内精品视频在线播放| 都市激情亚洲| 国产毛片视频网站| 99精品欧美一区二区三区综合在线| 国产精品23p| 亚洲国产天堂网精品网站| 91破解版在线观看| 国产一区二区免费电影| 亚洲在线视频| 一卡二卡三卡四卡| 日本精品一区二区三区四区的功能| 你懂的视频在线观看| 国产97色在线| 手机在线电影一区| 亚洲国产综合av| 亚洲成人黄色影院| 亚洲 欧美 激情 另类| 欧洲一区二区视频| 精品国产一区二区三区四区| 午夜久久久精品| 亚洲欧美一区二区三区孕妇| 俄罗斯嫩小性bbwbbw| 91国产美女在线观看| 国产一区二区区别| 亚洲综合20p| 亚洲电影第三页| 二区在线观看| 亚洲专区在线视频| 在线日本高清免费不卡| 97超碰在线资源| 欧美精品一二三| 国产精品一品| 欧美日韩在线精品一区二区三区| 免费成人你懂的| 欧美成欧美va| 亚洲欧美精品一区| **国产精品| 日本www在线视频| 欧美高清在线一区二区| 精品人妻一区二区三区换脸明星 | 久久国产天堂福利天堂| av男人一区| 欧美日韩在线成人| 亚洲另类中文字| 青青草免费观看免费视频在线| 国产视频999| 日韩亚洲国产精品| 天天操天天摸天天舔| 亚洲成人黄色网址| 欧美国产日韩电影| 野外做受又硬又粗又大视频√| 久久久精品免费网站| www.日韩在线观看| 国产精品久久久久久久电影 | 欧美一级电影久久| 亚洲精品二区三区| 白白色免费视频| 亚洲精品在线免费播放|