【那些年我们用过的Redis】Redis集群搭建原来这么简单

216 阅读20分钟

Reids服务集群模式可分为主从、哨兵、Cluster模式。本博客主要介绍主从和Cluster模式

三种集群模式简介

主从模式:主从模式是三种模式中最简单的,一般有一个master服务和多个(至少一个)slave服务组成。主要实现读写分离,减轻单Redis服务压力。master负责写数据,然后将数据copy给slaveslave服务负责读数据。

哨兵模式:主从模式有个弊端,就是一旦master服务挂掉,Redis服务就无法再写入数据,slave并不会升级为master。于是需要另外一种类型的服务Sentinel(哨兵)。Sentinel主要负责监控通知自动故障转移配置提供者。简单来说就是,Sentinel可以监督数据节点(masterslave)健康状态,并通知DBA(数据库管理人员),如果master挂了,从众多slave中选举一个新的master,并且告诉客户端(cli)数据节点的信息。

Cluster:哨兵模式虽然相较于主从模式来说,友善了很多,但是master不好做负载,并且储存受单机限制,还引入了另外一种类型的服务,有些繁琐。于是乎,Cluster就来了,通常具有 高可用、可扩展性、分布式、容错 等特性。当然,Cluster哨兵模式没有明确的谁好谁坏,还是要看自己的需求的。一般分布式,使用Cluster好一些。

主从模式

在搭建主从模式Cluster之前,我默认你会安装单机的redis,并且你的环境是Linux(CentOS7),你的Redis版本是5.0.9。如果不会单机redis安装,请戳

首先将原生的redis.conf复制两份到/usr/local路径下:

cp redis.conf /usr/local/redis_master.conf
cp redis.conf /usr/local/redis_replic.conf

然后利用vim修改两个配置文件,修改主要参数如下: redis_master.conf

# 主机地址,默认是127.0.0.1,修改成0.0.0.0
bind 0.0.0.0
# 端口
port 16379
# 是否开启为守护线程,默认是no,改成yes
daemonize yes
# 指定redis进程的PID文件存放位置 给文件重命名
pidfile /var/run/redis_16379.pid
# 日志存放位置 给文件重命名
logfile /var/log/redis_16379.log
# rdb模式持久化快照
dbfilename dump-16379.rdb
# 持久化文件存放位置
dir ./redis-workir
# redis连接密码
requirepass 123456
# 连接主服务器的密码,这里可以省略
masterauth 123456

redis_replic.conf

# 主机地址,默认是127.0.0.1,修改成0.0.0.0
bind 0.0.0.0
# 端口
port 26379
# 是否开启为守护线程,默认是no,改成yes
daemonize yes
# 指定redis进程的PID文件存放位置 给文件重命名
pidfile /var/run/redis_26379.pid
# 日志存放位置 给文件重命名
logfile /var/log/redis_26379.log
# rdb模式持久化快照
dbfilename dump-26379.rdb
# 持久化文件存放位置
dir ./redis-workir
# redis连接密码
requirepass 123456
# 连接主服务器的密码
masterauth 123456
# 本复制节点的主节点地址
replicaof 你服务器外网ip 16379

上面注意,在之前的版本replicaof叫做slaveof 。这里,我们模仿有两台主机,所以主机ip不写127.0.0.1了,写你服务器外网的ip,后面也方便说下网关的问题。然后开启两个服务。

redis-server /usr/local/redis_master.conf
redis-server /usr/local/redis_replic.conf

此时查看两个服务日志,都成长启动了。但是此时master,写数据,slave 无法复制数据,查看日志报错

Error condition on socket for SYNC: No route to host

这边需要打开服务器的防火墙,用到iptables,安装请移步我上篇博客(请戳)。

iptables -I INPUT -p tcp -m tcp --dport 16379 -j ACCEPT
iptables -I INPUT -p tcp -m tcp --dport 26379 -j ACCEPT
service iptables save
# 查看一下
iptables -L -n -v
# 的确暴露出去这两个端口了
   66  3528 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:26379
 196K   17M ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:16379

