Redis Cluster是redis3.0后正式推出的分布式解决方案。node
以前介绍了复制和哨兵,解决了高可用问题,经过复制,读操做能够分发到多个节点(读实现了负载均衡),可是写操做依然只有一个节点,没法实现写操做的负载均衡,可是依然面临单机内存和并发的瓶颈。redis
集群就是用来解决写操做负载均衡的问题。其核心有两个做用shell
常见哈希分区主要两种:数据库
N为节点的数量。这种方案优势是简单,缺点是当有节点数量变化(扩容or缩容),数据节点映射关系须要从新计算,会致使数据从新迁移。并发
通常用于节点能够预估不变的场景,好比数据库分表分库,好比订单库能够分64个,orderId mod 64可获得这个订单数据应该写入那个库。负载均衡
实现思路是为系统中的每个节点分配一个token,范围通常为0~2的32次方,这个这些token构成一个哈希环。分布式
当有数据写入时,先根据key计算出哈希值X,而后顺时针寻找到第一个大于X的token的节点,而后把值存入该节点便可。下图中:函数
一致性哈希分区中,若是增长或者减小节点,只影响节点改节点相邻的节点,其余节点毫无影响,好比在node1以前增长一个节点,只会使得原来存储到node1的数据一部分数据(好比A)转移到新节点,其余节点毫无影响。3d
一致性哈希的最大问题是,当节点比较少时,新增或者删除节点会致使数据的分配严重不均衡。 在上图中,若是删除node1和node2:code
虚拟槽分区是对一致性哈希的改进,用来解决负载均衡的问题。
Redis Cluster采用虚拟槽分区,槽是介于实际节点和数据之间的虚拟概念,每一个节点对应必定范围的槽,每一个槽包含必定范围内的哈希值,使用了虚拟槽分区后,数据的映射关系从hash-》节点变成了hash-》槽-》节点。
Redis Cluster槽的范围是16384(016383)。全部键基于哈希函数映射到016383整数槽内(CRC取模),计算公式:
示意图以下:
使用虚拟槽分区后,节点的变更对系统影响较小,好比上图中,删除node1,只须要对0-3276的槽从新分配便可。
搭建一个三主三从的集群,在同一台机器上,由端口号进行区分。
7000节点配置以下:
#端口号 port 7000 #开启集群模式 cluster-enabled yes #节点超时时间(毫秒) cluster-node-timeout 15000 #集群内部配置文件 cluster-config-file "nodes-7000.conf" logfile "log-7000.log" protected-mode no daemonize yes
依次配置7001,7002,8000,8001,8002。
启动6个节点:
src/redis-server redis-7000.conf src/redis-server redis-7001.conf src/redis-server redis-7002.conf src/redis-server redis-8000.conf src/redis-server redis-8001.conf src/redis-server redis-8002.conf
配置相关说明
上面的配置中cluster-enabled 和cluster-config-file是集群相关的配置。
cluster-enabled 设置为yes,表明集群模式,默认redis是单机模式。
cluster-config-file是集群特有的配置文件,在redis启动的时候若是发现没有配置文件会自动建立一个配置文件。
打开配置文件,若是集群配置文件已经存在,则直接读取。集群配置文件由redis自动维护,无需手动修改。
7000首次启动后生成的集群配置文件以下:
877e9d061f80cea70285e823cbc4246041752149 :7000@17000 myself,master - 0 0 0 connected 5474 5798 11459 11958 12706 13735 vars currentEpoch 0 lastVoteEpoch 0
记录了集群的初始状态,最重要的是第一个40位的16进制字符串,是集群的节点ID,节点ID在集群初始化的时候只建立一次,重启后会加载集群配置文件进行重用。集群节点ID不用于redis的运行id,运行id每次重启后都会变好。
直接使用redis-cli
命令来建立(redis5.0以后)
输入命令
redis-cli --cluster create 192.168.118.129:7000 192.168.118.129:7001 192.168.118.129:7002 192.168.118.129:8000 192.168.118.129:8001 192.168.118.129:8002 --cluster-replicas 1
--cluster-replicas 1
表示每个主节点分配一个从节点。
(上面的warning是由于我把全部节点部署到了同一个机器)
输入yes继续
集群配置成功,16384个slots分配完毕。
总体结构
Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 Adding replica 192.168.118.129:8001 to 192.168.118.129:7000 Adding replica 192.168.118.129:8002 to 192.168.118.129:7001 Adding replica 192.168.118.129:8000 to 192.168.118.129:7002
用上面命令建立的集群是没法手工指定主从关系的。
Redis采用Gossip协议(P2P),Gossip协议的工做原理就是节点之间不断通讯交换信息,一段时间后全部节点都会知道集群的完整信息,相似于流言传播,相似于下图:
通讯过程:
Gossip消息类型:
Gossip消息解析流程:
meet
上面的Gossip消息中,ping/pong消息都须要携带当前节点的信息和部分其余节点的信息(状态等),这些频繁的信息交换势必会加剧带宽和计算负担。依次每次选择多少个节点进行通讯(每次要发给多少个节点)变得特别重要:
具体选择:
选择发送节点
5个节点是指集群内随机找5个节点,取其中一个其余节点发送ping。
10次:针对上一步选出来的一个节点每100毫秒扫描一次本地的节点列表,若是发现节点最近一次接受pong消息的时间大于cluster-node-timeout/2 ,则须要给该节点发送ping消息,总节点数量:
ping消息数量
自身节点数量+1/10其余节点的数量
因而可知,节点的cluster_node_timeout和整个集群节点的数量都会影响集群节点之间的信息交换。