redis学习(6) | 青训营笔记

62 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 14 天

和Mysql保持数据一致性

保底策略:设置过期

cache-aside 策略

对DB做变更操作时,不同步变更缓存,而是删除缓存中的对应条目

该策略又可以细分为「读策略」和「写策略」

  • 写策略

    更新数据库中的数据; 删除缓存中的数据。

  • 读策略的步骤:

    读取的数据命中了缓存,则直接返回数据;

    如果读取的数据没有命中缓存,则从数据库中读取数据,然后回写到缓存,

    最后返回数据给用户

写策略的两种顺序:

先删缓存,再更新DB

问题:执行👆两个操作中间插入一次读操作,读操作使得回写旧值到缓存,

而DB存的新值,造成不一致(删写被读加塞)

==》延时双删,删除读请求可能造成的缓存脏数据,但延迟时间不好评估

# 伪代码
def delay_delete():
    redis.delKey(X) #删除缓存
    
    db.update(X) #更新数据库
    
    Thread.sleep(N)
    redis.delKey(X) #再删除缓存

先更新DB,再删缓存

问题:对于新数据,一次读操作会有回写数据到缓存的过程,如果这之间插入👆两个操作,

会导致DB中的值被更新,同时缓存是回写的旧值,造成不一致(读被写删加塞)

==》但在实际中,DB读取+缓存回写速度 要快于 DB写入+删除缓存,所以发生概率低

第二个删除缓存 失败

会导致不一致,有两种应对方法

『异步重试』

将第二个操作(删除缓存)要操作的数据加入到消息队列,由消费者来重试,

只要失败就从消息队列中重新读取数据,直到成功

可靠性的保证:

  • 消息队列保证可靠性:写到队列中的消息,成功消费之前不会丢失(重启项目也不担心)
  • 消息队列保证消息成功投递:下游从队列拉取消息,成功消费后才会删除消息,否则还会继续投递消息给消费者(符合我们重试的场景)

『订阅数据库变更日志,再操作缓存』

更新数据库成功,就会产生一条变更日志,记录在 binlog 里,

通过订阅 binlog 日志,解析后,再删除缓存

==》Canal中间件,伪装成Mysql从节点,同步binlog并解析

==》思路都是 异步操作缓存