缓存能想到什么?
- 想到redis memcached 选型
- 想到redis 分布式锁(和zk分布式锁的区别)
- 想到ehcache | Guava Cache | Caffeine
- 想到spring 的 @cacheable 不能自定义过期时间
如果去面试的哈,面试官关心这些
- redis为啥这么快?
- hash槽,
- 一致性hash,
- redis的2种持久化的区别
- 哨兵,主从,集群的区别
- … 等等非常奇奇怪怪的东西
why
目前服务器瓶颈在哪里?
- cpu性能剩余,
- 内存也越来越大,
- 网络?局域网不是问题,距离远一点,加上光纤也问题不大
瓶颈几乎集中在io上,具体到咱们日常写的项目,就是在数据库上,数据库的读写磁盘要求很高,虽然用了各种手段提高磁盘速度,做raid、用裸设备、现在上ssd,但是面对要求越来越高的并发,这些远远不够,so 需要缓存来保护dba的微笑
what
- 本地缓存:
- 同一个进程内部,没有网络开销等,在单应用不需要集群支持或者集群情况下各节点无需互相通知的场景下使用本地缓存较合适;
- 缺点也是应为缓存跟应用程序耦合,多个应用程序无法直接的共享缓存,各应用或集群的各节点都需要维护自己的单独缓存,对内存是一种浪费。
- 成员变量或局部变量实现
- 静态变量实现(配置文件,开始就加载)
- java.util.ConcurrentMap
- Ehcache
- Guava Cache
- Caffeine Cache
- OSCache、cache4j、ShiftOne、WhirlyCache等等登
- 分布式缓存:指的是与应用分离的缓存组件或服务,其最大的优点是自身就是一个独立的应用,与本地应用隔离,多个应用可直接的共享缓存。
- Redis
- memcached
how
咱们现在一般标配的
- redis+Spring cacheable
- Lettuce (spring2.*默认,之前的用的jedis)
- Jedis
- Redisson
问题在于 - @cacheable不能自定义过期时间
- redis也有瓶颈,也不能玩命的用
- redis还是有网络开销的
上个月检视了数据库连接池配置,发现不少开发人员没有注意到spring默认连接池这一块发生的变更,估计redis链接这一块,也存在差不多的问题,配置可能有问题
为什么缓存都不被善待
so 推荐 推荐
DB + JetCache( Redis + Caffeine Cache)
Caffeine Cache被spring默认采用,换掉了Guava Cache
JetCache 满足大部分
Guava使用jdk的Queue记录缓存的写读情况,导致OOM;
而Caffeine使用Disruptor的RingBuffer数据结构记录
Caffeine 基于LRU算法实现,支持多种缓存过期策略
清空策略
FIFO(first in first out)
先进先出策略,最先进入缓存的数据在缓存空间不够的情况下(超出最大元素限制)会被优先被清除掉,以腾出新的空间接受新的数据。策略算法主要比较缓存元素的创建时间。在数据实效性要求场景下可选择该类策略,优先保障最新数据可用。
LFU(less frequently used)
最少使用策略,无论是否过期,根据元素的被使用次数判断,清除使用次数较少的元素释放空间。策略算法主要比较元素的hitCount(命中次数)。在保证高频数据有效性场景下,可选择这类策略。
LRU(least recently used)
最近最少使用策略,无论是否过期,根据元素最后一次被使用的时间戳,清除最远使用时间戳的元素释放空间。策略算法主要比较元素最近一次被get使用时间。在热点数据场景下较适用,优先保证热点数据的有效性。
除此之外,还有一些简单策略比如:
根据过期时间判断,清理过期时间最长的元素;
根据过期时间判断,清理最近要过期的元素;
随机清理;
根据关键字(或元素内容)长短清理等。
数据库和缓存修改策略
- 先删缓存,再更新数据库
- 先更新数据库,再删缓存
不讨论更新的情况,跟新=删除+添加
- 先删除缓存,第二个服务进来,在db执行结束之前刷起来缓存,导致在一个ttl时间内,数据和db不一致
- 先跟新数据库,后删缓存,1个服务进来,先后修改数据库,就算刷起了一个新的缓存,存活时间也非常断,除非缓存写的时候,删除瞬间执行,这种可能性不大
问题
redis是数据更集中,还是更分散?
@CacheEvict 默认先删还是后删?