赞
踩
目录
3.write behind caching pattern
缓存是数据交换的缓冲区,是数据存储的临时地方,相对来说他的读写性能比较高
在web开发中缓存的引入会降低服务器的负载,提高读写效率降低响应时间
使用缓存会存在数据不一致性等问题,导致代码的维护成本变高。
如果在缓存集群的环境下,缓存的使用会消耗更多的人力资源
当客户端发送获取数据的请求时,我们先从redis中查询缓存,如果命中也就是缓存中存在数据,直接返回数据,如果缓存未命中,就需要去查询数据库然后将数据作为缓存写入redis
当数据库被修改,而客户端查询时查询到缓存里更新前的数据,为了解决这一问题有以下几种策略
内存淘汰 | 超时删除 | 主动更新 | |
说明 | 无需维护,利用redis本身的机制,当内存不足时自动淘汰部分数据,下次查询时更新缓存 | 给缓存的数据加TTL即超时时间,到期后自动删除,下次查询时更新缓存 | 在实现业务逻辑时,查询数据库的同时去更新缓存 |
一致性 | 差 | 中 | 好 |
维护成本 | 无 | 低 | 高 |
缓存调用者在操作数据库时的同时去更新缓存
将缓存与数据库作为一个整体的服务,由该服务来维护一致性。调用者只需要调用即可不需要去关心数据一致性问题
调用者只需操作缓存,由其他线程异步的去将缓存的数据持久化到数据库,,以此来保证数据的一致性
上述三种模式,方案一虽然需要开发人员自己编码但是可控性比较高。那么我们在更新数据库的时候是将缓存删除还是更新缓存呢?
如果对数据库做了上百次操作,则需要去更新上百次缓存,但是却没有请求来查询,则上百次的更新缓存相当于是无效操作。而如果删除缓存,则查询请求来的时候就会查询数据库并更新缓存。那么我们选择了删除。
此时又有一个问题,我们是先选择删除缓存后操作数据库呢,还是先操作数据库然后删除缓存呢?
先删除缓存后操作数据库,当线程1刚删除缓存时,线程2此时来查询,发现缓存没有,于是查询数据库,此时线程1还没有来得及去更新数据库,于是线程2获取到旧的数据返回并写入缓存,此时线程1更新完数据库。执行完毕时,缓存里的值是旧的,而数据库里确实跟新了的,就会存在线程安全的问题。
先操作数据库后删除缓存,假设缓存由于某种原因失效了,线程1来查询时缓存未命中于是去查询数据库数据,此时线程2再去更新数据,并将缓存删除,此时线程1执行将读取到的旧数据写入缓存,缓存值与数据库不一致存在线程安全问题。
但是后者是在假定缓存失效的情景下,相比而言前者的线程安全问题更严重
最后我们如何保证缓存与数据库操作同时成功或失败呢?
在单体系统里,我们可以将这两个操作放在一个事务里来保证,如果在分布式系统下则可以通过TCC等分布式事务来保证
如果对数据的一致性需求低,则可以使用默认的内存淘汰机制,对于一致性高的需求则使用主动更新的策略,并以超时删除作为兜底的方案
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。