烂笔头

不积跬步无以至千里

0%

redis集群搭建

why cluster

redis replication实现一主多从架构可以实现读写分离
redis sentinel实现一主多从下得高可用
但是却不能突破redis单机瓶颈

redis3以后增加了redis cluster成为海量数据得解决方案:

  1. 自动在多节点间进行数据分片
  2. 当一部分节点出现故障或无法与其余群集通信时,可以继续操作。

redis cluster端口

每个redis cluster node 需要两个端口:一个正常得redis端口,比如6379;一个正常redis端口+10000获得得端口,比如16379
这个大端口主要用来给cluster bus使用;cluster bus用来通过一个二进制协议实现节点间得通信,用于故障检测,配置更新,故障转移授权等。

redis cluster 数据分片

redis cluster没有使用一致性hash算法,而是使用了hash slot方式。
redis cluster中有16384个hash slot,要计算给定key的hash slot,只需对key的CRC16取模16384就可以获得对应得hash slot
redist cluster中每个node代表一个hash slot得子集,比如三节点情况下:
Node A contains hash slots from 0 to 5500. Node B contains hash slots from 5501 to 11000. Node C contains hash slots from 11001 to 16383.
这样得好处是在cluster中增加或删除节点会非常简单,只需要移动一些hash slot就可以了。并且这个过程不需要任何停机。
当一个redis命令脚本执行得时候,redis cluster支持所涉及得key都属于一个hash slot得情况。可以通过使用hash tag来保证所有key属于同一个hash slot
hash tag:如果key的{}中的括号之间有一个子字符串,则仅对字符串中的内容进行哈希处理,例如,此{foo}键和另一个{foo} key保证在同一hash slot中,并且可以在具有多个key作为参数的命令中一起使用。

redis cluster master-slave模型

可以在创建cluster得时候给master添加slave节点;
比如A、B、C为master node,A1、B1、C1为slave node,这样当B故障得时候B1可以提升为master继续提供服务;但是如果B和B1都发生故障得话,集群将不能继续运行。

redis cluster 一致性保证

Redis Cluster无法保证强一致性。实际上,这意味着在某些情况下,Redis Cluster可能会丢失客户端的写入操作。
造成丢失得原因有两个:

  • 异步复制
  • 在网络分区期间,在该分区中,客户端与少数实例(至少包括主实例)隔离。

官方文档

配置集群

4台机器模拟8节点 4主4从
192.168.0.201 192.168.0.202 192.168.0.203 192.168.0.204每一台执行如下操作:

1
2
3
4
mkdir /etc/redis-cluster
touch /etc/redis-cluster/7000.conf
touch /etc/redis-cluster/7001.conf
mkdir /var/log/redis

vim /etc/redis-cluster/7000.conf

1
2
3
4
5
6
7
8
9
port 7000
cluster-enabled yes
cluster-config-file /etc/redis-cluster/node-7000.conf
cluster-node-timeout 5000
appendonly yes
daemonize yes
pidfile /var/run/redis_7000.pid
logfile /var/log/redis/7000.log
bind 192.168.0.20X 127.0.0.1

vim /etc/redis-cluster/7001.conf

1
2
3
4
5
6
7
8
9
port 7001
cluster-enabled yes
cluster-config-file /etc/redis-cluster/node-7001.conf
cluster-node-timeout 5000
appendonly yes
daemonize yes
pidfile /var/run/redis_7001.pid
logfile /var/log/redis/7001.log
bind 192.168.0.20X 127.0.0.1

启动集群节点

1
2
redis-server /etc/redis-cluster/7000.conf
redis-server /etc/redis-cluster/7001.conf

查看启动日志

创建集群

在任意机器执行创建:比如192.168.0.202

1
redis-cli --cluster create 192.168.0.201:7000 192.168.0.201:7001 192.168.0.202:7000 192.168.0.202:7001 192.168.0.203:7000 192.168.0.203:7001 192.168.0.204:7000 192.168.0.204:7001 --cluster-replicas 1

