[一]主从集群的缺点,客户端分片的缺点
(1)主从+哨兵的redis集群,只是做主从备份,数据冗余的一种处理。但在存储空间的扩展上还是有限制。因为集群中的节点都是存储同样的数据。单一节点的容量,就可以决定整个集群存储数据的容量。木桶效应。
(2)客户端规划的分片(就是将不同的键存储在不同的节点上),包括客户端预分片技术,解决了存储容量的不受单台最小存储节点的限制,但在集群节点新加入和节点下线上,就会造成数据的命中率不高,需要人工手动重新规划,数据转移。
[二]redis3.0版本支持集群(包括存储容量水平扩展,新节点加入或下线的问题解决。)
(1)redis的Cluster,拥有和单机实例同样的性能
(2)在网络分区后能够提供一定的可访问性以及对主数据库故障恢复的支持
(3)例外集群几乎支持所有的单机实例支持的命令,对于涉及多键的命令(mget),如果每个键都位于同一个节点,则可以正常支持,否则报错。
(4)除此之外集群还有一个限制,是只能使用默认的0号数据库,如果使用select命令切换数据库,就会提示错误。
[三]使用3.0的redis的原因
(1)很好支持分片和存储容量的扩容
(2)哨兵和集群是两个独立的功能,单从特性上来看哨兵可以视为集群的子集,当不需要数据分片,或者已经在客户端进行分片的场景下,哨兵使用就足够了,单如果需要进行水平(存储容量扩容和数据分片)扩容,则集群是一个非常好的选择。
[四]redis3.0以上cluster集群的节点的增加
(1)redis-trib.rb是使用CLUSTER MEET命令来使每个节点认识集群中的其他节点的,可想而知如果想要向集群中加入新节点,也需要使用CLUSTER MEET命令实现。
(2)使用命令:CLUSTER MEET ip port
--->集群中加入新节点A。
--->向新节点发送:“CLUSTER MEET ip port”命令,ip和port是集群中任意一个节点的地址和端口号,A接收到客户端发来的命令后,会与该地址和端口号的节点B进行握手,使B将A认作当前集群中的一员。当B与A握手成功后,B会使用Gossip协议将节点A的信息通知给集群中的每一个节点。通过这一方式,即使集群中有多个节点,也只需要选择MEET其中任意一个节点,即可使新节点最终加入整个集群。
[五]什么是插槽?
(1)插槽的计算,将每个键的键名的有效部分使用CRC16算法计算出散列值,然后对16384取余数。这样使得每个键都可以分配到16384个插槽中
(2)键名的有效部分:
--->如果键名包含{符号,且在{符号后面存在}符号。并且{和}之间有至少一个字符,则有效部分是指{和}之间的内容
--->如果不满足上一条规则,那么整个键名是有效部分。
比如:{user102}:last.name的键名有效部分是:user102 shangxiaofei键名的有效部分是:shangxiaofei
[五]如何将插槽分配给指定的节点。插槽的分配分为如下几种情况。
(1)插槽之前没有被分配过,现在想分配给指定节点。链接上指定节点的服务器,输入分配插槽的命令。
--->命令:CLUSTER ADDSLOTS slot1 slot2.... [slotn]
--->redis-trib.rb也是通过该命令在创建集群时为新节点分配操作的。如果插槽已经被分配给某个节点,则会提示(error) err solts 100 is already busy
(2)插槽之前被分配过,现在想移动到指定的节点。
--->利用命令查看插槽的分配情况.CLUSTER SLOTS。
==>查看插槽的分配情况
==>利用redis-trib.rb进行插槽移动
==>查看插槽的移动结果
(3)手动再将0号插槽从6380节点移动回6379节点
--->插槽中没有任何键的移动命令:CLUSTRE SETSLOT 插槽号 NODE 新节点的运行id.
--->该命令的迁移的前提是插槽中没有任何键,因为CLUSTER SETSLOT命令迁移插槽时并不会连同相应的键一起迁移。这就造成了客户端在指定节点无法找到未迁移的键,
(4)将有键存在的插槽,从一个节点,移动到另一个节点,并将插槽中的键一并移动过去
--->手工获取某个插槽存在那些键:CLUSTER GETKEYSINSLOT 插槽号 要返回的键的数量
--->之后对每个键,使用MIGRATE命令将其迁移到目标节点:MIGRATE 目标节点的地址 目标节点端口 键名 数据库号码 超时时间 [COPY][REPLACE]
--->其中COPY选项,不将键从当前数据库删除,只是复制一份副本发往目标数据库。
--->其中REPLACE选项,如果目标存在同名键,则覆盖
三:如果实现redis不下线的情况迁移数据
(1)两条命令
--->CLUSTER SETSLOT 插槽号 MIGRATING 新节点的运行id
--->CLUSTER SETSLOT 插槽号 IMPORTING 原节点的运行ID
(2)假设把0号插槽从A迁移到B
--->在B执行:CLUSTER SETSLOT 0 IMPORTING A
--->在A执行:CLUSTER SETSLOT 0 MIGRATING B
--->执行CLUSTER GETKEYSINSLOT 0 获取零号插槽的键列表
--->对第三步获取的每个键执行MIGRATE命令,将其从A迁移到B
--->执行CLUSTRE SETSLOT 0 NODE B来完成迁移。
&&:注意:在迁移过程中,如果访问A节点,如果键尚未迁移,则正常处理,如果已经完成迁移,则返回一个ask跳转请求,告诉客户端这个键在B。避免键在迁移过程中出现临时丢失的现象。
四:获取与插槽对应的节点。
五:故障恢复
(1)在一个集群中每个节点都会定期向其他节点发送ping命令。并通过有没有收到回复来判断目标节点是否已经下线。
(2)每隔1秒随机选择5个节点,然后选择其中最久没有响应的节点发送ping命令。
(3)故障恢复和哨兵机制类似。
--->一旦节点a认为节点b疑似下线,就会在集群中传播该消息,所有其他节点收到消息后都会记录该信息。
--->当其群中某一节点c收集到半数以上的节点认为b疑似下线,就会将b标记为下线,并向集群中的其他节点传播该消息,从而使得b在整个集群中下线。若下线节点为主节点,则从对应的从节点列表中选举一个从节点升级成新主节点。选举算法:和哨兵中的选举领头哨兵算法一致,基于raft算法。当选举出新的主节点,则执行SLAVEOF ON ONE将自己升格为主数据库。
--->如果一个至少负责一个插槽的主数据库下线,且没有相应的从数据库可以进行故障恢复,则整个集群默认会进入下线状态无法工作。如果想在这种情况下,使集群仍能正常工作,可以修改配置cluster-require-full-coverage为no(默认值为yes)