在项目开发的时候,我们会经常发现,首页或者热门的数据都 存放在缓存中而不是直接请求数据库,并发情况下直接请求数据库,会增加数据库的服务压力,这时候就需要引入缓存,缓存目前用的比较多的是(redis,memcache 一个是单线程一个是多线程),在数据库被更新的时候就存在缓存数据没有被更新,导致缓存和数据库的数据不一致的问题。
解决方案一:
通过key的过期时间控制,MySQL更新,缓存不更新,但两者数据不一致的时间过长的话。在并发较高的情况下,过期时间过长,会产生很多长期的脏数据;
不足点:
完全依赖过期时间,时间太短容易缓存频繁失效,太长很容易导致过长的时间缓存和数据库数据不一致的问题。
解决方案二:
在方案一的基础上,通过过期时间兜底,并且在更新数据库的时候 更新redis;
不足点:
更新MySQL成功,在更新redis却失败了,这时候就需要等redis 过期才能更新缓存
在并发情况下更新数据,会增加数据库的压力;
解决方案三:
针对方案二对redis进行优化,增加队列机制,将redis的更新交给mq,利用消息队列的可靠性,搭建一个消息服务,用来异步的更新缓存
解决方案四:
通过订阅binlog来更新redis,把我们搭建的消费服务,作为mysql的一个slave,订阅binlog,解析出更新内容,再更新到redis
这样一旦MySQL中产生了新的写入、更新、删除等操作,就可以把binlog相关的消息推送至Redis,Redis再根据binlog中的记录,对Redis进行更新。
其实这种机制,很类似MySQL的主从备份机制,因为MySQL的主备也是通过binlog来实现的数据一致性。
这里可以结合使用canal(阿里的一款开源框架),通过该框架可以对MySQL的binlog进行订阅,而canal正是模仿了mysql的slave数据库的备份请求,使得Redis的数据更新达到了相同的效果。
当然,这里的消息推送工具你也可以采用别的第三方:kafka、rabbitMQ等来实现推送更新Redis。
如何保证mq消费的时候拿到最新消息?
mq的消息是无顺的,如何保证多数据信息消费的时候消费到最新的数据,需要在消息中放入一个创建时间,在数据更新的时候,先去查询一下,拿到更新时间对比消息的创建时间,当时间小于更新时间不于更新,反之更新。