docker容器中搭建redis集群,进行分布式存储
Redis集群并没有使用一致性hash而是引入了哈希槽的概念。Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。但为什么哈希槽的数量是16384(214)个呢?CRC16算法产生的hash值有16bit,该算法可以产生216=65536个值。
正常的心跳数据包带有节点的完整配置,可以用幂等方式用旧的节点替换旧节点,以便更新旧的配置。
这意味着它们包含原始节点的插槽配置,该节点使用2k的空间和16k的插槽,但是会使用8k的空间(使用65k的插槽)。同时,由于其他设计折衷,Redis集群不太可能扩展到1000个以上的主节点。
因此16k处于正确的范围内,以确保每个主机具有足够的插槽,最多可容纳1000个矩阵,但数量足够少,可以轻松地将插槽配置作为原始位图传播。请注意,在小型群集中,位图将难以压缩,因为当N较小时,位图将设置的slot /N位占设置位的很大百分比。
(1)如果槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于庞大。
在消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。当槽位为65536时,这块的大小是:65536÷8÷1024=8kb
因为每秒钟,redis节点需要发送一定数量的ping消息作为心跳包,如果槽位为65536,这个ping消息的消息头太大了,浪费带宽。
(2)redis的集群主节点数量基本不可能超过1000个。
集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者不建议redis cluster节点数量超过1000个。那么,对于节点数在1000以内的redis cluster集群,16384个槽位够用了。没有必要拓展到65536个。
(3)槽位越小,节点少的情况下,压缩比高,容易传输
Redis主节点的配置信息中它所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中会对bitmap进行压缩,但是如果bitmap的填充率slots/N很高的话(N表示节点数), bitmap的压缩率就很低。如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。
使用哈希槽算法,一个集群只能有16384个槽,编号0-16383 (0-2^14-1)。这些槽会分配给集群中的所有主节点,分配策略没有要求。可以指定哪些编号的槽分配给哪个主节点。集群会记录节点和槽的对应关系。解决了节点和槽的关系后,接下来就需要对key求哈希值,然后对16384取余,余数是几key就落入对应的槽里。slot=CRC16(key)% 16384。以槽为单位移动数据,因为槽的数目是固定的,处理起来比较容易,这样数据移动问题就解决了。
首先创建6个redis服务,并且配置容器卷,让宿主机与docker容器一一对应。
docker run -d --name redis-node-1 --net host --privileged=true -v /data/redis/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381
docker run -d --name redis-node-2 --net host --privileged=true -v /data/redis/share/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382
docker run -d --name redis-node-3 --net host --privileged=true -v /data/redis/share/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383
docker run -d --name redis-node-4 --net host --privileged=true -v /data/redis/share/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384
docker run -d --name redis-node-5 --net host --privileged=true -v /data/redis/share/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385
docker run -d --name redis-node-6 --net host --privileged=true -v /data/redis/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386
--net host 使用宿主机的ip和端口,默认
--privileged=true 获取宿主机的root权限
--cluster-enabled yes 开启redis集群
--appendonly yes 开启持久化
docker ps 查看是否启动成功
进入docker 容器后,构建主从关系,为每一个master创建一个slave节点
docker exec -it redis-node-1 /bin/bash
redis-cli --cluster create 192.168.218.15:6381 192.168.218.15:6382 192.168.218.15:6383 192.168.218.15:6384 192.168.218.15:6385 192.168.218.15:6386 --cluster-replicas 1
--cluster-replicas 1 表示为每一个master创建一个slave节点
分配哈希槽位,三主三从
查看集群信息,节点状态,分配了6个节点,对此,三主三从构建成功。
cluster info
cluster nodes 查看节点分配情况,和主从挂载关系
主从容错,切换迁移
数据读写存储,发现写入数据错误,现在存储是按照槽位分配,集群环境需要加入-c,进行登录,防止路由失效,
[root@hadoop15 ~]# docker exec -it redis-node-1 /bin/bash
root@hadoop15:/data# redis-cli -p 6381 -c
127.0.0.1:6381> keys *
1) "k3"
2) "k2"
127.0.0.1:6381> flushall
OK
127.0.0.1:6381> keys *
(empty array)
127.0.0.1:6381> set k1 v1
-> Redirected to slot [12706] located at 192.168.218.15:6383
OK
192.168.218.15:6383> set k2 v2
-> Redirected to slot [449] located at 192.168.218.15:6381
OK
192.168.218.15:6381> set k3 v3
OK
192.168.218.15:6381> set k4 v4
-> Redirected to slot [8455] located at 192.168.218.15:6382
OK
192.168.218.15:6382>
集群检查
redis-cli --cluster check 192.168.218.15:6381
主从扩容,新建两个节点,将新增的6387作为master节点加入集群
这里需要一个切入口,领头羊的意思,你要把一个主节点挂在另外一个主节点上,领进门,这里的6387挂载在6381上
docker run -d --name redis-node-7 --net host --privileged=true -v /data/redis/share/redis-node-7:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6387
docker run -d --name redis-node-8 --net host --privileged=true -v /data/redis/share/redis-node-8:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388
redis-cli --cluster add-node 192.168.218.15:6387 192.168.218.15:6381
暂时没有槽位,需要重新分配槽位、不是从0开始分配、而是各自匀出来一部分,你需要自己分配哈希槽位,这里设置大小为4096,这里添加的63387的id编号。
redis-cli --cluster reshard 192.168.218.15:6381
root@hadoop15:/data# redis-cli --cluster reshard 192.168.218.15:6381
>>> Performing Cluster Check (using node 192.168.218.15:6381)
M: 015ca1715ddc564d263183deef52ef1e21046547 192.168.218.15:6381
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 9fc4fb7ddc37371234e0582fc9657a81aeaa57e0 192.168.218.15:6385
slots: (0 slots) slave
replicates 2ad500da8c227a43ecba7cc97b5a26071c9c8b07
S: b5c98c5ae3ae88bc2301caeea202a99fbbaab0ab 192.168.218.15:6386
slots: (0 slots) slave
replicates 015ca1715ddc564d263183deef52ef1e21046547
M: 43cc0a7e0de30fc62de5fcefd02c92565caeb58c 192.168.218.15:6387
slots: (0 slots) master
M: 2ad500da8c227a43ecba7cc97b5a26071c9c8b07 192.168.218.15:6383
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: 9e88d227020bb5116ba041dd499815c922b01c7f 192.168.218.15:6384
slots: (0 slots) slave
replicates 07547db3c1871d2215b4d6bf8cf21e4702c10aea
M: 07547db3c1871d2215b4d6bf8cf21e4702c10aea 192.168.218.15:6382
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)? 4096
What is the receiving node ID? 43cc0a7e0de30fc62de5fcefd02c92565caeb58c
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
Source node #1: all
挂载从节点,现在需要在新的主节点上,添加一个新的从节点,这个时候添加的id是从节点的id,实现扩容,四主四从,
redis-cli --cluster add-node 192.168.218.15:6388 192.168.218.15:6387 --cluster-slave --cluster-master-id 43cc0a7e0de30fc62de5fcefd02c92565caeb58c
主从缩容
先清除从节点6388,清出来的槽位重新分配,在删除6387,恢复成三主三从
redis-cli --cluster del-node 192.168.218.15:6388 58e3ad5a83b84a22cd63c392a2a72382cdadd25d
重新分配槽号、把槽号全部分给6381,重新打散,6381为突破口
redis-cli --cluster reshard 192.168.218.15:6381
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)? 4096
What is the receiving node ID? 43cc0a7e0de30fc62de5fcefd02c92565caeb58c
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
Source node #1: all
Ready to move 4096 slots.
Source nodes:
M: 015ca1715ddc564d263183deef52ef1e21046547 192.168.218.15:6381
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: 2ad500da8c227a43ecba7cc97b5a26071c9c8b07 192.168.218.15:6383
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
M: 07547db3c1871d2215b4d6bf8cf21e4702c10aea 192.168.218.15:6382
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
Destination node:
M: 43cc0a7e0de30fc62de5fcefd02c92565caeb58c 192.168.218.15:6387
slots: (0 slots) master
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)? 4096
What is the receiving node ID? 43cc0a7e0de30fc62de5fcefd02c92565caeb58c
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
Source node #1: all
Ready to move 4096 slots.
Source nodes:
M: 015ca1715ddc564d263183deef52ef1e21046547 192.168.218.15:6381
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: 2ad500da8c227a43ecba7cc97b5a26071c9c8b07 192.168.218.15:6383
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
M: 07547db3c1871d2215b4d6bf8cf21e4702c10aea 192.168.218.15:6382
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
Destination node:
M: 43cc0a7e0de30fc62de5fcefd02c92565caeb58c 192.168.218.15:6387
slots: (0 slots) master
将6387删除,找到6387的真实节点,进行删除操作,删除成功
redis-cli --cluster del-node 192.168.218.15:6387 43cc0a7e0de30fc62de5fcefd02c92565caeb58c