标签:大数据 学习 秒杀系统 步骤 阅读 iss 业务 操作 根据
缓存操作读缓存可以分为两种情况命中(cache hit)和未命中(cache miss):
读缓存的的处理由缓存中有没有数据? 决定,如果缓存中有数据那就是缓存命中,如果没有那就是缓存未命中:
写缓存可以分为更新缓存和删除缓存。
更新缓存时需要分两种情况:
删除缓存也称为淘汰缓存,删除缓存的操作非常简单的,直接将缓存从缓存库中的删除就可以了。
缓存一般都是配合数据库一起使用,从数据库中获取数据然后再更新缓存。为什么要讨论缓存操作的顺序呢?因为在有些情况下不同的操作顺序会产生不一样的结果,常见的操作顺序可以分为:
如上图先将数据写入数据库,然后再去更新或删除缓存。两个步骤1、2都可能失败,如果是第一步失败可以通过抛出业务异常,业务调用方捕获异常信息进行处理,因为这个时候并没有操作缓存可以理解为写数据库失败了。
如果是第一步成功(写数据库成功),然后再操作缓存的时候失败,这里有两种情况:
String name = "arch-digest";
现在要将name的值更新成juejin,按照先数据库后缓存的顺序:
//将name的值更新为juejin
public void update(String name){
db.insert(...); //更新数据库
cache.delete(name); //更新缓存
}
正常情况下db.insert(...)和cache.delete(name)都执行成功没有异议。如果是一些其他原因cache.delete(name)执行失败,那数据库中的值是更新后的值juejin,而缓存中的数据还是arch-digest这样在下次读取缓存的时候拿到的值就是arch-digest。
public String getNameFromCache(String name){
String value = cache.get(name); //从缓存中获取数据
...
return value;
}
读取缓存的时候在getNameFromCache方法中,如果name缓存没有过期那会一直拿到arch-digest,这样情况就会导致用户看到的数据不一致。
先缓存后数据库和之前说到的先数据库后缓存差不多除了会可能导致数据不一致外,还会有并发问题。
如上面现在是更新数据,如果是在更新数据库的时候失败会发生什么呢?这里要根据缓存的操作分两种情况:
删除缓存:删除缓存中的数据,下次读取时从数据库中获取(数据一致)。
更新缓存和删除缓存操作上面已经介绍过了,不多做解释了。很明显关于更新缓存和删除缓存在这种情况先删除缓存更合适,没有数据不一致的问题,但是在使用删除缓存时也要注意会引发并发问题:
这里说的是优化方案不是解决方案哦,因为在分布式环境下事务是个难题,现在也没有好的解决方案。只能找到最适合业务的优化方案,使数据不一致的可能性或延迟降到一个业务可接受的范围内。
常见的几种优化方案可以包括:
不处理是最简单的方式了,即数据库与缓存中的数据不一致时在业务允许的情况下不做处理。虽然有点不合适,但是很香!
延时双删可以用来优化在先缓存后数据库中的并发问题:
针对上面的情形,应该自行评估自己的项目的读数据业务逻辑的耗时。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上,加几百ms即可。这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。
第二次删除作为异步的。自己起一个线程,异步删除。这样,写的请求就不用沉睡一段时间后了,再返回。这么做,加大吞吐量。
使用binlog订阅,这样一旦MySQL中产生了新的写入、更新、删除等操作,就可以把binlog相关的消息推送至Redis,Redis再根据binlog中的记录,对Redis进行更新。
其实这种机制,很类似MySQL的主从备份机制,因为MySQL的主备也是通过binlog来实现的数据一致性。
这里可以结合使用canal(阿里的一款开源框架),通过该框架可以对MySQL的binlog进行订阅,而canal正是模仿了mysql的slave数据库的备份请求,使得Redis的数据更新达到了相同的效果。
当然,这里的消息推送工具你也可以采用别的第三方:kafka、rabbitMQ等来实现推送更新缓存。
-END-
架构文摘
ArchDigest
架构知识丨大型网站丨大数据丨机器学习
如有收获,点个在看,诚挚感谢图片
标签:大数据 学习 秒杀系统 步骤 阅读 iss 业务 操作 根据
原文地址:https://blog.51cto.com/15054050/2563634