redis-cluster集群设置

Redis集群是一个可以在多个Redis节点之间进行数据共享的设施( installation )。

Redis集群不支持那些需要同时处理多个键的Redis命令,因为执行这些命令需要在多个Redis节点之间移动数据,并且在高负载的情况下,这些命令将降低Redis集群的性能,并导致不可预测的行为。

Redis集群通过分区( partition )来提供一定程度的可用性( availability ) : 即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求。

将数据自动切分( split) 到多个节点的能力。

当集群中的一部分节点失效或者无法进行通讯时,仍然可以继续处理命令请求的能力。

为什么要用redis-cluster

解决并发

redis官方生成可以达到 10万/每秒,每秒执行10万条命令
假如业务需要每秒100万的命令执行呢?

数据量太大

一台服务器内存正常是16~256G,假如你的业务需要500G内存,

新浪微博作为世界上最大的redis存储,就超过1TB的数据,去哪买这么大的内存条?各大公司有自己的解决方案,推出各自的集群功能,核心思想都是将数据分片(sharding)存储在多个redis实例中,每一片就是一个redis实例。

解决方案

  1. 配置一个超级牛逼的计算机,超大内存,超强cpu,但是问题是。。。。

  2. 正确的应该是考虑分布式,加机器,把数据分到不同的位置,分摊集中式的压力,一堆机器做一件事

客户端分片

redis3.0集群采用P2P模式,完全去中心化,将redis所有的key分成了16384个槽位,每个redis实例负责一部分slot,集群中的所有信息通过节点数据交换而更新。

redis实例集群主要思想是将redis数据的key进行散列,通过hash函数特定的key会映射到指定的redis节点上

数据分布理论

分布式数据库首要解决把整个数据集按照分区规则映射到多个节点的问题,即把数据集划分到多个节点上,每个节点负责整个数据的一个子集。

常见的分区规则有哈希分区和顺序分区。Redis Cluster采用哈希分区规则,因此接下来会讨论哈希分区规则。

  • 节点取余分区
  • 一致性哈希分区
  • 虚拟槽分区(redis-cluster采用的方式)

顺序分区

哈希分区

节点取余

例如按照节点取余的方式,分三个节点

1~100的数据对3取余,可以分为三类

  • 余数为0
  • 余数为1
  • 余数为2

那么同样的分4个节点就是hash(key)%4

节点取余的优点是简单,客户端分片直接是哈希+取余

一致性哈希

客户端进行分片,哈希+顺时针取余

虚拟槽分区

Redis Cluster采用虚拟槽分区

虚拟槽分区巧妙地使用了哈希空间,使用分散度良好的哈希函数把所有的数据映射到一个固定范围内的整数集合,整数定义为槽(slot)。

Redis Cluster槽的范围是0 ~ 16383

槽是集群内数据管理和迁移的基本单位。采用大范围的槽的主要目的是为了方便数据的拆分和集群的扩展,

每个节点负责一定数量的槽。

搭建redis cluster

搭建集群分为几部

  • 准备节点(几匹马儿)
  • 节点通信(几匹马儿分配主从)
  • 分配槽位给节点(slot分配给马儿)

redis-cluster集群架构

多个服务端,负责读写,彼此通信,redis指定了16384个槽。

多匹马儿,负责运输数据,马儿分配16384个槽位,管理数据。

ruby的脚本自动就把分配槽位这事做了

环境准备

ruby安装

1
apt-get install ruby

安装ruby gem 包管理工具

1
2
3
4
gem install -l redis

#查看gem有哪些包
gem list -- check redis gem

安装redis-trib.rb命令

安装好gem redis包会生成redis-trib.rb命令,如果你执行提示没有该命令说明不在环境变量中,使用find查找该命令位置

1
2
3
4
5
root@Tony-PC:/tmp/cluster# find /usr -name redis-trib.rb
/usr/share/doc/redis-tools/examples/redis-trib.rb

# 可以将其加入到环境变量
root@Tony-PC:/tmp/cluster#cp /usr/share/doc/redis-tools/examples/redis-trib.rb /usr/local/bin/

准备redis-server配置文件

