• 缓存与数据库如何保持一致性


    1、引言

    数据库压力过大时,会对数据库做读写分离,一个主库多个从库,

    当读压力过大时,又可以将要读的内容放在缓存中,比如放到redis中,mysql是将数据存在磁盘中,redis是存在内存里,这一点上redis读取数据要比mysql快几个数量级,

    同时内存也比磁盘贵几个数量级。。。

    那么,如何要保证redis和mysql中的数据一致,便是本文要讲的内容。

    2、读数据

    这个的流程没有多大讨论性,根据有限的缓存容量缓存最热的数据,经常读的数据被写入到缓存中,冷门的数据也会从缓存中淘汰(详见LRU等缓存淘汰算法)

    一般采用这么个逻辑:

    判断数据是否在缓存,若在:直接读取;若不在:从mysql中读取数据,再将数据写入redis。

    3、写数据

    (1)先删redis中的数据,再更新mysql中的数据

    如果在删缓存数据之后,有线程读到了未更新的数据(可能是并发问题、主从延迟等),然后将未更新的数据写入到了缓存中,产生了严重的数据不一致。

    因为写操作慢于读操作,发生概率较大。

    (2)先更新mysql中的数据,再删redis中的数据

    问题1:这种数据也有(1)方案中的一个相似问题,如下图:

     但分析一下发现这个概率是极低的,1、需要是缓存中没有读到数据的情况,2、读写线程撞在了一起,理论上读数据要比写数据快得多,写入缓存就更快了,发生上图中情况的概率很低。

    对于这个低概率问题的还是有点担心的,可以考虑适当延长数据库更新操作和删除缓存操作的间隔时间,比如将删除缓存操作放入到异步队列中执行。

    问题2:删除缓存可能失败

    可以在异步队列中增加一个重试机制

    4、异步队列的思考

    异步队列的增加无疑会增加系统的复杂性,且会增加维护难度。

    在生产中,一般由后台管理服务进行修改操作,前端服务来读取数据展示给用户看,在大公司中两个服务还会由不同的团队来维护。

    做一个更新操作后,,可能该数据涉及到的比如商品页面缓存要删,广告页面缓存要删等等,,,维护更加复杂了。。。。

    不如引入消息队列中间件,后台管理服务只充当生产者,将删除操作放入消息队列就啥都不用管了,其它服务来充当消费者。(解耦)

  • 相关阅读:
    Java统计程序运行时间(转)
    有符号定点数的表示方法
    移位运算符
    索引
    self与super的区别(转)
    Java经典题型(未完成)
    ObjectiveC 的 self 和 super 详解
    边界计算与不对称边界
    各种排序总结
    运算符的优先级
  • 原文地址:https://www.cnblogs.com/lnu161403214/p/13873483.html
Copyright © 2020-2023  润新知