V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
liyunyang
V2EX  ›  程序员

分布式环境中,业务报错如何保证 redis 数据一致性?

  •  
  •   liyunyang · 2023-01-05 15:27:18 +08:00 · 2297 次点击
    这是一个创建于 675 天前的主题,其中的信息可能已经有所发展或是发生改变。
    这是一个困扰我很久的问题,一直不知道有什么好的处理方式,故来此地取经。

    举个例子:

    分布式订单服务 A 和库存服务 B

    服务 A 调用服务 B ,服务 A 修改了 redis 缓存,服务 B 报错了,全局事物回滚,服务 A 的缓存没有回滚

    各位大佬,这种情况有什么推荐处理方式吗?
    17 条回复    2023-01-07 07:50:33 +08:00
    qq976739120
        1
    qq976739120  
       2023-01-05 15:30:00 +08:00
    redis 的数据应该是跟着 mysql 的,所以 a 服务的数据库回滚以后,redis 应该跟着 a 服务的 mysql 走,而不是在 b 服务里做处理
    liyunyang
        2
    liyunyang  
    OP
       2023-01-05 15:45:30 +08:00
    @qq976739120 #1 redis 怎么回滚?
    7911364440
        3
    7911364440  
       2023-01-05 15:51:33 +08:00
    加一个服务监听数据库日志,数据写入成功再刷新缓存。
    leonshaw
        4
    leonshaw  
       2023-01-05 16:01:32 +08:00
    @liyunyang 失效
    zuixinwenyue
        5
    zuixinwenyue  
       2023-01-05 16:06:07 +08:00
    我觉得应该把修改 redis 缓存,放在调用服务 B 之后,如果调用 B 报错也不需要回滚 redis
    dwlovelife
        6
    dwlovelife  
       2023-01-05 16:06:28 +08:00
    服务 A 为什么不等服务 B 成功了再去修改缓存
    liyunyang
        7
    liyunyang  
    OP
       2023-01-05 16:16:34 +08:00
    @7911364440 #3 诶,这个应该是最好的方式吧,不过实现起来比较复杂,维护成本也不低
    liyunyang
        8
    liyunyang  
    OP
       2023-01-05 16:17:20 +08:00
    @dwlovelife #6 一言难尽,老项目了,业务非常复杂,如果是新功能,肯定会注意到这个的
    gold2022
        9
    gold2022  
       2023-01-05 17:09:21 +08:00
    @liyunyang 失效原来 redis 缓存,让他重新根据 mysql 生成缓存
    CodeSorcerer
        10
    CodeSorcerer  
       2023-01-05 18:05:20 +08:00   ❤️ 1
    用 canal 来更新 redis ?
    fkdog
        11
    fkdog  
       2023-01-05 19:02:21 +08:00   ❤️ 1
    将刷新缓存、发送 mq 等操作放到事务提交成功的 callback 里。
    如果 A 服务在事务中修改了 redis ,那么其他线程会读到错误的缓存数据。
    等事务完成同步到 db 里以后再去做缓存的更新操作。

    其实有的时候也没必要追求强一致,存库实时都在变,某个用户在某个时间点看到的库存也许再下一秒就变了,只要 CUD 的时候保证一致就行了。
    qq976739120
        12
    qq976739120  
       2023-01-05 21:02:54 +08:00
    @liyunyang 不是回滚 redis,是 a 数据库回滚后,有个服务去修改 redis
    vitoliu
        13
    vitoliu  
       2023-01-05 21:17:26 +08:00 via iPhone
    最简单的解决方案:每次更新操作,先清空所有缓存。
    notwaste
        14
    notwaste  
       2023-01-05 21:23:41 +08:00
    类似八股文很多,最常见的面试产物就是延迟双删,而且这里 A 服务不应该修改缓存而是删除缓存
    Joker1995
        15
    Joker1995  
       2023-01-05 21:53:23 +08:00   ❤️ 1
    我自己认为不 manual 去处理缓存,通过 canal+kafka 进行处理会好些,确实会有短时间的不一致
    Haires
        16
    Haires  
       2023-01-06 09:03:55 +08:00
    缓存应该是删除,而不是更新
    pagewang
        17
    pagewang  
       2023-01-07 07:50:33 +08:00 via iPhone
    失败后重新生成新的缓存,只允许第一个请求去 db 查库存,其他的读缓存
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2719 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 10:12 · PVG 18:12 · LAX 02:12 · JFK 05:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.