Redis各种点杂记
整理不易,转载请注明: https://blog.csdn.net/zhangjingao/article/details/117601983
一致性哈希算法
一致性哈希算法将空间分为一个环形空间,在环形空间里,每台机器结点被分布在环上不同的点,当key值被计算到某个点后,会顺时针寻找一个结点,数据会被保存在那里。当一个机器宕机了或者新添加了一个机器,也只会影响就近的一部分key,不会影响后面所有的key,这样尽可能的减少了删除或者新增机器对结点rehash带来的影响。这个特点解决了单调性和负载均衡的特性。
如果节点少,那么就存在两个问题:
1、存在数据倾斜问题。将节点hash后放在环上,如果hash的结果不够均匀,那么就会存在数据倾斜问题。比如:有两个节点,hash后的值分别是
2、存在缓存雪崩问题,如果节点中有一个节点被删除了,那么会有大量的key失效,那么就会有雪崩的问题。
为了解决上面的问题,一致性哈希算法引入了虚拟节点的概念,将一个真实的节点分为很多个虚拟节点,将虚拟节点放在环上,那么在新增或删除节点时,受影响的点会大幅降低。
如下图:v100和v101都是节点1的虚拟节点,v200和v201是节点2的虚拟节点,v300和v301是节点3的虚拟节点。此时如果删除节点1,那么相应的v100和v101就会消失,那么受影响的数据只有k1映射到v301上,k4映射到v200上。
一致性哈希算法给每个机器结点虚拟出来了很多个虚拟结点,均匀的分布在环上,这样解决了平衡性,不会导致某个结点缓存过多key,而某些结点缓存过少key这样不平衡的情况。
注意:真实的节点并不会放在哈希环上,只放虚拟节点。
哈希槽算法(当前使用的)
当前redis集群使用的算法是哈希槽算法,并不是一致性哈希算法。
哈希槽算法不在是一个环,是一个线性区间。一共有16384(2^14=281024)个槽位,在集群创建时,每个master节点负责哪些槽就已经分配好了,在之后新增和删除节点时,做的只是槽位的迁移。
放一张经典的key、槽、节点、集群的关系图。
维护槽和节点关系的是一个数组结构,key是槽下标,value是节点对象。这样就可以很快根据槽找到对应的处理的节点。
性能优化
压测命令:./redis-benchmark -h 127.0.0.1,我的电脑上get和set100000条数据使用了133s
redis内存有限,跟电脑有关,64G或者128G
内存有限,可使用分库分表来增加内存,对不同的key取模进行分服务器存储
读多写少的情况下,使用读写分离来实现速度的优化
RESP协议
Redis的java客户端jedis与redis进行通信的通信协议。基于TCP应用层协议。
缓存穿透
原因:客户端多次查询一个不存在的key,导致每次都在缓存中查询不到,从而每次都到达数据库中查询。
解决方案
缓存空key
redis缓存这个不存在的key,值设置为null,当在数据库中查询不到的时候,redis一样缓存这个不存在的key,设置过期时间。
使用BloomFilter。
BloomFilter是一个可以判断这个key是否存在的组件,可以加载缓存之前,如果在bloomfilter中判断key不存在,直接返回null,如果存在就查缓存再查db。
两种方案对比
当客户端可能经常使用重复率高的不存在的key查询,我们可以使用第一种方案,
当客户端使用的不存在的key重复率低,那么使用第二种方案。
缓存击穿
原因:当多个线程同时请求一个key,但是这时key恰好失效了,这就导致一瞬间很多个请求同时请求数据库,数据库压力剧增。
解决方案
当有多个线程请求数据库时,就用互斥锁锁住请求,当第一个线程请求到了数据,那么可以将数据存进缓存,那么其他线程就可以直接使用缓存了。
缓存雪崩
原因:指某一时刻大量数据同时失效,例如当缓存服务突然宕机了,那么所有的请求都会直接请求到数据库,数据库可能承受不住。
解决方案
事前
使用集群缓存,保证缓存服务的高可用,在redis中,可以使用主从+哨兵,redis cluster来避免redis全盘崩盘的情况。
事中
ehcache本地缓存 + Hystrix限流&降级,避免MySQL被打死
事后
开启redis持久化机制,恢复内存中的数据。
热点数据失效
原因:我们在设置缓存时,经常会设置过期时间,当多个热点数据同时过期时,可能会出现很多个请求同时到达数据库,导致数据库压力增加。
解决方案
设置不同的失效时间
给不同的热点数据设置不同的失效时间,失效时间可以是某一个确定的时间+一个不确定的在一个小范围内波动的随机值。
互斥锁
和缓存击穿的方案类似,给请求的线程加锁,当第一个线程在数据库中请求到数据库,请求相同数据的线程就不会再到数据库中,但这样的方案会降低系统吞吐量。结合情况使用。
持久化
持久化有两种方式:RDB和AOF
RDB
原理:redis调用fork线程,子线程会把数据更改写到rdb文件中,覆盖旧文件,是一种快照形式的持久化方式
优点
1、rdb会配置时间点,在达到时间点时更改量到达要求的数据时就会开始持久化,比如save 60 100,在60s内更改量达到了100就进行备份,可以有多个时间点配置
2、采用子线程备份,不用影响主线程的继续服务
3、在数据量大的情况下,RDB相比AOF更快能启动
缺点
1、设置的时间点过长,可能导致redis宕机等时候在上次时间点至宕机时候数据未恢复
AOF
原理:比较可靠,当redis数据被修改时,就会把命令添加到aof文件中,当redis重启时,就会把aof文件重新执行一遍