然后使用一下

[root@VM_0_10_centos ~]# redis-cli -h 127.0.0.1 -p 16379 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:16379> set today 1106
OK
127.0.0.1:16379> 
[root@VM_0_10_centos ~]# redis-cli -h 127.0.0.1 -p 26379 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:26379> get today
"1106"

Cluster模式

首先我们创建一个文件夹/usr/local/redis-cluster。并在它下面创建logdataconf,并在data文件中创建不同服务的文件夹。基本就是cd到位置,然后使用mkdir,比较简单,就看下目录结构吧

[root@VM_0_10_centos redis-cluster]# tree -d
.
|-- conf
|-- data
|   |-- redis-6378
|   |-- redis-6380
|   |-- redis-6381
|   |-- redis-6389
|   |-- redis-6390
|   |-- redis-6391
`-- log

然后在conf文件下创建这几个服务的配置文件,这几个文件,一摸一样,只需要关键位置替换端口号就好了,你懂的,下面以6378为例。

cd /usr/local/redis-cluster/conf
# copy一份原始文件过来
cp /usr/local/redis.conf /usr/local/redis-cluster/conf/redis-6378.conf
vim redis-6378.conf

修改关键配置如下,其他默认不变 redis-6378.conf

# 主机地址,默认是127.0.0.1,修改成0.0.0.0
bind 0.0.0.0
# 端口
port 6378
# 是否开启为守护线程,默认是no,改成yes
daemonize yes
# 指定redis进程的PID文件存放位置 给文件重命名
pidfile /var/run/redis-cluster/redis-6378.pid
# 日志存放位置 给文件重命名
logfile /usr/local/redis-cluster/log/redis-6378.log
# rdb模式持久化快照
dbfilename dump-6378.rdb
# 持久化文件存放位置
dir /usr/local/redis-cluster/data/redis-6378
# redis连接密码
requirepass 123456
# 连接主服务器的密码
masterauth 123456
# 开启AOF持久化模式
appendonly yes
# 开启cluster集群模式
cluster-enabled yes
# 集群的配置,配置文件首次启动自动生成
cluster-config-file /usr/local/redis-cluster/conf/node-6378.conf
# 请求超时,默认的就好
cluster-node-timeout 15000

cluster-enabled开启cluster集群模式,appendonly开启AOF持久化模式,一种实时性比RDB模式更好的持久化模式。生成的aof格式文件也在dir路径下,并且被读进内存的优先级比dump-6378.rdb文件要高。cluster-config-file是存放集群配置文件的地方,自动生成。同样的配置,将端口号换成其他五个,生成redis-6380.conf redis-6381.conf redis-6389.conf redis-6390.conf redis-6391.conf 。然后开启这些服务。

redis-server redis-6378.conf 
redis-server redis-6380.conf 
redis-server redis-6381.conf 
redis-server redis-6389.conf 
redis-server redis-6390.conf 
redis-server redis-6391.conf 
# 查看下是否开启
ps -ef | grep redis
# 进程已存在
root      3009     1  0 Nov05 ?        00:01:49 redis-server 0.0.0.0:6378 [cluster]
root      3047     1  0 Nov05 ?        00:01:47 redis-server 0.0.0.0:6381 [cluster]
root      3056     1  0 Nov05 ?        00:01:50 redis-server 0.0.0.0:6389 [cluster]
root      3073     1  0 Nov05 ?        00:01:49 redis-server 0.0.0.0:6390 [cluster]
root      3083     1  0 Nov05 ?        00:01:50 redis-server 0.0.0.0:6391 [cluster]
root     26443     1  0 Nov05 ?        00:01:39 redis-server 0.0.0.0:6380 [cluster]

注意,它们后面都显示它们是以cluster集群形式开启的。下面开启集群,如果是redis5.0以前的版本,需要下载ruby,通过ruby开启,redis5.0以后可直接开启,命令如下:

# 开启集群
redis-cli -a 123456--cluster create 127.0.0.1:6378 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6389 127.0.0.1:6390 127.0.0.1:6391 --cluster-replicas 1
# 会多一步询问,输入yes即可
Can I set the above configuration? (type 'yes' to accept): yes
#开启代理防火墙
iptables -I INPUT -p tcp -m tcp --dport 6378 -j ACCEPT
iptables -I INPUT -p tcp -m tcp --dport 6380 -j ACCEPT
iptables -I INPUT -p tcp -m tcp --dport 6381 -j ACCEPT
iptables -I INPUT -p tcp -m tcp --dport 6389 -j ACCEPT
iptables -I INPUT -p tcp -m tcp --dport 6390 -j ACCEPT
iptables -I INPUT -p tcp -m tcp --dport 6391 -j ACCEPT
service iptables save

开启集群的命令,会自动生成主从关系,分配solt,终端会询问这种分配方式ok吗?如果操作者觉得可以的话,需要输入yes。用cli方式随便连接一个redis服务。

redis-cli -c -h 127.0.0.1 -p 6378 -a 123456
127.0.0.1:6378> CLUSTER INFO
# 此处省略一些信息
127.0.0.1:6378> CLUSTER NODES
114d082bb43c67042c806e0060f5fb8157736b98 127.0.0.1:6390@16390 slave ca998854f1d96e2b64b7304aea5e5b4c96a9d85a 0 1604672507350 5 connected
1efc0139a5422c68f1c43428d1d6f566ce361fed 127.0.0.1:6378@16378 myself,master - 0 1604672504000 1 connected 0-5460
f10fc263b1b887fe175307b2fb7600370d39c0e1 127.0.0.1:6389@16389 master - 0 1604672505000 8 connected 5461-10922
e1eb98ead97d9b22fe4538601cbcd193e998baad 127.0.0.1:6380@16380 slave f10fc263b1b887fe175307b2fb7600370d39c0e1 0 1604672505347 8 connected
ca998854f1d96e2b64b7304aea5e5b4c96a9d85a 127.0.0.1:6381@16381 master - 0 1604672506000 3 connected 10923-16383
0f75c7f994a43551671e955a9f72c28a9c6edb56 127.0.0.1:6391@16391 slave 1efc0139a5422c68f1c43428d1d6f566ce361fed 0 1604672504344 6 connected

可以看出637863896381master节点,分别管理卡槽0-54605461-1092210923-16383。并且可以根据id值,判断出三个slave节点的主节点是谁,例如6390主节点id值是ca998854f1d96e2b64b7304aea5e5b4c96a9d85a,所以就是6381了。

这里需要说明一下,当我们存值的时候,key会根据hash函数计算出来,落在那个卡槽上。

127.0.0.1:6378> set haha 123
OK
127.0.0.1:6378> set name pjjlt
-> Redirected to slot [5798] located at 127.0.0.1:6389
OK
127.0.0.1:6389> 

可以看出来,haha经过hash运算,落在的卡槽在0-5460范围内,name经过hash运算,落在的卡槽在5461-10922范围内,所以服务终端也自动重定向到6389服务上。get也会导致服务终端重定向。

127.0.0.1:6389> get name
"pjjlt"
127.0.0.1:6389> get haha
-> Redirected to slot [3662] located at 127.0.0.1:6378
"123"
127.0.0.1:6378> 

增加和移除节点

cluster集群可以友好的水平拓展。下面增加两个节点,同上面一样,增加配置文件redis-6395.confredis-6396.conf,并开启这两个服务

redis-server redis-6395.conf 
redis-server redis-6396.conf 

加入集群

# 随便连接一个服务
redis-cli -c -h 127.0.0.1 -p 6378 -a 123456
# 加入集群
CLUSTER MEET 127.0.0.1 6395
CLUSTER MEET 127.0.0.1 6395
# 查看状态
CLUSTER NODES
114d082bb43c67042c806e0060f5fb8157736b98 127.0.0.1:6390@16390 slave ca998854f1d96e2b64b7304aea5e5b4c96a9d85a 0 1604673986000 5 connected
1efc0139a5422c68f1c43428d1d6f566ce361fed 127.0.0.1:6378@16378 myself,master - 0 1604673985000 1 connected 0-5460
2eefbdc56047282fc80baf3cc7bc08ff86dbdf9e 127.0.0.1:6395@16395 master - 0 1604673985000 7 connected
f10fc263b1b887fe175307b2fb7600370d39c0e1 127.0.0.1:6389@16389 master - 0 1604673988720 8 connected 5461-10922
e1eb98ead97d9b22fe4538601cbcd193e998baad 127.0.0.1:6380@16380 slave f10fc263b1b887fe175307b2fb7600370d39c0e1 0 1604673987717 8 connected
f8c884f07375cb524236341c4fcb963f58f82622 127.0.0.1:6396@16396 master - 0 1604673987517 7 connected
ca998854f1d96e2b64b7304aea5e5b4c96a9d85a 127.0.0.1:6381@16381 master - 0 1604673986000 3 connected 10923-16383
0f75c7f994a43551671e955a9f72c28a9c6edb56 127.0.0.1:6391@16391 slave 1efc0139a5422c68f1c43428d1d6f566ce361fed 0 1604673986716 6 connected

可以看出,此时加入的两个节点全都是master服务,现在将6396设置成6395的slave节点。

redis-cli -c -h 127.0.0.1 -p 6396 -a 123456 cluster replicate 2eefbdc56047282fc80baf3cc7bc08ff86dbdf9e
# 随便连接一个服务
redis-cli -c -h 127.0.0.1 -p 6378 -a 123456
CLUSTER NODES
114d082bb43c67042c806e0060f5fb8157736b98 127.0.0.1:6390@16390 slave ca998854f1d96e2b64b7304aea5e5b4c96a9d85a 0 1604673986000 5 connected
1efc0139a5422c68f1c43428d1d6f566ce361fed 127.0.0.1:6378@16378 myself,master - 0 1604673985000 1 connected 0-5460
2eefbdc56047282fc80baf3cc7bc08ff86dbdf9e 127.0.0.1:6395@16395 master - 0 1604673985000 7 connected
f10fc263b1b887fe175307b2fb7600370d39c0e1 127.0.0.1:6389@16389 master - 0 1604673988720 8 connected 5461-10922
e1eb98ead97d9b22fe4538601cbcd193e998baad 127.0.0.1:6380@16380 slave f10fc263b1b887fe175307b2fb7600370d39c0e1 0 1604673987717 8 connected
f8c884f07375cb524236341c4fcb963f58f82622 127.0.0.1:6396@16396 slave 2eefbdc56047282fc80baf3cc7bc08ff86dbdf9e 0 1604673987517 7 connected
ca998854f1d96e2b64b7304aea5e5b4c96a9d85a 127.0.0.1:6381@16381 master - 0 1604673986000 3 connected 10923-16383
0f75c7f994a43551671e955a9f72c28a9c6edb56 127.0.0.1:6391@16391 slave 1efc0139a5422c68f1c43428d1d6f566ce361fed 0 1604673986716 6 connected

可以看出,此时6396节点已经变成了6395的slave节点了。

移除集群

规则:不能移除登录节点,不能移除自己的master节点。可以删除其他的master或者slave节点

# 根据上面可以看出 1efc0139a5422c68f1c43428d1d6f566ce361fed 就是6378节点
127.0.0.1:6378> CLUSTER FORGET 1efc0139a5422c68f1c43428d1d6f566ce361fed
(error) ERR I tried hard but I can't forget myself...
# 登录6378的slave节点6391,删除6378,失败。
[root@VM_0_10_centos conf]# redis-cli -c -h 127.0.0.1 -p 6391 -a pjjlt1126
127.0.0.1:6391> CLUSTER FORGET 1efc0139a5422c68f1c43428d1d6f566ce361fed
(error) ERR Can't forget my master!
# 将刚加入的节点 6396
127.0.0.1:6378> CLUSTER FORGET f8c884f07375cb524236341c4fcb963f58f82622
OK
127.0.0.1:6378> CLUSTER NODES
114d082bb43c67042c806e0060f5fb8157736b98 127.0.0.1:6390@16390 slave ca998854f1d96e2b64b7304aea5e5b4c96a9d85a 0 1604675461284 5 connected
1efc0139a5422c68f1c43428d1d6f566ce361fed 127.0.0.1:6378@16378 myself,master - 0 1604675460000 1 connected 0-5460
2eefbdc56047282fc80baf3cc7bc08ff86dbdf9e 127.0.0.1:6395@16395 master - 0 1604675460283 7 connected
f10fc263b1b887fe175307b2fb7600370d39c0e1 127.0.0.1:6389@16389 master - 0 1604675462284 8 connected 5461-10922
e1eb98ead97d9b22fe4538601cbcd193e998baad 127.0.0.1:6380@16380 slave f10fc263b1b887fe175307b2fb7600370d39c0e1 0 1604675462000 8 connected
ca998854f1d96e2b64b7304aea5e5b4c96a9d85a 127.0.0.1:6381@16381 master - 0 1604675460000 3 connected 10923-16383
0f75c7f994a43551671e955a9f72c28a9c6edb56 127.0.0.1:6391@16391 slave 1efc0139a5422c68f1c43428d1d6f566ce361fed 0 1604675463287 6 connected

发现移除了,由于node.conf文件还存在(cluster-config-file配置的那个文件),还可以恢复移除

# 恢复移除
127.0.0.1:6378> CLUSTER SAVECONFIG 
OK
# 发现6396它又回来了
127.0.0.1:6378> CLUSTER NODES
114d082bb43c67042c806e0060f5fb8157736b98 127.0.0.1:6390@16390 slave ca998854f1d96e2b64b7304aea5e5b4c96a9d85a 0 1604675573000 5 connected
1efc0139a5422c68f1c43428d1d6f566ce361fed 127.0.0.1:6378@16378 myself,master - 0 1604675569000 1 connected 0-5460
2eefbdc56047282fc80baf3cc7bc08ff86dbdf9e 127.0.0.1:6395@16395 master - 0 1604675572000 7 connected
f10fc263b1b887fe175307b2fb7600370d39c0e1 127.0.0.1:6389@16389 master - 0 1604675572000 8 connected 5461-10922
e1eb98ead97d9b22fe4538601cbcd193e998baad 127.0.0.1:6380@16380 slave f10fc263b1b887fe175307b2fb7600370d39c0e1 0 1604675571000 8 connected
f8c884f07375cb524236341c4fcb963f58f82622 127.0.0.1:6396@16396 slave 2eefbdc56047282fc80baf3cc7bc08ff86dbdf9e 0 1604675572509 7 connected
ca998854f1d96e2b64b7304aea5e5b4c96a9d85a 127.0.0.1:6381@16381 master - 0 1604675574514 3 connected 10923-16383
0f75c7f994a43551671e955a9f72c28a9c6edb56 127.0.0.1:6391@16391 slave 1efc0139a5422c68f1c43428d1d6f566ce361fed 0 1604675573511 6 connected

模拟宕机

首先说一个坑:在cluster集群模式下,不能直接kill -9 某个节点,只能用kill(当然模拟宕机咱们用的是CLUSTER FORGET命令)。kill -9 ,再重启集群的时候会报错,需要删除pidfile、data、log等等一些东西,才能重启集群成功,所以尽量不要kill -9。

直接kill 6378 试试

[root@VM_0_10_centos conf]# redis-cli -c -h 127.0.0.1 -p 6391 -a 123456
127.0.0.1:6391> CLUSTER NODES
0f75c7f994a43551671e955a9f72c28a9c6edb56 127.0.0.1:6391@16391 myself,master - 0 1604675774000 9 connected 0-5460
ca998854f1d96e2b64b7304aea5e5b4c96a9d85a 127.0.0.1:6381@16381 master - 0 1604675779737 3 connected 10923-16383
f8c884f07375cb524236341c4fcb963f58f82622 127.0.0.1:6396@16396 slave 2eefbdc56047282fc80baf3cc7bc08ff86dbdf9e 0 1604675778000 7 connected
f10fc263b1b887fe175307b2fb7600370d39c0e1 127.0.0.1:6389@16389 master - 0 1604675777000 8 connected 5461-10922
2eefbdc56047282fc80baf3cc7bc08ff86dbdf9e 127.0.0.1:6395@16395 master - 0 1604675776000 7 connected
114d082bb43c67042c806e0060f5fb8157736b98 127.0.0.1:6390@16390 slave ca998854f1d96e2b64b7304aea5e5b4c96a9d85a 0 1604675779000 5 connected
1efc0139a5422c68f1c43428d1d6f566ce361fed 127.0.0.1:6378@16378 master,fail - 1604675757260 1604675756000 1 disconnected
e1eb98ead97d9b22fe4538601cbcd193e998baad 127.0.0.1:6380@16380 slave f10fc263b1b887fe175307b2fb7600370d39c0e1 0 1604675778000 8 connected

发现此时6378为master,fail,而它原来的slave节点为master。再重启6378节点看看。

[root@VM_0_10_centos conf]# redis-server redis-6378.conf 
[root@VM_0_10_centos conf]# redis-cli -c -h 127.0.0.1 -p 6391 -a 123456
127.0.0.1:6391> CLUSTER NODES
0f75c7f994a43551671e955a9f72c28a9c6edb56 127.0.0.1:6391@16391 myself,master - 0 1604675996000 9 connected 0-5460
ca998854f1d96e2b64b7304aea5e5b4c96a9d85a 127.0.0.1:6381@16381 master - 0 1604675993000 3 connected 10923-16383
f8c884f07375cb524236341c4fcb963f58f82622 127.0.0.1:6396@16396 slave 2eefbdc56047282fc80baf3cc7bc08ff86dbdf9e 0 1604675992368 7 connected
f10fc263b1b887fe175307b2fb7600370d39c0e1 127.0.0.1:6389@16389 master - 0 1604675997000 8 connected 5461-10922
2eefbdc56047282fc80baf3cc7bc08ff86dbdf9e 127.0.0.1:6395@16395 master - 0 1604675996376 7 connected
114d082bb43c67042c806e0060f5fb8157736b98 127.0.0.1:6390@16390 slave ca998854f1d96e2b64b7304aea5e5b4c96a9d85a 0 1604675997376 5 connected
1efc0139a5422c68f1c43428d1d6f566ce361fed 127.0.0.1:6378@16378 slave 0f75c7f994a43551671e955a9f72c28a9c6edb56 0 1604675995000 9 connected
e1eb98ead97d9b22fe4538601cbcd193e998baad 127.0.0.1:6380@16380 slave f10fc263b1b887fe175307b2fb7600370d39c0e1 0 1604675998378 8 connected

发现此时原来的master节点6378变成了6391的slave节点了。

**但是,只有当master节点有slot卡槽的时候,才会出现主从节点转化,当master节点没有卡槽时,不会进行转化。**例如,删除6395,再重启,发现6395还是master,6396还是slave

另外,上面提到的node.conf,不仅可以帮助移除恢复(CLUSTER SAVECONFIG),还可以记录刚刚的CLUSTER 指令日志。

以上,就是cluster模式的搭建介绍,谢谢观看。