缓存技术
缓存加载时机:
1、启动时全量加载=》全局有效,使用简单
2、懒加载
(1)、同步使用加载:
-先看缓存中是否有数据,没有的话从数据库中读取
-读取数据,先放到内存,然后返回给调用方
(2)、延迟异步加载
-从缓存获取数据,不管是否为空直接返回
-策略1(异步)如果为空,则发起一个异步加载的线程,负责加载数据
-策略2(解耦)异步线程负责维护缓存的数据,定期过根据条件触发更新
缓存的有效性与数据同步
一般来说变动频率打、一致性要求搞的数据,不适合用缓存。
如何评价缓存的有效性:
(1)、读写比:对数据的写操作导致数据变动,意味着维护成本。
(2)、命中率:命中缓存意味着缓存数据被使用,意味着有价值。
本地缓存
1、MyBatis缓存
一级缓存:session
二级缓存:sessionFactory级别
2、 Guava Cache
可配置缓存大小、超时策略、弱引用(当没有被引用,则清除该缓存信息),还可以显式清除,统计信息、移除事件监听。
3、spring Cache
(1)基于注解和aop,使用非常方便
(2)可以配置Condition和SPEL,非常灵活
(3)需要注意:绕过Srping的话,注解无效
核心功能@Chcheable、@CachePut、@CacheEvict
远程缓存
本地缓存的缺点:
(1)多个集群环境同步?当集群规模增大,缓存的读写放大。
(2)再JVM中长期占用内存?如果是堆内存,总会影响GC。
(3)缓存数据的调度处理,影响执行业务的线程,抢资源。
缓存策略
1、容量:缓存数据容量是必须要考虑的问题,
2、过期策略:按FIFO或LRU(最近最少使用)、按固定时间过期、按业务时间加权
缓存常见的问题
缓存穿透
问题:大量并发查询不存在的KEY,导致都直接将压力透传到数据库
分析:为什么会多次透传?不存在一直为空。
需要注意让缓存能够区分KEY不存在和查询到一个空值
解决方法:
1、缓存空值的KEY,这样第一次不存在也会被加载会记录,下次拿到有这个KEY
2、Bloom过滤器或RoaringBitmap判断KEY是否存在
3、完全已缓存为准,使用延迟异步加载的策略2,这样就不会触发更新
缓存击穿
问题:某个KEY失效的时候,正好有大量并发请求访问这个KEY
分析:当一个KEY失效的时候,刚好有并发的访问,那么并发线程都会去数据库中查找这个key。
解决方法:
1、KEY的更新操作添加全局互斥锁,就是说key的更新只能有一个线程来操作
2、完全以缓存为主,使用延迟异步加载的策略2,这样就不会触发更新
缓存雪崩
问题:当某一时刻发生大规模的缓存失效情况,会有大量的请求进来直接打到数据库,导致数据库压力过大导致宕机
分析:一般来说,由于更新策略、或者数据热点、缓存服务宕机等原因,可能会导致缓存数据通过个时间点大规模不可用,或者都更新。所以,需要我们的更新策略要在时间上合适,数据均匀分散,缓存服务器要多台高可用。
解决方法:
1、更新策略再时间上做到比较均匀
2、使用的热数据尽量分散到不同的机器上
3、多台机器做主从复制或多副本,实现高可用
4、实现熔断限流机制,对系统进行负载能力控制
redis
1、redis性能测试:redis-benchmark -n 次数-c 连接数
redis5种数据结构
1、字符串(在redis中是二进制安全的)
set/get/getset/del/exists/append
incr(+1)/decr(-1)/incrby/decrby
注意:
- 字符串append会占用多余内存
- 整数共享:如果能使用整数,就尽量使用整数,限制了redis内存+LRU
- 整数精度问题:redis大概能保证16位整数,超过16为可能会丢失精度
2、hash
hset/hget/hmset/hmget/hgetall/hdel/hincrby
hexists/hlen/hkeys/hvals
3、list(按插入顺序排序的链表,如果链表中的元素均被移除,那么该键也会被移除)
lpush/rpush/lrange/lpop/rpop
4、set set类型是没有排序的字符集合,与list相比set集合汇总不允许出现重复的元素
sadd/srem/smembers/sismember
sdiff(集合求差集)/sinter(求交集)/sunion(求并集)
5、sorted set (和set相似,sortedset中每一个成员都会有一个分数与之关联,redis通过分数来为集合的成员进行从小到大的排序)
zadd key score member
redis用法
1、通用数据缓存,实时数据,会话缓存
2、业务数据去重:订单处理的幂等校验、业务数据排序
3、全局流控计数,
4、统计计数:id去重,记录访问ip、UV,PV等访问量
5、发布订阅:subscribe key(订阅key)、publish key value (发布消息)
6、分布式锁:
- 获取锁:set dlock my_random_value NX(是否存在) PX(超时) 30000
- 释放锁:if redis.call(“get”,KEYS[1])==ARGV[1] then
return redis.call(“del”,KEYS[1])
else
return 0
end
关键点:原子性、互斥、超时
redis客户端
jedis
类似jdbc,redis的命令包装
基于bio,线程不安全,需要配置连接池管理连接
lettuce
基于nio,目前主流的驱动
redission
加入大量丰富的分布式功能特性,比如juc的线程安全集合和工具的分布式版泵,分布式的基本数据类型和锁
spring data redis
redis事务
开启事务:multi
命令入队
执行事务:exec
撤销事务:discard
redis高可用
redis主从备份
主从切换
可以做到监控主从节点的在线状态,并做切换
两种启动方式:
redis-sentinel sentinel.conf
redis-server redis.conf --sentinel
sentinel.conf配置
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-millisecond mymaster 60000 --心跳检测
sentinel failover-timeout mymaster 180000 --重连时间
sentinel parallel-syncs mymaster 1 --当从库从主库读取数据时会暂停访问,这个配置是现在每次只能有一个从库读取数据,以保证还有从库可用
redission
特点:大量丰富的分布式功能特性,比如:JUC的线程安全集合和工具的分布式版本,分布式的基本数据类型和锁