Jedis
连接
- sentinel:直接连sentinel,通过sentinel获取master的地址然后封装成连接
- cluster:缓存了slot到node的映射关系,调用的时候根据映射关系获取对应的connectPool(pool在这里其实就代表对应node的连接)
Pipeline
缓存命令,然后批量(按配置默认8192)发送给服务端,节省多次请求/响应的开销。
发送和返回都会存储到对应的缓冲区。
分布式锁
分布式锁:互斥、避免死锁、我只能释放我加的锁
- 加锁:set key value(reqId) notExist setWithExpire time
- 释放锁:通过value判断,只能释放自己加的锁,避免超时出现乱释放的情况
红锁:分布式集群锁,避免单点问题,纷纷加锁,大部分加锁成功算成功
Redission:基于redis实现了一种分布式服务
- 分布式锁:用hash机构实现,key是线程名,value是重入次数
缓存时的数据一致性问题
缓存需要设置过期时间,这样能保证最终是一致的。
数据有变化时,需要对Redis和数据库同时操作,为了尽量保证数据一致,我们需要考虑以下问题
操作Redis是更新还是删除
删除Redis中的数据,毕竟最终还是以数据库为主
先操作Redis还是先操作数据库
- 先数据库后Redis:删除redis失败,redis是旧值(可以考虑失败时重新删除:比如发消息重试;监听数据库binlog)
- 先Redis后数据库:更新数据库成功,但是更新前,redis删除后,其他线程来缓存了旧值,数据还是不一致
- 先删除Redis 然后数据库 延时 再删除Redis:还是会有问题,类似上一步,再最后的删除步骤失败了,还是不一致,只不过概率会变低
热点数据发现
- redis-faina 监听redis服务端(只能单点监控)
- 抓包
缓存雪崩
大量热点key同时过期,请求量一下都打到数据库,导致数据库瞬时压力很高
解决办法:
- 过期时间加随机数
- 永不过期(数据不变化)
- 缓存预更新,后台起线程定时扫描缓存,预更新过期的缓存
缓存穿透
请求key不存在,大量请求一直请求到数据库
解决办法:
- 缓存空对象
- 布隆过滤器(引入了误判率):假如过滤器认为元素不存在,则一定不存在,认为存在,有可能不存在。布隆过滤器的数据是离线加载进去的,添加数据方便,但是删除数据很麻烦。
缓存击穿
大量请求打到一个key上,key失效时导致大量请求打到数据库
解决办法:
- 使用分布式锁,当发现缓存为空时加锁,只有第一个请求打到数据库,其余都走缓存