1
2
3
4
5
6
cluster-8001.conf  127.0.0.1:8001
cluster-8002.conf 127.0.0.1:8002
cluster-8003.conf 127.0.0.1:8003
cluster-8004.conf 127.0.0.1:8004
cluster-8005.conf 127.0.0.1:8005
cluster-8006.conf 127.0.0.1:8006
编辑配置文件
1
2
3
4
5
6
7
8
9
10
11
12
root@Tony-PC:/tmp/cluster# touch cluster-8001.conf
root@Tony-PC:/tmp/cluster# vim cluster-8001.conf

# 文件内容
port 8001
daemonize yes
dir /tmp/cluster
logfile 8001.log
dbfilename 8001.rdb
cluster-enabled yes #开启集群模式
cluster-config-file nodes-8001.conf  #集群内部的配置文件
cluster-require-full-coverage no  #redis cluster需要16384个slot都正常的时候才能对外提供服务,换句话说,只要任何一个slot异常那么整个cluster不对外提供服务。 因此生产环境一般为no
编辑其他配置文件
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
61
62
63
64
65
66
67
root@Tony-PC:/tmp/cluster# sed 's/8001/8002/g' cluster-8001.conf > cluster-8002.conf

# 文件内容
port 8002
daemonize yes
dir /tmp/cluster
logfile 8002.log
dbfilename 8002.rdb
cluster-enabled yes
cluster-config-file nodes-8002.conf
cluster-require-full-coverage no

-----------------------------------------------------------------------------

root@Tony-PC:/tmp/cluster# sed 's/8001/8003/g' cluster-8001.conf > cluster-8003.conf

# 文件内容
port 8003
daemonize yes
dir /tmp/cluster
logfile 8003.log
dbfilename 8003.rdb
cluster-enabled yes
cluster-config-file nodes-8003.conf
cluster-require-full-coverage no

-----------------------------------------------------------------------------

root@Tony-PC:/tmp/cluster# sed 's/8001/8004/g' cluster-8001.conf > cluster-8004.conf

# 文件内容
port 8004
daemonize yes
dir /tmp/cluster
logfile 8004.log
dbfilename 8004.rdb
cluster-enabled yes
cluster-config-file nodes-8004.conf
cluster-require-full-coverage no

-----------------------------------------------------------------------------

root@Tony-PC:/tmp/cluster# sed 's/8001/8005/g' cluster-8001.conf > cluster-8005.conf

# 文件内容
port 8005
daemonize yes
dir /tmp/cluster
logfile 8005.log
dbfilename 8005.rdb
cluster-enabled yes
cluster-config-file nodes-8005.conf
cluster-require-full-coverage no

-----------------------------------------------------------------------------

root@Tony-PC:/tmp/cluster# sed 's/8001/8006/g' cluster-8001.conf > cluster-8006.conf

# 文件内容
port 8006
daemonize yes
dir /tmp/cluster
logfile 8006.log
dbfilename 8006.rdb
cluster-enabled yes
cluster-config-file nodes-8006.conf
cluster-require-full-coverage no

运行redis-server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
root@Tony-PC:/tmp/cluster# redis-server cluster-8001.conf
root@Tony-PC:/tmp/cluster# redis-server cluster-8002.conf
root@Tony-PC:/tmp/cluster# redis-server cluster-8003.conf
root@Tony-PC:/tmp/cluster# redis-server cluster-8004.conf
root@Tony-PC:/tmp/cluster# redis-server cluster-8005.conf
root@Tony-PC:/tmp/cluster# redis-server cluster-8006.conf


root@Tony-PC:/tmp/cluster# ps -ef | grep redis
root 8131 1 0 10:22 ? 00:00:00 redis-server *:8001 [cluster]
root 8140 1 0 10:22 ? 00:00:00 redis-server *:8002 [cluster]
root 8148 1 0 10:22 ? 00:00:00 redis-server *:8003 [cluster]
root 8156 1 0 10:22 ? 00:00:00 redis-server *:8004 [cluster]
root 8164 1 0 10:22 ? 00:00:00 redis-server *:8005 [cluster]
root 8171 1 0 10:22 ? 00:00:00 redis-server *:8006 [cluster]
root 8179 5341 0 10:23 pts/1 00:00:00 grep redis

