redis,db,mq一致性

本文探讨了在引入缓存后,如何解决缓存与数据库的一致性问题,对比了更新数据库+更新缓存和更新数据库+删除缓存两种方案,并深入分析了先更新数据库再删除缓存方案在并发场景下的应用,包括使用消息队列和订阅变更日志来确保数据一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

redis和db
2、引入缓存后,需要考虑缓存和数据库一致性问题,可选的方案有:「更新数据库 + 更新缓存」、「更新数据库 + 删除缓存」

3、更新数据库 + 更新缓存方案,在「并发」场景下无法保证缓存和数据一致性,且存在「缓存资源浪费」和「机器性能浪费」的情况发生

4、在更新数据库 + 删除缓存的方案中,「先删除缓存,再更新数据库」在「并发」场景下依旧有数据不一致问题,解决方案是「延迟双删」,但这个延迟时间很难评估,所以推荐用「先更新数据库,再删除缓存」的方案

5、在「先更新数据库,再删除缓存」方案下,为了保证两步都成功执行,需配合「消息队列」或「订阅变更日志」的方案来做,本质是通过「重试」的方式保证数据一致性,通过队列失败了可以过会重试,binlog后就更简单了,更新完全不需要关注缓存,接binlog消息删除缓存

6、在「先更新数据库,再删除缓存」方案下,「读写分离 + 主从库延迟」也会导致缓存和数据库不一致,缓解此问题的方案是「延迟双删」,凭借经验发送「延迟消息」到队列中,延迟删除缓存,同时也要控制主从库延迟,尽可能降低不一致发生的概率

缓存时间短点,尽可能降低不一致的影响时间,考虑事务也是一个方向,绝对的强一致是很难的,即时能做到,也及其影响性能,比如分布式锁。

db和mq
使用事务消息,sendMessage 往消息库插入一条记录,然后注册事务的回调,事务提交发消息,成功则删除消息。失败补偿任务重发,直到成功删除。

### Redis数据库数据一致性解决方案 为了保证Redis数据库之间的数据一致性,通常会采用以下几种方法: #### 1. 删除缓存策略 在修改数据库前,先删除对应的Redis缓存。这种方式可以确保下次读取该数据时,由于Redis中不存在对应键值,系统会重新从数据库加载最新数据并刷新到Redis中[^3]。 此方案简单易实现,但在高并发环境下可能会引发短暂的脏读现象。因此需结合其他手段优化,比如设置合理的过期时间或使用分布式锁控制访问顺序。 #### 2. 双写机制 双写是指同时向Redis数据库提交相同的操作请求。然而这种方法难以完全同步两者状态变化的时间差问题,尤其是在网络延迟或者异常中断情况下容易造成不一致情况的发生[^4]。 一种改进措施是引入消息队列作为中间件来协调两者的交互过程,即先把变更记录发送至MQ服务器,然后再分别通知目标存储完成相应动作。如此一来即使某个环节出现问题也不会立刻影响整体功能正常运行,并且可以通过后续补偿逻辑修复错误。 #### 3. 异步重试删除机制 针对可能出现的Redis删除失败情形设计专门处理流程——当检测到某条记录未能成功清除时启动定时任务不断尝试直至达成预期效果为止[^2]。这种做法虽然增加了开发成本但也极大提升了系统的可靠性水平。 另外还需关注几个重要方面: - **缓存的有效期限设定**:合理配置TTL参数有助于减少陈旧信息残留概率; - **更新策略制定**:依据具体应用场景灵活调整何时以及怎样触发相应的维护活动; 综上所述,通过综合运用以上提到的各种技术和管理措施可以在很大程度上缓解甚至解决因频繁操作而导致的数据偏差难题。 ```python import redis from sqlalchemy import create_engine, Column, Integer, String from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base() class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String) engine = create_engine('sqlite:///example.db') Session = sessionmaker(bind=engine) session = Session() r = redis.StrictRedis(host='localhost', port=6379, db=0) def update_user(user_id, new_name): user = session.query(User).filter_by(id=user_id).first() if not r.exists(f"user:{user_id}"): # 如果缓存已失效,则直接更新DB user.name = new_name session.commit() else: try: # 同时更新RedisDB r.set(f"user:{user_id}", new_name) user.name = new_name session.commit() except Exception as e: # 处理可能发生的异常 print(e) session.rollback() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值