redis cluster 搭建
一、redis常用的三种集群模式
- 主从
- 通过持久化功能,redis保证了即使在服务器重启的情况下也不会丢失(或少量丢失)数据,因为持久化会把内存中的数据保存在硬盘上。重启会从硬盘上加载数据。但是由于数据是存在一台服务器上,如果这台服务器出现硬盘故障等问题,也会导致数据丢失
- 为了避免单点故障,通常的做法是将数据复制多个副本,以部署在不同的服务器上,这样即使有一台服务器出现故障,其他服务器依然可以提供服务。为此,reids提供了复制(replication)功能,可以实现一台数据库中的数据更新后,自动将更新的数据同步到其他服务器上。
- 在复制的概念中,数据库分为两类,一类是主数据库(master),另一类是从数据库(slaver)
- 主数据库可以进行读写操作,当写操作导致数据变化时会自动将数据同步给从数据库。
- 而从数据库一般只是只读的,并接受数据库同步过的数据。
- 一个主数据库可以拥有多个从数据库,而一个从数据库只能拥有一个主数据库
- 哨兵
- 第一种主从同步/复制的模式,当主服务器宕机后,需要手动把一台服务器切换为主服务器。这就需要人工干预,费时费力。还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。
- 哨兵模式是一种特殊的模式,首先redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,他会独立运行
- 其原理是哨兵通过发送命令,等待redis服务器响应,从而监控运行的多个redis实例。
- cluster
- redis的哨兵模式基本可以实现高可用,读写分离,但是在这种模式下,每台redis服务器都存储相同的数据,浪费内存。并且水平扩容很费劲。
- 所以在redis 3.0上加入了cluster集群模式,实现了redis的分布式存储,也就是说每台redis节点上存储不同的内容。
- 官方推荐cluster集群模式,水平扩容也方便。
二、redis cluster简介
- redis 3.0版本之前,只支持单例模式,在3.0版本之后才支持集群
- redis集群采用P2P模式,是完全去中心化的,不存在中心节点或者代理节点
- redis集群是没有统一的入口的,客户端连接集群中的任意节点即可,集群内部的节点是相互通信的(Gossip通信协议, PING-PONG机制),每个节点都是一个redis实例
- 为了实现集群的高可用,即判断节点是否健康,redis cluster有这么一个投票容错机制:如果集群中找过半数的节点投票认为某节点挂了,那么该节点就挂了(fail)。
- 如何判断机器是否挂了呢: 如果集群中任意一个主节点挂了,而该节点又没有从节点(备份节点),那么这个集群就挂了。
- 为什么任意一个主节点挂了(又没有对应的从节点)这个集群就挂了呢:是因为集群内置了16384(0~16383)个slot(哈希槽),并且把所有的物理节点映射到了这16384个slot上,或者说把这些slot均等的分配给了各个节点。
- 当需要redis集群存放一个数据(key-value)时,redis会先对这个key进行crc16算法,然后得到一个结果
- 再把这个结果对16384进行取余,这个余数会对应到(0~16383)其中一个槽,进而决定key-value存储在哪个节点中
- 所以一旦某个主节点(又没有从节点)挂了,该节点的slot就无法使用了,那么就会导致集群无法正常工作
- redis集群至少需要3个主节点:因为投票容错机制要求超过半数节点认为某节点挂了该节点才是挂了,所以2个节点服务构建集群。
- redis集群至少需要6台服务器
- 因为要保证集群的高可用,需要每个主节点都有至少一个从节点(备份节点)
- 如果手上没那么多服务,也可以采用伪分布式集群搭法,即一台物理机启动多个redis实例
三、redis cluster搭建
目前手头上只有3台物理机, 所以采取每台服务器开启2台实例构建基础主从。
服务器:ubuntu 20.04
redis:6.2.6
地址规划与结构图:
redis物理节点部署.png简单说明:
- 每台物理机器有一个主节点(端口6379)
- 每个主节点的从节点在其他物理机上(端口为6380),避免一台物理机挂掉之后,整个redis集群都不好使了
开始搭建
分别修改3台物理机的/etc/hosts
文件,添加如下内容
192.168.100.101 node1
192.168.100.102 node2
192.168.100.103 node3
在node1(192.168.100.101)上进行操作:
# 我们准备把redis放在/opt/redis-cluster目录下
# 创建目录
mkdir /opt/redis-cluster
# 切换目录
cd /opt/redis-cluster
# 下载redis源码
wget https://download.redis.io/releases/redis-6.2.6.tar.gz
# 解压
tar -xavf redis-6.2.6.tar.gz
cd redis-6.2.6
# 如果需要,安装编辑工具make, gcc
apt install make
apt install gcc
# 编译,注意:如果不加MALLOC=libc,会报fatal error: jemalloc/jemalloc.h: 没有那个文件或目录
make MALLOC=libc
# 安装, 安装后redis命令会放在/usr/local/bin目录下
make install
# 为redis 创建配置目录
mkdir -p /opt/redis-cluster/redis_63{79,80}/{conf,pid,logs}
修改redis_6379配置:vim /opt/redis-cluster/redis_6379/conf/redis.cnf
# 守护进行模式启动
daemonize yes
# 设置数据库数量,默认数据库为0
databases 16
# 绑定地址,需要修改
bind 192.168.100.101
# 绑定端口,需要修改
port 6379
# pid文件存储位置,文件名需要修改
pidfile /opt/redis-cluster/redis_6379/pid/redis_6379.pid
# log文件存储位置,文件名需要修改
logfile /opt/redis-cluster/redis_6379/logs/redis_6379.log
# RDB快照备份文件名,文件名需要修改
dbfilename redis_6379.rdb
# 本地数据库存储目录,需要修改
dir /opt/redis-cluster/redis_6379
# 集群相关配置
# 是否以集群模式启动
cluster-enabled yes
# 集群节点回应最长时间,超过该时间被认为下线
cluster-node-timeout 15000
# 生成的集群节点配置文件名,文件名需要修改
cluster-config-file nodes_6379.conf
修改redis_6380配置:vim /opt/redis-cluster/redis_6380/conf/redis.cnf
, 将上边配置文件中的79替换为80即可。
在node2和node3做同样的操作,或者直接吧node1上的redis-cluster目录拷贝到另外两台上
启动集群
每个节点上执行以下2条命令进行服务启动:
$ redis-server /opt/redis-cluster/redis_6379/conf/redis.cnf
$ redis-server /opt/redis-cluster/redis_6380/conf/redis.cnf
集群模式启动,进程后会加上[cluster]的字样:
root@node1:~$ ps -ef | grep redis
root 9422 1 0 16:33 ? 00:00:07 redis-server 192.168.100.101:6380 [cluster]
root 15148 1 0 17:45 ? 00:00:06 redis-server 192.168.100.101:6379 [cluster]
root 16125 9116 0 21:32 pts/1 00:00:00 grep --color=auto redis
加入集群
现在虽然说每个服务都成功启动了,但是彼此之间并没有任何联系。
所以下一步要做的就是将6个服务加入至一个集群中,如下操作示例(在任意节点执行都行):
$ redis-cli -h node1 -p 6379
node1:6379> cluster meet 192.168.0.102 6379
node1:6379> cluster meet 192.168.0.103 6379
node1:6379> cluster meet 192.168.0.101 6380
node1:6379> cluster meet 192.168.0.102 6380
node1:6379> cluster meet 192.168.0.103 6380
CLUSTER MEET
命令被用来连接不同的开启集群支持的 Redis 节点,以进入工作集群。
查看当前集群所有的节点:
node1:6379> cluster nodes
05a31e3aeaea4d6da847dfcd2fbae82c3d122133 192.168.100.102:6380@16380 master - 0 1646818185880 4 connected
2e2271a5c0144d037a7888fb0ca42362a9e7f429 192.168.100.102:6379@16379 master - 0 1646818184000 1 connected
fd78fc80e90d469cb1347db82cce5f707f095845 192.168.100.103:6379@16379 master - 0 1646818185000 0 connected
3de43ea30f65fad909f0e5647028af2f35c360c2 192.168.100.101:6380@16380 master - 0 1646818182841 3 connected
e0867a4bca1758c7bcc9caa8f8a1c4ce4675ea51 192.168.100.103:6380@16380 master - 0 1646818186882 5 connected
9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0 192.168.100.101:6379@16379 myself,master - 0 1646818185000 2 connected
主从配置
6个服务之间并没有任何主从关系,所以现在进行主从配置,记录下上面cluster nodes命令输出的node-id信息,只记录主节点
hostname | 节点 | node-id |
---|---|---|
node1 | 192.168.0.101:6379 | 9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0 |
node2 | 192.168.0.102:6379 | 2e2271a5c0144d037a7888fb0ca42362a9e7f429 |
node3 | 192.168.0.103:6379 | fd78fc80e90d469cb1347db82cce5f707f095845 |
首先是node1的6380,将它映射到node2的6379:
root@node1:~$ redis-cli -h node1 -p 6380
node1:6380> CLUSTER REPLICATE 2e2271a5c0144d037a7888fb0ca42362a9e7f429
OK
node1:6380>exit
然后是node2的6380,将它映射到node3的6379:
root@node1:~$ redis-cli -h node2 -p 6380
node2:6380> CLUSTER REPLICATE fd78fc80e90d469cb1347db82cce5f707f095845
OK
node2:6380>exit
最后是node3的6380,将它映射到node1的6379:
root@node1:~$ redis-cli -h node3 -p 6380
node3:6380> CLUSTER REPLICATE 9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0
OK
node3:6380>exit
查看集群节点信息,
b-slaver2:6380> CLUSTER NODES
9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0 192.168.100.101:6379@16379 master - 0 1646818480000 2 connected
05a31e3aeaea4d6da847dfcd2fbae82c3d122133 192.168.100.102:6380@16380 slave fd78fc80e90d469cb1347db82cce5f707f095845 0 1646818479177 0 connected
3de43ea30f65fad909f0e5647028af2f35c360c2 192.168.100.101:6380@16380 slave 2e2271a5c0144d037a7888fb0ca42362a9e7f429 0 1646818478171 1 connected
e0867a4bca1758c7bcc9caa8f8a1c4ce4675ea51 192.168.100.103:6380@16380 myself,slave 9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0 0 1646818475000 2 connected
fd78fc80e90d469cb1347db82cce5f707f095845 192.168.100.103:6379@16379 master - 0 1646818478000 0 connected
2e2271a5c0144d037a7888fb0ca42362a9e7f429 192.168.100.102:6379@16379 master - 0 1646818480182 1 connected
分配槽位
接下来我们要开始分配槽位了,为了考虑今后的写入操作能分配均匀,槽位也要进行均匀分配。
仅在Master上进行分配,从库不进行分配,仅做主库的备份和读库使用。
槽位分配情况如下,槽位号从0开始,到16383结束,共16384个槽位,均匀分配:
节点 | 槽位数量 |
---|---|
node1:6379 | 0 - 5461 |
node2:6379 | 5462 - 10922 |
node3:6379 | 10923 - 16383 |
开始分配:
$ redis-cli -h node1 -p 6379 cluster addslots {0..5461}
$ redis-cli -h node2 -p 6379 cluster addslots {5462..10922}
$ redis-cli -h node3 -p 6379 cluster addslots {10923..16383}
检查槽位是否分配正确
node1:6379> CLUSTER NODES
05a31e3aeaea4d6da847dfcd2fbae82c3d122133 192.168.100.245:6380@16380 slave fd78fc80e90d469cb1347db82cce5f707f095845 0 1646818753000 0 connected
2e2271a5c0144d037a7888fb0ca42362a9e7f429 192.168.100.245:6379@16379 master - 0 1646818751296 1 connected 5462-10922
fd78fc80e90d469cb1347db82cce5f707f095845 192.168.100.246:6379@16379 master - 0 1646818752299 0 connected 10923-16383
3de43ea30f65fad909f0e5647028af2f35c360c2 192.168.100.109:6380@16380 slave 2e2271a5c0144d037a7888fb0ca42362a9e7f429 0 1646818754302 1 connected
e0867a4bca1758c7bcc9caa8f8a1c4ce4675ea51 192.168.100.246:6380@16380 slave 9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0 0 1646818755306 2 connected
9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0 192.168.100.109:6379@16379 myself,master - 0 1646818751000 2 connected 0-5461
检查状态
使用以下命令检查集群状态是否ok,如果槽位全部分配完毕应该是ok,不然的话就检查你分配槽位时是否输错了数量:
$ redis-cli -h node1 -p 6379
node1:6379> CLUSTER info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:5
cluster_my_epoch:5
cluster_stats_messages_ping_sent:2825
cluster_stats_messages_pong_sent:2793
cluster_stats_messages_meet_sent:5
cluster_stats_messages_sent:5623
cluster_stats_messages_ping_received:2793
cluster_stats_messages_pong_received:2830
cluster_stats_messages_received:5623
读写测试
$ redis-cli -c -h node1 -p 6379
node1:6379> set k1 "v1"
-> Redirected to slot [12706] located at 192.168.0.140:6379
OK
注意:-c参数无所谓你的Redis是否是集群模式, 如果不加-c会报(error) MOVED...
一并对主从进行验证,这条数据是写入至了node3的Master中,我们登录node2的Slaver中进行查看:
$ redis-cli -h node2 -p 6380 -c
node2:6380> keys *
1) "k1"
故障转移
模拟node1的6379下线宕机,此时应该由node3的6380接管它的工作
$ redis-cli -h node1 -p 6379 shutdown
登录集群任意节点查看目前的集群节点信息:
root@node1:~$ redis-cli -c -h node2 -p 6380
node2:6380> CLUSTER NODES
9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0 192.168.100.101:6379@16379 master,fail - 1646819034665 1646819031000 2 disconnected
3de43ea30f65fad909f0e5647028af2f35c360c2 192.168.100.101:6380@16380 slave 2e2271a5c0144d037a7888fb0ca42362a9e7f429 0 1646819090108 1 connected
fd78fc80e90d469cb1347db82cce5f707f095845 192.168.100.103:6379@16379 master - 0 1646819089100 0 connected 10923-16383
e0867a4bca1758c7bcc9caa8f8a1c4ce4675ea51 192.168.100.103:6380@16380 master - 0 1646819089000 6 connected 0-5461
2e2271a5c0144d037a7888fb0ca42362a9e7f429 192.168.100.102:6379@16379 master - 0 1646819089000 1 connected 5462-10922
05a31e3aeaea4d6da847dfcd2fbae82c3d122133 192.168.100.102:6380@16380 myself,slave fd78fc80e90d469cb1347db82cce5f707f095845 0 1646819088000 0 connected
恢复工作
重启node1的6379:
$ redis-server /opt/redis-cluster/redis_6379/conf/redis.cnf
登录node1的6379,发现他已经自动的进行上线了,并且作为node3中6380的从库:
root@b-master:~# redis-cli -c -h node2 -p 6380
node2:6380> CLUSTER NODES
9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0 192.168.100.101:6379@16379 slave e0867a4bca1758c7bcc9caa8f8a1c4ce4675ea51 0 1646819155000 6 connected
3de43ea30f65fad909f0e5647028af2f35c360c2 192.168.100.101:6380@16380 slave 2e2271a5c0144d037a7888fb0ca42362a9e7f429 0 1646819155573 1 connected
fd78fc80e90d469cb1347db82cce5f707f095845 192.168.100.103:6379@16379 master - 0 1646819155000 0 connected 10923-16383
e0867a4bca1758c7bcc9caa8f8a1c4ce4675ea51 192.168.100.103:6380@16380 master - 0 1646819156578 6 connected 0-5461
2e2271a5c0144d037a7888fb0ca42362a9e7f429 192.168.100.102:6379@16379 master - 0 1646819155000 1 connected 5462-10922
05a31e3aeaea4d6da847dfcd2fbae82c3d122133 192.168.100.102:6380@16380 myself,slave fd78fc80e90d469cb1347db82cce5f707f095845 0 1646819153000 0 connected
四、常见问题
-
如果一组主从宕机,集群是否可用
- 之前说一个节点挂掉,又没有从节点,那么集群不可用(默认为yes)
- 如果修改下边的配置属性,则宕机的1组不可用,而其他组的机器可以用
- 往1组保存数据,失败,导致数据丢失
- 往2组或3组保存数据,正常运行
# cluster-require-full-coverage yes
网友评论