此时启动redis-cli,集群还不能用,未提供hsah

1
2
3
4
5
root@Tony-PC:/tmp/cluster# redis-cli -c -p 8001
127.0.0.1:8001> keys *
(empty list or set)
127.0.0.1:8001> set name tony
(error) CLUSTERDOWN Hash slot not served

开启redis-cluster集群

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
#每个主节点,有一个从节点,代表--replicas 1
root@Tony-PC:/tmp/cluster# redis-trib.rb create --replicas 1 127.0.0.1:8001 127.0.0.1:8002 127.0.0.1:8003 127.0.0.1:8004 127.0.0.1:8005 127.0.0.1:8006
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
127.0.0.1:8001
127.0.0.1:8002
127.0.0.1:8003
Adding replica 127.0.0.1:8005 to 127.0.0.1:8001
Adding replica 127.0.0.1:8006 to 127.0.0.1:8002
Adding replica 127.0.0.1:8004 to 127.0.0.1:8003
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: e1654cae78b3c314deeb8c9741d7fbcc4606469c 127.0.0.1:8001
slots:0-5460 (5461 slots) master
M: 0fdb6c8423c25ffd8841cf67d25ed6ff5934ebb6 127.0.0.1:8002
slots:5461-10922 (5462 slots) master
M: 07239385ba365d456cc9d7d7c60274eb894f4ebc 127.0.0.1:8003
slots:10923-16383 (5461 slots) master
S: 98ab1b39b41a3588ab0102098915a92bb2b67203 127.0.0.1:8004
replicates 0fdb6c8423c25ffd8841cf67d25ed6ff5934ebb6
S: dd8b553ce03137892578e59629f7b6ec483135a4 127.0.0.1:8005
replicates 07239385ba365d456cc9d7d7c60274eb894f4ebc
S: 6df2f0ecbff311dd3289764ff9d9d789ad1cef6e 127.0.0.1:8006
replicates e1654cae78b3c314deeb8c9741d7fbcc4606469c
Can I set the above configuration? (type 'yes' to accept): yes
# 提示是否应用以上配置,同意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 127.0.0.1:8001)
M: e1654cae78b3c314deeb8c9741d7fbcc4606469c 127.0.0.1:8001
slots:0-5460 (5461 slots) master
1 additional replica(s)
S: dd8b553ce03137892578e59629f7b6ec483135a4 127.0.0.1:8005
slots: (0 slots) slave
replicates 07239385ba365d456cc9d7d7c60274eb894f4ebc
S: 98ab1b39b41a3588ab0102098915a92bb2b67203 127.0.0.1:8004
slots: (0 slots) slave
replicates 0fdb6c8423c25ffd8841cf67d25ed6ff5934ebb6
S: 6df2f0ecbff311dd3289764ff9d9d789ad1cef6e 127.0.0.1:8006
slots: (0 slots) slave
replicates e1654cae78b3c314deeb8c9741d7fbcc4606469c
M: 07239385ba365d456cc9d7d7c60274eb894f4ebc 127.0.0.1:8003
slots:10923-16383 (5461 slots) master
1 additional replica(s)
M: 0fdb6c8423c25ffd8841cf67d25ed6ff5934ebb6 127.0.0.1:8002
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.

开启成功,集群自动分配主从关系 8001、8006、8003为 8004、8005、8006 主动关系

新版开启集群方式

新版本开启集群的方式已经不需要redis-trib.tb命令了,官方给我们的警告是:WARNING: redis-trib.rb is not longer available!,也就是说这个命令不再可用了,官方给的完整提示如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
WARNING: redis-trib.rb is not longer available!
You should use redis-cli instead.

All commands and features belonging to redis-trib.rb have been moved
to redis-cli.
In order to use them you should call redis-cli with the --cluster
option followed by the subcommand name, arguments and options.

Use the following syntax:
redis-cli --cluster SUBCOMMAND [ARGUMENTS] [OPTIONS]

Example:
redis-cli --cluster create 127.0.0.1:8001 127.0.0.1:8002 127.0.0.1:8003 127.0.0.1:8004 127.0.0.1:8005 127.0.0.1:8006 --cluster-replicas 1