将能看到输出日志:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
>>> Performing hash slots allocation on 8 nodes...
Master[0] -> Slots 0 - 4095
Master[1] -> Slots 4096 - 8191
Master[2] -> Slots 8192 - 12287
Master[3] -> Slots 12288 - 16383
Adding replica 192.168.0.202:7001 to 192.168.0.201:7000
Adding replica 192.168.0.203:7001 to 192.168.0.202:7000
Adding replica 192.168.0.204:7001 to 192.168.0.203:7000
Adding replica 192.168.0.201:7001 to 192.168.0.204:7000
M: 9c45c1ed0d1686ebb8f648dd1950388e980ff7fd 192.168.0.201:7000
slots:[0-4095] (4096 slots) master
S: dc18063897d9ced631e409ae5129a98df717137b 192.168.0.201:7001
replicates c92a97df67f96b0f00562eac3f610785c203b393
M: 4ad71dc43b6014faf072b66de0b981360d71fe68 192.168.0.202:7000
slots:[4096-8191] (4096 slots) master
S: 5c2237d20a4957e9b604ca6f5e354676049518b7 192.168.0.202:7001
replicates 9c45c1ed0d1686ebb8f648dd1950388e980ff7fd
M: 23b72679000b8ab64b1116b556b6b06630586194 192.168.0.203:7000
slots:[8192-12287] (4096 slots) master
S: 490ad398792978333e62f40abdae5b9461acc11e 192.168.0.203:7001
replicates 4ad71dc43b6014faf072b66de0b981360d71fe68
M: c92a97df67f96b0f00562eac3f610785c203b393 192.168.0.204:7000
slots:[12288-16383] (4096 slots) master
S: 4bc59c58ebe3e0245226816a0b6443f535252294 192.168.0.204:7001
replicates 23b72679000b8ab64b1116b556b6b06630586194
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
...
>>> Performing Cluster Check (using node 192.168.0.201:7000)
M: 9c45c1ed0d1686ebb8f648dd1950388e980ff7fd 192.168.0.201:7000
slots:[0-4095] (4096 slots) master
1 additional replica(s)
S: 490ad398792978333e62f40abdae5b9461acc11e 192.168.0.203:7001
slots: (0 slots) slave
replicates 4ad71dc43b6014faf072b66de0b981360d71fe68
S: 5c2237d20a4957e9b604ca6f5e354676049518b7 192.168.0.202:7001
slots: (0 slots) slave
replicates 9c45c1ed0d1686ebb8f648dd1950388e980ff7fd
M: c92a97df67f96b0f00562eac3f610785c203b393 192.168.0.204:7000
slots:[12288-16383] (4096 slots) master
1 additional replica(s)
M: 4ad71dc43b6014faf072b66de0b981360d71fe68 192.168.0.202:7000
slots:[4096-8191] (4096 slots) master
1 additional replica(s)
S: 4bc59c58ebe3e0245226816a0b6443f535252294 192.168.0.204:7001
slots: (0 slots) slave
replicates 23b72679000b8ab64b1116b556b6b06630586194
M: 23b72679000b8ab64b1116b556b6b06630586194 192.168.0.203:7000
slots:[8192-12287] (4096 slots) master
1 additional replica(s)
S: dc18063897d9ced631e409ae5129a98df717137b 192.168.0.201:7001
slots: (0 slots) slave
replicates c92a97df67f96b0f00562eac3f610785c203b393
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

查看状态

1
2
redis-cli -p 7000 cluster nodes
redis-cli --cluster check 127.0.0.1:7000

测试数据分片

1
2
3
4
5
6
7
8
9
10
11
12
13
$ redis-cli -c -p 7000
redis 127.0.0.1:7000> set foo bar
-> Redirected to slot [12182] located at 127.0.0.1:7002
OK
redis 127.0.0.1:7002> set hello world
-> Redirected to slot [866] located at 127.0.0.1:7000
OK
redis 127.0.0.1:7000> get foo
-> Redirected to slot [12182] located at 127.0.0.1:7002
"bar"
redis 127.0.0.1:7000> get hello
-> Redirected to slot [866] located at 127.0.0.1:7000
"world"

-c参数,客户端会进行分片自动重定向。如果没有这个参数则需要到对应分片节点操作,slave节点还需要先输入readonly,然后才能进行get操作

测试故障转移

查看所有master

1
redis-cli -p 7000 cluster nodes | grep master

模拟故障

1
redis-cli -h 192.168.0.201 -p 7000  debug segfault

检查集群状态

1
redis-cli --cluster check 127.0.0.1:7000

可以发现192.168.0.201:7000得节点已经被摘除了
启动192.168.0.201:7000节点重新查看所有master,会发现master已经被其他节点接管,192.168.0.201:7000已经变成一个slave节点

添加新节点-master

添加一个空节点

1
2
3
4
cp /etc/redis-cluster/7000.conf  /etc/redis-cluster/7002.conf
sed -i 's/7000/7002/g' /etc/redis-cluster/7002.conf
redis-server /etc/redis-cluster/7002.conf
redis-cli --cluster add-node 127.0.0.1:7002 192.168.0.204:7000

检查集群状态,会发现已经加入成功
此时得master没有hash slot,不能保存数据,还需要reshard使其可以保存分片数据

1
2
3
4
#交互式迁移
redis-cli --cluster reshard 127.0.0.1:7000
或命令式迁移
redis-cli --cluster reshard <host>:<port> --cluster-from <node-id> --cluster-to <node-id> --cluster-slots <number of slots> --cluster-yes

添加新节点-slave

  • 方式1
1
2
3
4
#这种方式会随机加入一个拥有最少slaves得master
redis-cli --cluster add-node 127.0.0.1:7002 127.0.0.1:7000 --cluster-slave
#这种方式指定master
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 --cluster-slave --cluster-master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e
  • 方式2
1
2
redis-cli -p 7002
cluster replicate 23b72679000b8ab64b1116b556b6b06630586194

方式2更灵活,可以手动将slave从一个master移动到另一个master
可以通过冗余slave得方式实现slave得自动迁移:如果某个master的slave的挂了,其他节点冗余的slave会自动迁移到这个master

删除节点

1
redis-cli --cluster del-node 127.0.0.1:7000 `<node-id>`

您可以用这种方法删除master,但是要删除master,它必须为空。如果master不为空,则需要先将数据从其重新分片到所有其他master。