保证Redis和数据库一致性方法

张开发
2026/4/9 16:15:39 15 分钟阅读

分享文章

保证Redis和数据库一致性方法
阅读目录1、实时同步2、异步队列3、使用阿里的同步工具canal回到顶部1、实时同步对强一致要求比较高的应采用实时同步方案即查询缓存查询不到再从DB查询保存到缓存更新缓存时先更新数据库再将缓存的设置过期建议不要去更新缓存内容直接设置缓存过期。为什么不去更新缓存内容而是设置缓存过期呢答我们先来了解两个概念1.1.缓存穿透缓存穿透是指查询一个数据库中一定不存在的数据由于缓存是不命中时需要从数据库中查询查不到数据则不写入缓存这就将导致这个不存在的数据每次请求都要到数据库中查询造成缓存穿透。你可以通俗的理解直接把缓存穿透了没有利用到缓存。。。举例If(redis存在此key){查询redis值}else{查询数据库如果能查到数据就写入到redis中}这一段代码逻辑就会造成缓存穿透的恶果。。你想假设这个查询数据库中永远没有值那么这个redis中这个key是不是就不会创建那么代码就永远只走查询数据库这段代码跟redis没关系了。。解决缓存穿透很简单就是数据库查询不到也要缓存结果不过缓存结果赋值为空而已但它的过期时间会很短最长不超过五分钟。If(redis存在此key){Var redisValue查询redis值返回值}else{查询数据库.If(能查到数据){就写入到redis中}else{如果查询不到也写到redis中只不过值是空值}}要注意的点第一空值做了缓存意味着缓存层中存了更多的键需要更多的内存空间 ( 如果是攻击问题更严重 )比较有效的方法是针对这类数据设置一个较短的过期时间让其自动剔除。第二缓存层和存储层的数据会有一段时间窗口的不一致可能会对业务有一定影响。例如过期时间设置为 5分钟如果此时存储层添加了这个数据那此段时间就会出现缓存层和存储层数据的不一致此时可以利用消息系统或者其他方式清除掉缓存层中的空对象。第三Insert时需要事先移除要查询的key否则即便DB中有值也查询不到当然也可以设置空缓存的过期时间1.2.缓存雪崩如果缓存集中在一段时间内失效发生大量的缓存穿透所有的查询都落在数据库上造成了缓存雪崩。这个没有完美解决办法但可以分析用户行为尽量让失效时间点均匀分布。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线程进程写从而避免失效时大量的并发请求落到底层存储系统上。解决方法1. 加锁排队. 限流-- 限流算法1.计数2.滑动窗口3. 令牌桶Token Bucket4.漏桶 leaky bucket在缓存失效后通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存其他线程等待。业界比较常用的做法是使用mutex。简单地来说就是在缓存失效的时候判断拿出来的值为空不是立即去load db而是先使用缓存工具的某些带成功操作返回值的操作比如Redis的SETNX或者Memcache的ADD去set一个mutex key当操作返回成功时再进行load db的操作并回设缓存否则就重试整个get缓存的方法。SETNX是「SET if Not eXists」的缩写也就是只有不存在的时候才设置可以利用它来实现锁的效果。2.数据预热可以通过缓存reload机制预先去更新缓存再即将发生大并发访问前手动触发加载缓存不同的key设置不同的过期时间让缓存失效的时间点尽量均匀3.做二级缓存或者双缓存策略。A1为原始缓存A2为拷贝缓存A1失效时可以访问A2A1缓存失效时间设置为短期A2设置为长期。4.缓存永远不过期这里的“永远不过期”包含两层意思(1) 从缓存上看确实没有设置过期时间这就保证了不会出现热点key过期问题也就是“物理”不过期。(2) 从功能上看如果不过期那不就成静态的了吗所以我们把过期时间存在key对应的value里如果发现要过期了通过一个后台的异步线程进行缓存的构建也就是“逻辑”过期.从实战看这种方法对于性能非常友好唯一不足的就是构建缓存时候其余线程(非构建缓存的线程)可能访问的是老数据但是对于一般的互联网功能来说这个还是可以忍受。1.3.热点Key热点key某个key访问非常频繁当key失效的时候有大量的线程来构建缓存导致负载增加系统崩溃。解决办法1、使用锁单机用synchronizedlock等分布式用分布式锁2、缓存过期时间不设置而是设置在key对应的value里。如果检测到存的时间超过过期时间则异步更新缓存3、在value设置一个比过期时间t0小的过期时间值t1当t1过期的时候延长t1并做更新缓存操作4、设置标签缓存标签缓存设置过期时间标签缓存过期后需要异步更新实际缓存回到顶部2、异步队列对于并发程度较高的可采用异步队列的方式同步可采用kafka等消息中间件处理消息生产和消费。正在上传…重新上传取消回到顶部3、使用阿里的同步工具canalcanal是阿里巴巴旗下的一款开源项目纯Java开发。基于数据库增量日志解析提供增量数据订阅消费目前主要支持了MySQL也支持mariaDB。起源早期阿里巴巴B2B公司因为存在杭州和美国双机房部署存在跨机房同步的业务需求。不过早期的数据库同步业务主要是基于trigger的方式获取增量变更不过从2010年开始阿里系公司开始逐步的尝试基于数据库的日志解析获取增量变更进行同步由此衍生出了增量订阅消费的业务从此开启了一段新纪元。基于日志增量订阅消费支持的业务数据库镜像数据库实时备份多级索引 (卖家和买家各自分库索引)search build业务cache刷新价格变化等重要业务消息简单来说Canal 会将自己伪装成 MySQL 从节点Slave并从主节点Master获取 Binlog解析和贮存后供下游消费端使用。Canal 包含两个组成部分服务端和客户端。服务端负责连接至不同的 MySQL 实例并为每个实例维护一个事件消息队列客户端则可以订阅这些队列中的数据变更事件处理并存储到数据仓库中原理相对比较简单canal模拟mysql slave的交互协议伪装自己为mysql slave向mysql master发送dump协议mysql master收到dump请求开始推送binary log给slave(也就是canal)canal解析binary log对象(原始为byte流)

更多文章