To get help about all subcommands, type:
redis-cli --cluster help

也就是说以后我们使用redis-cli --cluster create命令就可以开启集群了。

查看集群状态

1
2
3
4
5
6
7
8
redis-cli -p 7000 cluster info  

redis-cli -p 7000 cluster nodes #等同于查看nodes-7000.conf文件节点信息

集群主节点状态
redis-cli -p 7000 cluster nodes | grep master
集群从节点状态
redis-cli -p 7000 cluster nodes | grep slave
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
root@Tony-PC:/tmp/cluster# redis-cli -c -p 8001
127.0.0.1:8001> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=8006,state=online,offset=1134,lag=1
master_replid:6914abc6a11f70134a2d1e2446a21665539babcd
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1134
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1134


root@Tony-PC:/tmp/cluster# redis-cli -c -p 8002
127.0.0.1:8002> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=8004,state=online,offset=1134,lag=0
master_replid:8497b92f1b109a90dda607f0b629e031edde9842
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1134
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1134


root@Tony-PC:/tmp/cluster# redis-cli -c -p 8003
127.0.0.1:8003> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=8005,state=online,offset=1162,lag=0
master_replid:5e35aa5d820ccb34dfabbd2868bbe62379c44da8
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1162
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1162


root@Tony-PC:/tmp/cluster# redis-cli -c -p 8004
127.0.0.1:8004> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:8002
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:1162
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:8497b92f1b109a90dda607f0b629e031edde9842
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1162
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1162


root@Tony-PC:/tmp/cluster# redis-cli -c -p 8005
127.0.0.1:8005> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:8003
master_link_status:up
master_last_io_seconds_ago:6
master_sync_in_progress:0
slave_repl_offset:1176
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:5e35aa5d820ccb34dfabbd2868bbe62379c44da8
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1176
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1176


root@Tony-PC:/tmp/cluster# redis-cli -c -p 8006
127.0.0.1:8006> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:8001
master_link_status:up
master_last_io_seconds_ago:10
master_sync_in_progress:0
slave_repl_offset:1176
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:6914abc6a11f70134a2d1e2446a21665539babcd
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1176
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1176

测试写入数据

测试写入集群数据,登录集群必须使用redis-cli -c -p 8001必须加上-c参数

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
# 这里会将key自动的重定向,放到某一个节点的slot槽位中
127.0.0.1:8001> set a 1
-> Redirected to slot [15495] located at 127.0.0.1:8003
OK
127.0.0.1:8003> set b 2
-> Redirected to slot [3300] located at 127.0.0.1:8001
OK
127.0.0.1:8001> set c 3
-> Redirected to slot [7365] located at 127.0.0.1:8002
OK
127.0.0.1:8002> set d 4
-> Redirected to slot [11298] located at 127.0.0.1:8003
OK
127.0.0.1:8003> set e 5
OK
127.0.0.1:8003> set f 6
-> Redirected to slot [3168] located at 127.0.0.1:8001
OK


127.0.0.1:8001> get a
-> Redirected to slot [15495] located at 127.0.0.1:8003
"1"
127.0.0.1:8003> get b
-> Redirected to slot [3300] located at 127.0.0.1:8001
"2"
127.0.0.1:8001> get c
-> Redirected to slot [7365] located at 127.0.0.1:8002
"3"
127.0.0.1:8002> get d
-> Redirected to slot [11298] located at 127.0.0.1:8003
"4"
127.0.0.1:8003> get e
"5"
127.0.0.1:8003> get f
-> Redirected to slot [3168] located at 127.0.0.1:8001
"6"

127.0.0.1:8001> keys *
1) "b"
2) "f"
127.0.0.1:8002> keys *
1) "c"
127.0.0.1:8003> keys *
1) "d"
2) "e"
3) "a"

127.0.0.1:8004> keys *
1) "c"
127.0.0.1:8005> keys *
1) "e"
2) "a"
3) "d"
127.0.0.1:8006> keys *
1) "b"
2) "f"

集群ok

工作原理:

redis客户端任意访问一个redis实例,如果数据不在该实例中,通过重定向引导客户端访问所需要的redis实例