为什么要缓存
- 性能方面
数据库在面对读写时,不仅要保证数据可写入和可读出,还要保证事务ACID,性能在后者上面存在部分损耗,所以整体的读写流量都会不可能做到很高。 - 业务方面
业务接口中,某些要求快速响应,访问数据库达不到这样的标准,所以需要引入缓存来缩短响应时间。
缓存存在什么问题
缓存和数据库的一致性如何保证,但结论很明显,只能保证最终一致性,保证不了实时一致性,如果需要保证实时一致性,那还不如直接读取数据库,还省得搞一层缓存,麻烦的不行。
保证缓存一致性的几种level
1.由redis过期时间保证
表现:redis设置过期时间,这段时间内数据库更新都不更新redis,等redis过期了,再从数据库读一下,然后再更新。
更新方式:先读缓存,没有的话读数据库,然后将数据更新到缓存,再返回。
更新的情况下,是先更新数据库,然后删除缓存,等待下一次查询再刷新缓存。
结论:虽然一致性很差,但是,这种方式一般也是业务最常用的缓存方式,大部分业务场景面对时延性并不敏感,这种方式可以接受。
2.同步更新redis和数据库
表现:更新数据库时,也把更新操作应用到缓存中。
更新方式:
- 底层服务A同时连接数据库和缓存,更新时,同步更新。但是会造成底层服务A的连接资源占用过多。
- 底层服务A只连接数据库,缓存通过mq更新,但是mq不保证消费有序性,所以可能存在数据库和缓存更新指令顺序不一致,导致的数据不一致。
结论:两种方式的工作量都不小,且都有缺点。
3. 最常见的保证一致性方式-先更新数据库,然后删除缓存
正常思路是更新数据库,然后删除缓存,由下一次读取来刷新缓存。但是为什么不再更新后,就进行缓存的更新呢?
- 缓存的数据不一样只是简单的set和get,可能还需要加工,然后再set。在不知道缓存是否为热点的情况下,总是消耗cpu进行加工,不是一个明智的选择。
- 缓存是在内存中,内存是有限的,总是往里塞数据,容易造成容量不够用。
但是当删除操作失败的时候,只能等到缓存过期后的再次刷新来获取新数据,这样子不一致情况的时间会比较长。当删除失败时,可以将删除操作写入到消息队列中进行重试,来保证一定能把脏缓存删除掉。
4. 监听binlog
最牛逼的,自己监听binlog构建缓存,一致性杠杠的。
但是,工作量也杠杠的。