1. 解决的问题:
- 容量不够
- 并发写操作
2. 集群:
- Redis集群实现了对Redis的水平扩容,即启动了N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数据的1/N
- Redis集群通过分区(partition)来提供一定程度的可用性(availability):即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求。
2.1 设置集群
此处省略6个redis的集群配置。
可查看:https://blog.csdn.net/qq_42815754/article/details/82912130
设置redis-trib后可以看到,redis自动给我们设置了3主3从的配置。
3. 在集群中设置k-v:
我们设置了集群后,只需要登录到其中的一个客户端。
登录到6379,设置一个值,可以看到k设置的插槽是12706,这个k-v被存放到6381这个服务器上去了。
当我们想要访问这个值的时候,值在哪个服务器就会切换到对应的服务器,这个过程不需要我们去处理,我们只管访问数据就行了。
3.1 如何强行设置两个键值到一个插槽:
例:aa和aaa都在组user中:
4. redis cluster如何分配这六个节点:
5. 插槽slot:
5.1 为什么是16384个槽
集群中的各节点在握手成功后,两个节点之间会定期发送ping/pong消息,交换数据信息,在redis节点发送心跳包时需要把所有的槽信息放到这个心跳包里,以便让节点知道当前集群信息,在发送心跳包时使用char进行bitmap压缩后是2k(16384÷8÷1024=2kb),也就是说使用2k的空间创建了16k的槽数。
虽然使用CRC16算法最多可以分配65535(2^16-1)个槽位,65535=65k,压缩后就是8k(8 * 8 (8 bit) * 1024(1k) = 8K),也就是说需要8k的心跳包,作者认为这样做不太值得;并且一般情况下一个redis集群不会有超过1000个master节点,所以16k的槽位是个比较合适的选择。
如果槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于庞大。redis的集群主节点数量基本不可能超过1000个。集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者,不建议redis cluster节点数量超过1000个。槽位越小,节点少的情况下,压缩率高,Redis主节点的配置信息中,它所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中,会对bitmap进行压缩,但是如果bitmap的填充率slots / N很高的话(N表示节点数),bitmap的压缩率就很低。如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。
6. 查询集群中的值:
7. 故障恢复:
- 如果主节点下线?从节点能否自动升为主节点?
答案:从节点会自动升为主主节点
关闭6381,查看集群节点信息:cluster nodes
- 主节点恢复后,主从关系如何?
答案:原来的主节点会变成从节点
恢复6381,查看集群节点信息
- 如果某一端插槽内的主从节点都当掉,redis服务是否还能继续?
答案:那么那个地方的插槽就不能用了
关闭6381和6391,
尝试获取宕机redis中的内容:
8. 设置所有slot都正常时才能对外提供服务:
9. 集群中节点是如何通信的?
在 redis cluster 架构下,每个 redis 要放开两个端口号,比如一个是 6379,另外一个就是 加1w 的端口号,比如 16379。
16379 端口号是用来进行节点间通信的,也就是 cluster bus 的东西,cluster bus 的通信,用来进行故障检测、配置更新、故障转移授权。cluster bus 用了另外一种二进制的协议,gossip 协议,用于节点间进行高效的数据交换,占用更少的网络带宽和处理时间。
10. 为什么redis不使用一致性hash而用slot槽
9.1 slot槽:
使用哈希槽进行扩缩容就会很方便,如果我们想要新添加个节点D, 我们只需要从之前的节点分部分哈希槽到节点D上。 如果我想移除某个节点,只需要将该节点中的哈希槽移到另外两个节点上,然后将该节点从集群中移除即可。从一个节点将哈希槽移动到另一个节点并不会停止服务(渐进式rehash),所以无论添加或是删除节点都不会造成集群的不可用,这样就实现了动态扩缩容。
9.2 一致性hash
一致性哈希用于解决分布式缓存系统中的数据选择节点存储问题和数据选择节点读取问题以及在增删节点后减少数据缓存的消失范畴,防止雪崩的发生。它是一个0到2的32次方的闭合环型结构,占用4个字节,拥有2的32次方个桶空间,每个桶空间可以存储很多数据。
一致性哈希是采用的是如下步骤:
- 对节点进行hash,通常使用其节点的ip或者是具有唯一标示的数据进行hash(ip),将其值分布在这个闭合圆上。
- 将存储的key进行hash(key),然后将其值要分布在这个闭合圆上。
- 从hash(key)在圆上映射的位置开始顺时针方向找到的一个节点即为存储key的节点。如果到圆上的0处都未找到节点,那么0位置后的顺时针方向的第一个节点就是key的存储节点。
- 添加节点:如果在节点A和节点C中间增加一个节点D,那么在节点A和节点C之间的部分数据要存储的节点就会有所变化,在节点C到节点D之间的数据会从节点A转移到节点D。
- 删除节点:如果删除一个节点,就会把当前节点所有数据加到它的下一个节点上。这样会导致下一个节点使用率暴增,可能会导致挂掉,如果下一个节点挂掉,下下个节点将会承受更大的压力,最终导致集群雪崩。
- 节点太少:可能会造成数据倾斜,假设只有俩节点,可能会造成大量数据存放在node A节点上,而node B节点存储很少的数据。
9.3 对比:
- 一致性哈希的节点分布基于圆环,无法很好的手动设置数据分布,比如有些节点的硬件差,希望少存一点数据,这种很难操作。而哈希槽可以很灵活的配置每个节点占用哈希槽的数量
- 一致性哈希的某个节点宕机或者掉线后,当该机器上原本缓存的数据被请求时,会从数据源重新获取数据,并将数据添加到失效机器后面的机器,这个过程被称为 “缓存抖动” ,而使用哈希槽的节点宕机,会导致一定范围内的槽不可用,只能通过主从复制加哨兵模式保证高可用。
- 真是基于一致性哈希的特点,当某台机器宕机时,极易引起雪崩,如上述介绍中删除节点。
- Redis Cluster的槽位空间是可以用户手动自定义分配的,类似于 windows 盘分区的概念,可以手动控制大小。
- 相对于哈希槽,一致性哈希算法更复杂
11. 什么是redis集群脑裂问题?
Redis的集群脑裂指在主从集群中,同时有两个master主节点,它们都能接收写请求。而脑裂最直接的影响,就是客户端不知道应该往哪个master主节点写入数据,结果就是不同的客户端会往不同的主节点上写入数据。此时Redis的集群脑裂就有可能会导致数据丢失。
11.1 为什么会发生脑裂?
- 网络问题:导致Redis Master节点跟Redis Slave节点和哨兵Sentinel集群处于不同的网络分区,此时因为Sentinel集群无法感知到master的存在,所以将Slave节点提升为Master节点。此时就存在两个不同的Master节点,就像一个大脑分裂成了两个。
- 主机资源问题:redis Master节点所在的服务器上的其他程序临时占用了大量资源(例如 CPU 资源),导致主库资源使用受限,短时间内无法响应心跳,于是Sentinel集群重新选举了新的Master,当其它程序不再使用资源时,旧Master节点又恢复正常,同一集群下出现两个Master。
- Redis 主节点阻塞:主库自身遇到了阻塞的情况,例如,处理 bigkey 或是发生内存 swap,短时间内无法响应心跳,还是会触发Sentinel机制,等主库阻塞解除后,又恢复正常的请求处理了。
11.2 解决:
在redis的配置文件中有两个参数我们可以设置:
min-slaves-to-write N
min-slaves-max-lag N
-
min-slaves-to-write默认配置为0,这个配置表示master至少有N个slave节点才进行工作。当出现Redis集群脑裂时,其中一个出问题的master此时就少于N的slave连接,此master就拒绝写请求。
-
min-slaves-max-lag默认配置为10,这个配置表示slave和master之间只能落后N ms的数据。超过了该值就拒绝写请求,就不会往master中写入数据。
服务降级解决master拒绝写请求问题,但是那些写请求可以写到Mysql中,再把数据从MySQL加载出来,写到正常的mater去。