有关Redis的其他一些采访问题也已写过,例如常见的缓存渗透,雪崩,故障和热点问题,但还有一个更麻烦的问题是如何确保缓存一致性。
对于缓存和数据库操作,主要有以下两种方法。
首先删除缓存,然后更新数据库。
首先删除缓存,并且数据库尚未成功更新。
此时,如果读取了高速缓存,则高速缓存不存在,并且从数据库中读取旧值,并且发生高速缓存不一致。
解决方案延迟双重删除延迟双重删除的思想是避免在更新数据库时其他线程无法从缓存中读取数据。
更新数据库后,请休眠一会儿,然后再次删除缓存。
。
应该为业务读写缓存时间评估睡眠时间,并且睡眠时间应大于读写缓存时间。
过程如下:线程1删除缓存,然后更新数据库。
线程2读取缓存。
发现缓存已被删除,因此可以直接从数据库中读取它。
此时,线程1尚未更新,因此它将读取旧值。
然后将旧值写入高速缓存线程1。
根据估计的时间进入睡眠状态。
由于睡眠时间大于线程2读取数据+写入高速缓存的时间,因此将再次删除该高速缓存。
如果还有其他线程要读取缓存,它将再次从数据库中读取最新值,首先更新数据库,然后删除缓存。
如果操作相反,请先更新数据库,然后再删除缓存?这是一个更明显的问题。
如果数据库已成功更新,如果对缓存的删除失败或没有时间删除,则其他线程将从缓存中读取旧值,并且仍然会发生不一致。
解决方案消息队列这是Internet上许多文章中已编写的解决方案。
但是该方案的缺点将更加明显。
首先更新数据库,成功后将消息发送到消息队列,使用完消息后删除缓存,并使用消息队列的重试机制达到最终一致性的效果。
这种解决方案实际上是有更多问题的。
引入消息中间件之后,问题变得更加复杂。
如何确保消息不会丢失更麻烦。
即使更新数据库和删除缓存没有问题,消息的延迟也会带来短期的不一致,但是该延迟是可以接受的。
为了解决高速缓存一致性的问题,高级版本的消息队列引入了一个单独的消息队列,这太复杂了。
实际上,大多数大公司都有自己的消息队列,用于侦听Binlog消息,主要是为了进行检查。
这样,我们可以使用消息队列监视binlog删除缓存。
这样做的好处是您不需要自己介绍它并入侵您的业务代码。
中间件可帮助您解耦。
同时,中间件本身保证了高可用性。
当然,消息延迟的问题仍然存在,但是比简单地引入消息队列要好。
此外,如果并发不是特别高,则此方法的实时性和一致性仍然可以接受。
其他解决方案设置缓存过期时间每次将其放入缓存中时,请设置一个过期时间,例如5分钟。
后续操作将仅修改数据库,而不操作缓存,并等待超时后从数据库重新读取缓存。
如果一致性要求不是很高,则可以使用此解决方案。
该方案还有另一个问题,即如果非常频繁地更新数据,则不一致的问题将很严重。
在实际生产中,我们以这种方式处理了一些活动的缓存数据。
因为活动不经常更改,对于活动来说,短期的不一致并不是一个大问题。
为什么要删除而不是更新缓存?让我们首先更新数据库,然后删除缓存作为示例。
如果是更新,请先更新数据库,然后再更新缓存。
例如:如果数据库在一小时内更新了1000次,则高速缓存必须被更新1000次,但是高速缓存只能在一小时内读取一次。
是否需要1,000次更新?相反,如果是删除操作,则即使数据库已更新1000次,也只会缓存一次,并且仅在实际读取缓存时才加载数据库。
总结首先,我们必须弄清楚缓存不是更新,而是删除。
删除缓存有两种方法:首先删除缓存,然后更新数据库。
解决的办法是使用延迟双重删除。
首先更新数据库,然后删除缓存。
独奏