为什么要有集群
单个Redis存在不稳定性,当Redis服务宕机或硬盘故障,系统崩溃之后,就没有可用的服务了,还会造成数据的丢失
单个Redis的读写能力也是有限的
| 概念
通过添加服务器的数量,提供相同的服务,从而让服务器达到一个稳定,高效的状态
| 三种模式
-
主从模式
-
哨兵模式
-
Cluster模式
主从模式介绍
| 为什么要用主从复制
单机redis的风险与问题
问题一:机器故障
-
硬盘故障,系统崩溃
-
本质:数据丢失,可能对业务造成灾难性打击
问题二:容量瓶颈
-
内存不足,一台redis内存是有限的
解决方案:
为了避免单点Redis服务器故障,准备多台服务器,互相联通,将数据复制多个副本保存在不同服务器上,连接在一起,并保证数据是同步的,即使有其中一台服务器宕机,其他服务器依然可以继续提供服务,实现Redis的高可用,同时实现数据冗余备份
| 工作原理
如上图所示,是Redis的工作原理,其对应的文字说明如下:
-
replica库通过”SLAVEOF 172.200.1.201 6379″命令连接master库并发送”SYNC”给master
-
master库收到”SYNC”,会立即触发”BGSAVE”后台保存RDB快照,并将RDB快照发送给replica库;
-
replica库接收后会应用RDB快照;
-
master库会陆续将中间产生的新的操作保存并发送给replica库;
-
到此我们master复制集就正常工作了;
-
再此以后,master库只要发生新的操作,都会以命令传播的形式自动发送给replica库;
-
所有复制相关信息,从info信息中都可以查到,即使重启任何节点,他的master-replica关系依然都在;
-
如果发生master-replica关系断开时,replica库数据没有任何损坏,在下次重连之后,replica库发送”PSYNC
-
master库只会将replica库缺失部分的数据同步给replica库应用,达到快速恢复master-replica架构的目的;
温馨提示:(可能面试时会问到):
-
在Redis 2.8版本之前,如果master-replica架构中replica库宕机将会再次触发”SYNC”,从而全量拷贝主库的数据,这样效率明显很低
于是在Redis 2.8版本之后就新增了”PSYNC”指令以实现可以理解为”断点续传”的功能
-
生产环境中,建议开启master库持久化功能,避免因主库意外重启而导致缓存丢失
举个例子,master库右1w条数据,replica库在某一时刻仅有9k数据,还有1k数据未来得及同步master库时,master库意外重启导致KEY为0,此时replica库同步master库数据会将replica库已有的9k缓存数据删除以达到和master库同步的目的
哨兵模式介绍
哨兵(sentinel)是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master
| 为什么有哨兵
主机宕机,如何能够高可用的恢复正常,不用人为进行干预
作用:
-
监控:不断地检查master和slave是否正常运行;master存活检测,master与slave运行清空检测
-
通知(提醒):当被监控地服务器出现问题时,向其他(哨兵、客户端)发送通知
-
自动故障转移:断开master与slave连接,选取一个slave作为master,将其他slave连接到新地master,并告知客户端新地服务器地址
注意:
-
哨兵也是一台redis服务器,只是不提供数据服务
-
通常哨兵配置数量为单数
Cluster模式介绍
redis最开始使用主从模式做集群,若master宕机需要手动配置slave转为master
后来为了高可用提出来哨兵模式,该模式下有一个哨兵监视master和slave,若master宕机可自动将slave转为master,但它也有一个问题,就是不能动态扩充,哨兵模式还是只有一个master
所以在3.x提出cluster集群模式
| 工作原理
Redis数据分片原理说明:
-
redis会有多组分片构成,本篇笔记实验环境是3组;
-
redis cluster使用固定个数的slot存储数据,一共16384是slot;
-
每组分片分得1/3 slot个数,分别为”0-5460,5461-10921,10922-16383″
-
基于CRC16(key) % 16384公式会得到一个”槽位号”(该编号范围在”0-16383″之间);
-
根据计算得出的槽位值,找到相对应的分片节点的主节点,存储到相应槽位上;
-
如果客户端当时连接的节点不是将来要存储的分片节点,分片集群会将客户端连接切换至真正存储节点进行数据存储;
综上所述,我们来举个例子,在Redis分布式集群中,假设我们执行了”SET name oldboy”这一条指令,那么数据该如何存储的呢?其大致的存储逻辑如下:
-
使用”CRC16(KEY_NAME)”进行校验计算一个值,假设”CRC16(name)”的计算结果为”1234567890″;
-
再使用”CRC16(KEY_NAME)%16384″进行计算,从而得出该KEY_NAME被分配到哪个slot上,假设结果为”1234567890%16384=722″,就表示数据被落到slot=722的分片上;
-
而slot=722恰好在第一个分片上,因为我们第一个分片的slot范围就是”0-5460″
主从模式部署
| 为各个Redis实例创建数据和配置文件目
# 创建Redis的数据存储目录
mkdir -pv /oldboyedu/data/redis1637{0..2}
# 创建Redis的配置文件存储目录
mkdir -pv /oldboyedu/softwares/redis1637{0..2}
| 为各个Redis实例创建配置文件
1)为”redis16370″实例创建配置文件
# cat > /oldboyedu/softwares/redis16370/redis.conf <<EOF
port 16370
daemonize yes
pidfile /oldboyedu/data/redis16370/redis.pid
loglevel notice
logfile /oldboyedu/data/redis16370/redis.log
dbfilename dump.rdb
dir /oldboyedu/data/redis16370
bind 172.200.1.201 127.0.0.1
requirepass oldboyedu
masterauth oldboyedu
# 配置RDB持久化策略
save 900 1
save 300 10
save 60 10000
# 配置AOF持久化
appendonly yes
appendfsync everysec
EOF
2)为”redis16371″实例创建配置文件
# cat > /oldboyedu/softwares/redis16371/redis.conf <<EOF
port 16371
daemonize yes
pidfile /oldboyedu/data/redis16371/redis.pid
loglevel notice
logfile /oldboyedu/data/redis16371/redis.log
dbfilename dump.rdb
dir /oldboyedu/data/redis16371
bind 10.0.0.112 127.0.0.1
requirepass oldboyedu
masterauth oldboyedu
# 配置RDB持久化策略
save 900 1
save 300 10
save 60 10000
# 配置AOF持久化
appendonly yes
appendfsync everysec
EOF
3)为”redis16372″实例创建配置文件
cat > /oldboyedu/softwares/redis16372/redis.conf <<EOF
port 16372
daemonize yes
pidfile /oldboyedu/data/redis16372/redis.pid
loglevel notice
logfile /oldboyedu/data/redis16372/redis.log
dbfilename dump.rdb
dir /oldboyedu/data/redis16372
bind 10.0.0.112 127.0.0.1
requirepass oldboyedu
masterauth oldboyedu
# 配置RDB持久化策略
save 900 1
save 300 10
save 60 10000
# 配置AOF持久化
appendonly yes
appendfsync everysec
EOF
温馨提示:
-
所有的requirepass建议设置为一致,这为我们”哨兵模式”做准备,很明显,”requirepass”表示配置当前实例的验证口令;
-
注意”masterauth”表示的含义是主库的验证口令;下面的模板你可以根据自己业务的实际需求进行改动即可
cat > /oldboyedu/softwares/redis16372/redis.conf <<EOF
port 16372
daemonize yes
pidfile /oldboyedu/data/redis16372/redis.pid
loglevel notice
logfile /oldboyedu/data/redis16372/redis.log
dbfilename dump.rdb
dir /oldboyedu/data/redis16372
bind 10.0.0.112 127.0.0.1
requirepass oldboyedu
masterauth oldboyedu
# 配置RDB持久化策略
save 900 1
save 300 10
save 60 10000
# 配置AOF持久化
appendonly yes
appendfsync everysec
EOF
| 启动各个Redis实例
1)启动各个Redis实例
redis-server /oldboyedu/softwares/redis16370/redis.conf
redis-server /oldboyedu/softwares/redis16371/redis.conf
redis-server /oldboyedu/softwares/redis16372/redis.conf
# 执行 ss -lnt 查看是否启动
ss -lnt
2)停止各个Redis实例运行,此步骤可跳过,因为我们暂时还不需要停止Redis,我们要用Redis实例做主从架构
redis-cli -p 16370 -a oldboyedu shutdown
redis-cli -p 16371 -a oldboyedu shutdown
redis-cli -p 16372 -a oldboyedu shutdown
| 开启Redis的主从
实验说明:以 redis16370 实例为主库,以 redis16371 实例和 redis16372 实例为从库
# 从库实例开启主从
redis-cli -p 16371 -a oldboyedu SLAVEOF 10.0.0.112 16370
redis-cli -p 16372 -a oldboyedu SLAVEOF 10.0.0.112 16370
| 主库实例查看主从信息
redis-cli -p 16370 -a oldboyedu INFO REPLICATION
| 从库实例查看主从信息
在 “redis16371” 实例中查看主从状态信息:
信息
redis-cli -p 16371 -a oldboyedu INFO REPLICATION
在 “redis16372” 实例中查看主从状态信息:
redis-cli -p 16372 -a oldboyedu INFO REPLICATION
| 验证主从配置是否生效
在”redis16370″实例主库的11号数据库创建测试数据
# redis-cli -p 16370 -a oldboyedu -n 11
16370[11]> KEYS *
(empty array)
16370[11]> SET name oldboyedu
OK
16370[11]> SET age 18
OK
16370[11]> KEYS *
1) "name"
2) "age"
16370[11]> QUIT
在”redis16371″实例从库的11号数据库查看是否同步主库的11号数据库
# redis-cli -p 16371 -a oldboyedu -n 11
16371[11]> KEYS *
1) "name"
2) "age"
16371[11]> GET name
"oldboyedu"
16371[11]> GET age
"18"
16371[11]> QUIT
在”redis16372″实例从库的11号数据库查看是否同步主库的11号数据库
# redis-cli -p 16372 -a oldboyedu -n 11
16371[11]> KEYS *
1) "name"
2) "age"
16371[11]> GET name
"oldboyedu"
16371[11]> GET age
"18"
16371[11]> QUIT
| 解除”redis16372″实例的主从关系
redis-cli -p 16372 -a oldboyedu SLAVEOF NO ONE
| 跨节点部署Redis集群实战案例
(0)主从架构设计
主库为:
10.0.0.108
从库:
10.0.0.106
10.0.0.107
(1)10.0.0.106的配置
install -d /oldboyedu/data/redis
cat > /oldboyedu/softwares/redis/conf/redis.conf <<EOF
port 8106
daemonize yes
pidfile /oldboyedu/data/redis/redis.pid
loglevel notice
logfile /oldboyedu/data/redis/redis.log
dbfilename oldboyedu_linux.rdb
dir /oldboyedu/data/redis/
bind 10.0.0.106
requirepass oldboyedu
masterauth oldboyedu
# 配置RDB持久化策略
save 900 1
save 300 10
save 60 10000
EOF
redis-server /oldboyedu/softwares/redis/conf/redis.conf
(2)10.0.0.107的配置
install -d /oldboyedu/data/redis
cat > /oldboyedu/softwares/redis/conf/redis.conf <<EOF
port 8107
daemonize yes
pidfile /oldboyedu/data/redis/redis.pid
loglevel notice
logfile /oldboyedu/data/redis/redis.log
dbfilename oldboyedu_linux.rdb
dir /oldboyedu/data/redis/
bind 10.0.0.107
requirepass oldboyedu
masterauth oldboyedu
# 配置RDB持久化策略
save 900 1
save 300 10
save 60 10000
EOF
redis-server /oldboyedu/softwares/redis/conf/redis.conf
(3)10.0.0.108的配置
install -d /oldboyedu/data/redis
cat > /oldboyedu/softwares/redis/conf/redis.conf <<EOF
port 8108
daemonize yes
pidfile /oldboyedu/data/redis/redis.pid
loglevel notice
logfile /oldboyedu/data/redis/redis.log
dbfilename oldboyedu_linux.rdb
dir /oldboyedu/data/redis/
bind 10.0.0.108
requirepass oldboyedu
masterauth oldboyedu
# 配置RDB持久化策略
save 900 1
save 300 10
save 60 10000
EOF
redis-server /oldboyedu/softwares/redis/conf/redis.conf
(4)从库开启主从
# 10.0.0.106:
redis-cli -p 8106 -h 10.0.0.106 -a oldboyedu SLAVEOF 10.0.0.108 8108
# 10.0.0.107:
redis-cli -p 8107 -h 10.0.0.107 -a oldboyedu SLAVEOF 10.0.0.108 8108
哨兵模式部署
| 准备3个Redis实例
(可以直接基于上一节搭建的主从复制环境即可)
| 创建sentinel的配置文件,数据,日志存储目录
mkdir /oldboyedu/softwares/redis16379
cat > /oldboyedu/softwares/redis16379/sentinel.conf <<EOF
bind 10.0.0.112 127.0.0.1
port 16379
dir /oldboyedu/data/redis16379
sentinel monitor oldboyedu_master 10.0.0.112 16370 1
sentinel down-after-milliseconds oldboyedu_master 5000
sentinel auth-pass oldboyedu_master oldboyedu
EOF
配置文件参数说明如下:
| 启动sentinel进程并查看日志
启动sentinel进程
redis-sentinel /oldboyedu/softwares/redis16379/sentinel.conf &> /oldboyedu/logs/redis16379/sentinel.log &
查看日志信息
tail -100f /oldboyedu/logs/redis16379/sentinel.log
| 手动停止主库运行,模拟主库宕机
手动将主库宕机,观察从库被sentinel实现了自动切换
redis-cli -p 16370 -a oldboyedu SHUTDOWN
# 由于我们将主库服务停了,因此无法再次连接主库了
redis-cli -p 16370 -a oldboyedu INFO REPLICATION
redis-cli -p 16371 -a oldboyedu INFO REPLICATION
查看sentinel的日志信息,不难发现有记录切换的过程,如下所示
tail -100f /oldboyedu/logs/redis16379/sentinel.log
| 手动修复宕机的主库,sentinel会自动发现
修复之后,之前宕机的主库会自动加入集群并成为slaves节点
redis-server /oldboyedu/softwares/redis16370/redis.conf
redis-cli -p 16370 -a oldboyedu INFO REPLICATION
温馨提示:除了提到上面的变化外,还有一点变化就是配置文件也修改了,每个”slave”节点都新增了以下两行:
(本案例只有”redis16370″和”redis16372″这两个实例的配置文件是slave节点,因此这两个节点中是存在的!)
# tail -3 /oldboyedu/softwares/redis16370/redis.conf
# Generated by CONFIG REWRITE
user default on #4208512d2963b999e0ef7a467cb42671c30be4d629ec75536a0eb6db15ee0d90 ~* &* +@all
replicaof 10.0.0.112 16371
# tail -3 /oldboyedu/softwares/redis16372/redis.conf
# Generated by CONFIG REWRITE
user default on #4208512d2963b999e0ef7a467cb42671c30be4d629ec75536a0eb6db15ee0d90 ~* &* +@all
replicaof 10.0.0.112 16371
Cluster模式部署
| 实验环境说明
在生产环境中,如果部署6个redis实例,一般会放到3台硬件服务器
在企业规划中,一个分片被分配到两个不同的物理机,防止硬件主机宕机造成的整个分片数据丢失
温馨提示:
本案例为了实验方便,就直接将6个Redis实例放在同一个节点上,对应的端口号为:63790-63795
| 创建多Redis实例使用的配置文件,数据,日志目录
mkdir -pv /oldboyedu/softwares/redis1000{0..5}
mkdir -pv /oldboyedu/data/redis1000{0..5}
mkdir -pv /oldboyedu/logs/redis1000{0..5}
| 为各个Redis实例创建配置文件
# 创建"redis10000"实例的配置文件
cat > /oldboyedu/softwares/redis10000/redis.conf <<EOF
port 10000
daemonize yes
pidfile /oldboyedu/data/redis10000/redis.pid
loglevel notice
logfile /oldboyedu/logs/redis10000/redis.log
dbfilename dump.rdb
dir /oldboyedu/data/redis10000
bind 10.0.0.112 127.0.0.1
# 配置RDB持久化策略
save 900 1
save 300 10
save 60 10000
# 配置AOF持久化
appendonly yes
appendfsync everysec
# 配置Redis Cluster模式
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
EOF
# 创建"redis10001"实例的配置文件
cat > /oldboyedu/softwares/redis10001/redis.conf <<EOF
port 10001
daemonize yes
pidfile /oldboyedu/data/redis10001/redis.pid
loglevel notice
logfile /oldboyedu/logs/redis10001/redis.log
dbfilename dump.rdb
dir /oldboyedu/data/redis10001
bind 10.0.0.112 127.0.0.1
# 配置RDB持久化策略
save 900 1
save 300 10
save 60 10000
# 配置AOF持久化
appendonly yes
appendfsync everysec
# 配置Redis Cluster模式
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
EOF
# 创建"redis10002"实例的配置文件
cat > /oldboyedu/softwares/redis10002/redis.conf <<EOF
port 10002
daemonize yes
pidfile /oldboyedu/data/redis10002/redis.pid
loglevel notice
logfile /oldboyedu/logs/redis10002/redis.log
dbfilename dump.rdb
dir /oldboyedu/data/redis10002
bind 10.0.0.112 127.0.0.1
# 配置RDB持久化策略
save 900 1
save 300 10
save 60 10000
# 配置AOF持久化
appendonly yes
appendfsync everysec
# 配置Redis Cluster模式
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
EOF
# 创建"redis10003"实例的配置文件
cat > /oldboyedu/softwares/redis10003/redis.conf <<EOF
port 10003
daemonize yes
pidfile /oldboyedu/data/redis10003/redis.pid
loglevel notice
logfile /oldboyedu/logs/redis10003/redis.log
dbfilename dump.rdb
dir /oldboyedu/data/redis10003
bind 10.0.0.112 127.0.0.1
# 配置RDB持久化策略
save 900 1
save 300 10
save 60 10000
# 配置AOF持久化
appendonly yes
appendfsync everysec
# 配置Redis Cluster模式
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
EOF
# 创建"redis10004"实例的配置文件
cat > /oldboyedu/softwares/redis10004/redis.conf <<EOF
port 10004
daemonize yes
pidfile /oldboyedu/data/redis10004/redis.pid
loglevel notice
logfile /oldboyedu/logs/redis10004/redis.log
dbfilename dump.rdb
dir /oldboyedu/data/redis10004
bind 10.0.0.112 127.0.0.1
# 配置RDB持久化策略
save 900 1
save 300 10
save 60 10000
# 配置AOF持久化
appendonly yes
appendfsync everysec
# 配置Redis Cluster模式
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
EOF
# 创建"redis10005"实例的配置文件
cat > /oldboyedu/softwares/redis10005/redis.conf <<EOF
port 10005
daemonize yes
pidfile /oldboyedu/data/redis10005/redis.pid
loglevel notice
logfile /oldboyedu/logs/redis10005/redis.log
dbfilename dump.rdb
dir /oldboyedu/data/redis10005
bind 10.0.0.112 127.0.0.1
# 配置RDB持久化策略
save 900 1
save 300 10
save 60 10000
# 配置AOF持久化
appendonly yes
appendfsync everysec
# 配置Redis Cluster模式
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
EOF
配置参数说明:
温馨提示:
-
Redis的端口号范围在10000~55535之间。这是因为当我们启动各个redis实例后,会监听在对应redis实例的端口上加10000;
-
由于上面我使用了”protected-mode no”指令,表示不开启安全模式,如果设置为”YES”,尽管配置了”requirepass”和”masterauth”这两个配置项,我们在将redis节点加入到集群时依旧会报错哟!
-
Redis cluster模式无需像redis sentinel模式那样有一个专门的监控模式;
| 启动各个Redis实例
redis-server /oldboyedu/softwares/redis10000/redis.conf
redis-server /oldboyedu/softwares/redis10001/redis.conf
redis-server /oldboyedu/softwares/redis10002/redis.conf
redis-server /oldboyedu/softwares/redis10003/redis.conf
redis-server /oldboyedu/softwares/redis10004/redis.conf
redis-server /oldboyedu/softwares/redis10005/redis.conf
| 将节点加入集群管理
redis-cli --cluster create 10.0.0.112:10000 10.0.0.112:10001 10.0.0.112:10002 10.0.0.112:10003 10.0.0.112:10004 10.0.0.112:10005 --cluster-replicas 1
注意:这里需要自己手动输入yes,如果超时了还没有输入,则会自动退出,需要再次创建!
看到以下信息说明创建redis缓存库成功:
| 查看集群的状态
# 查看集群的状态
redis-cli -p 10005 CLUSTER NODES
# 查看master节点的状态
redis-cli -p 10005 CLUSTER NODES | grep "master"
# 查看slave节点的状态
redis-cli -p 10005 CLUSTER NODES | grep "slave"
每项的含义如下:
各flags的含义 (上面所说数据项3):
温馨提示:
-
如果有”myself”字样,说明你正在连接的是哪个节点;
-
注意观察槽位编号信息,比如”10.0.0.112:10000 master”被分配到的槽位号是”0-5460″,而”10.0.0.112:10001″被分配到的槽位号是”5461-10922″,”10.0.0.112:10002 master”被分配到的槽位号是”10923-16383″;
-
每个redis实例都有其独有的id编号,比如”10.0.0.112:10000 master”的编号为”eefe41adf0a9dc823ef56183881bfa14f10571b9″,这有点类似于MySQL的”server_uuid”;
总结
在本教程中,我们通过一些示例学习了如何去部署Redis的三种集群
感谢您的阅读,由于文档整理较费时费力,难免会有疏漏和不妥当地方,敬请谅解
原文始发于微信公众号(运维基地):【Linux运维】Redis集群的三种方式
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/23534.html