美文网首页微服务实践程序员
实现缓存最终一致性的两种方案

实现缓存最终一致性的两种方案

作者: 小程故事多 | 来源:发表于2018-01-22 15:28 被阅读1443次

    一、重客户端

    写入缓存:

    image.png
    • 应用同时更新数据库和缓存
    • 如果数据库更新成功,则开始更新缓存,否则如果数据库更新失败,则整个更新过程失败。
    • 判断更新缓存是否成功,如果成功则返回
    • 如果缓存没有更新成功,则将数据发到MQ中
    • 应用监控MQ通道,收到消息后继续更新Redis。

    问题点:如果更新Redis失败,同时在将数据发到MQ之前的时间,应用重启了,这时候MQ就没有需要更新的数据,如果Redis对所有数据没有设置过期时间,同时在读多写少的场景下,只能通过人工介入来更新缓存。

    读缓存:

    如何来解决这个问题?那么在写入Redis数据的时候,在数据中增加一个时间戳插入到Redis中。在从Redis中读取数据的时候,首先要判断一下当前时间有没有过期,如果没有则从缓存中读取,如果过期了则从数据库中读取最新数据覆盖当前Redis数据并更新时间戳。具体过程如下图所示:

    image.png

    二、客户端数据库与缓存解耦

    上述方案对于应用的研发人员来讲比较重,需要研发人员同时考虑数据库和Redis是否成功来做不同方案,如何让研发人员只关注数据库层面,而不用关心缓存层呢?请看下图:


    image.png
    • 应用直接写数据到数据库中。
    • 数据库更新binlog日志。
    • 利用Canal中间件读取binlog日志。
    • Canal借助于限流组件按频率将数据发到MQ中。
    • 应用监控MQ通道,将MQ的数据更新到Redis缓存中。

    可以看到这种方案对研发人员来说比较轻量,不用关心缓存层面,而且这个方案虽然比较重,但是却容易形成统一的解决方案。

    推荐图书

    最后推荐一本很不错的技术书籍《深入分布式缓存》

    image.png

    京东购书二维码:


    image.png

    相关文章

      网友评论

      • 廖羽绒:有些业务的数据是不存数据库,只保存在缓存,有需要异地多活,这种情况有什么好办法?
      • 阿飞的博客:程大大,看过左耳朵耗子大神的博客,修改数据库后更新缓存可能存在很大的问题:A将数据库改为new_value_a,B改为new_value_b,这时候数据库正确的值是new_value_b,但是后面的更新缓存是异步的,可能导致先把缓存改为new_value_b再改为new_value_a这个错误的值!😂
        alsmn:@小程故事多 其实如果是按照耗子博客里的这种情况,用消息队列也不能保证顺序性的,因为并不能保证修改new_value_a的消息比修改new_value_b的消息先发到消息队列;(另外我们也是用的canal的方案,可以说清晰好用,对业务开发透明)
        小程故事多:@阿飞Javaer 如果更新数据库特别频繁的话,那就用队列确保消息的顺序性,我现在用的是binlog、已经实现的很好
      • Nathans:最后才是伏笔啊
        小程故事多:@邱睿_f880 关于方案有什么好建议可以多交流
        邱睿_f880:@Nathans 哈哈,卖书无错
      • 罗曼蒂克:这本书不错。
        如果是我来做更新缓存这块,我可能会采取最简单最笨的做法:与缓存相关的数据有写操作的时候,直接删除缓存对应的key。复杂度会降低,付出代价就是多查询一次。
        小程故事多:@藤伦柳揶 如果每次删除,并发量很高的时候,会有穿透风险
        一帅:58的沈剑老师是这样建议的,我也觉得是比较简单实用的方式
        小程故事多:@罗曼蒂克 删除会有穿透风险,这点你要注意

      本文标题:实现缓存最终一致性的两种方案

      本文链接:https://www.haomeiwen.com/subject/xiulaxtx.html