• redis缓存一致性问题


    转自:https://segmentfault.com/a/1190000023925209,https://blog.csdn.net/weixin_39530557/article/details/110860066

    1.缓存一致性问题

    是指缓存和数据库数据不同步的问题。比较依赖缓存的过期和更新策略。一般会在数据发生更改的时,主动更新缓存中的数据或者移除对应的缓存。

     不管是先写MySQL数据库,再删除Redis缓存;还是先删除缓存,再写库,都有可能出现数据不一致的情况:

    • 如果删除了缓存Redis,还没有来得及写库MySQL,另一个线程就来读取,发现缓存为空,则去数据库中读取数据写入缓存,此时缓存中为脏数据。
    • 如果先写了库,在删除缓存前,写库的线程宕机了,没有删除掉缓存,则也会出现数据不一致情况。【即上图第3行】

    因为写和读是并发的,没法保证顺序,就会出现缓存和数据库的数据不一致的问题。

    2.缓存类型

    按照Redis缓存是否接受写请求,可以分为只读缓存和读写缓存。

    2.1 只读缓存

    使用只读缓存时,是先把修改写到后端数据中,再把缓存中的数据删除。下次访问时,再从后端数据库读取。

    • 优点:数据库和缓存完全一致,缓存中永远保留的是经常访问的热点数据。
    • 缺点:数据删除后访问会触发一次缓存缺失,从后端数据库加载数据到缓存中,这个过程访问延时会变大。

    2.2 读写缓存

    读和写的请求都会发到缓存处理。最新的数据是在Redis中,但redis是内存数据库,如果宕机则数据丢失,所以,根据业务应用对数据可靠性和缓存性能的不同要求,会有两种策略,分别是同步直写异步写回

    • 同步直写,优先保证数据可靠性:写请求发给缓存,同时也会发给后端数据库进行处理,等到缓存和数据库都写完数据,才给客户端返回。【能够保证一致性】但在高并发场景下,可能会导致缓存和数据库的不一致。
    • 异步写回,优先提供快速响应:所有写请求都先在缓存中处理,等到这些增改的数据要被缓存淘汰时,缓存再写回后端数据库。【只修改缓存,淘汰时再写库】

    总结:

    • 只读缓存牺牲一定性能,优先保证数据库和缓存的一致性,更适合对于一致性要求比较高的业务场景。
    • 对于数据库和缓存一致性要求不高,或者不存在并发修改同一个值的情况,使用读写缓存比较合适,保证更好的性能。

    3.解决方案 

    3.1 延时双删

    https://zhuanlan.zhihu.com/p/467410359,讲的并不清晰,画的图不解释。。。

    def update_data(key, obj):
        del_cache(key)     # 删除 redis 缓存数据。
        update_db(obj)     # 更新数据库数据。
        logic_sleep(_time) # 当前逻辑延时执行。
        del_cache(key)     # 删除 redis 缓存数据。

    但为什么要先删除缓存?以及为什么要延时?为什么要第二次删除缓存?好多疑问。

    延时:为了redis和mysql数据同步?那为什么还要删第二次?

    缺点:

    • 有等待环节,如果系统要求低延时,这种场景就不合适了;
    • 不适合“秒杀”这种频繁修改数据和要求数据强一致的场景;
    • 延时时间是一个预估值,不能确保 mysql 和 redis 数据在这个时间段内都实时同步或持久化成功了。

    3.2 设置过期时间

    redis 的定位是缓存热点数据,热点数据应该设置过期时间,当数据过期后,redis 会自动淘汰,这样当业务服务节点从 redis 查询已淘汰的数据时,查询不到数据,会重新从 mysql 数据库读取数据写入 redis。

    3.3 异步更新缓存(基于订阅binlog的同步机制)

    1. 读Redis:热数据基本都在Redis
    2. 写MySQL:增删改都是操作MySQL
    3. 更新Redis数据:MySQ的数据操作binlog,binlog更新到消息队列,增量实时更新到Redis,增量是指update、insert、delate等变更数据。

    类似mysql的主从备份机制。消息推送工具也可以用:kafka、rabbitMQ等。

  • 相关阅读:
    算法(第四版)C# 习题题解——2.4
    算法(第四版)C# 习题题解——2.3
    .NET编译的目标平台(AnyCPU,x86,x64)
    Windows无法访问局域网内共享文件夹[0x800704cf,0x80070035]解决方案
    ASP.NET 网站部署到IIS上如何进行调试
    ASP.NET 前台Javascript调用后台代码 / 后台调用前台Javascript
    C#反射-Assembly.Load、LoadFrom与LoadFile
    Entity Framework Context上下文管理(CallContext 数据槽)
    Entity Framework(EF的Code First方法)
    Entity Framework(EF的Model First方法)
  • 原文地址:https://www.cnblogs.com/BlueBlueSea/p/16677977.html
Copyright © 2020-2023  润新知