Redis 高级部分
一、主从复制
image.pngRdis 的主从复制特点
image.png1. 配置主从
实现方式同样有两种: 命令方式和配置文件方式
命令方式
只需要在从服务器上执行如下命令即可
slaveof 主服务器的IP 端口号
slaveof
命令是异步的,不阻塞。
并且此时,从服务器现有的数据会先被清空,之后再同步主服务器的数据。
停止一台从服务器的复制操作,在此台服务器上执行如下命令
slaveof no one
配置文件的方式如下
只需要在从服务器上配置即可
修改配置文件
假如主服务器 IP 是: 172.16.153.178
端口是: 6379
# slaveof <masterip> <masterport>
slaveof 172.16.153.178 6379
// 配置此服务器只提供读取操作
slave-read-only yes
之后重启从主机的 Redis 服务
查看主从信息
127.0.0.1:6379> info replication
二、主从 + Sentinel
哨兵模式
Redis Sentinel是Redis官方的高可用性解决方案。
Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务:
-
监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
-
提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
-
自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
Redis Sentinel 是一个分布式系统, 你可以在一个架构中运行多个 Sentinel 进程(progress), 这些进程使用流言协议(gossip protocols)来接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移, 以及选择哪个从服务器作为新的主服务器。
虽然 Redis Sentinel 释出为一个单独的可执行文件 redis-sentinel , 但实际上它只是一个运行在特殊模式下的 Redis 服务器。
此种模式下,客户端要访问的 服务 IP 不是主节点,而是 sentiner
服务器的 IP。
架构图
image.pngRedis Sentinel 故障转移
image.png架构的扩展应用
image.png1. 配置主从
a. 快速生成主节点的配置文件
编译全新文件 /etc/redis/redis-6380.conf
, 添加如下内容
port 6380
daemonize yes
protected-mode no
pidfile /var/run/redis-6380.pid
logfile /var/log/redis-6380.log
dir /redis/data/
假如是多个主机实现的,就需要更改为
protected-mode yes
,
并且添加bind 0.0.0.0
b. 快速生成从节点的配置文件
[root@s1 ~]# sed 's/6380/6381/g' /etc/redis/redis-6380.conf > /etc/redis/redis-6381.conf
[root@s1 ~]# sed 's/6380/6382/g' /etc/redis/redis-6380.conf > /etc/redis/redis-6382.conf
查看配置文件内容,检验配置结果
[root@s1 ~]# cat /etc/redis/redis-6381.conf
port 6381
daemonize yes
pidfile /var/run/redis-6381.pid
logfile /var/log/redis-6381.log
dir /redis/data/
[root@s1 ~]# cat /etc/redis/redis-6382.conf
port 6382
daemonize yes
pidfile /var/run/redis-6382.pid
logfile /var/log/redis-6382.log
dir /redis/data/
[root@s1 ~]#
c. 配置主从关系
[root@s1 ~]# echo "slaveof 172.16.153.178 6380" >> /etc/redis/redis-6381.conf
[root@s1 ~]# echo "slaveof 172.16.153.178 6380" >> /etc/redis/redis-6382.conf
[root@s1 ~]#
d. 启动服务,并验证进程
[root@s1 ~]# /usr/local/bin/redis-server /etc/redis/redis-6380.conf
[root@s1 ~]# /usr/local/bin/redis-server /etc/redis/redis-6381.conf
[root@s1 ~]# /usr/local/bin/redis-server /etc/redis/redis-6382.conf
[root@s1 ~]# ps -ef |grep redis
root 4335 1 0 19:30 ? 00:00:03 /usr/local/bin/redis-server *:6380
root 4490 1 0 20:17 ? 00:00:00 /usr/local/bin/redis-server *:6381
root 4495 1 0 20:17 ? 00:00:00 /usr/local/bin/redis-server *:6382
root 4500 3755 0 20:17 pts/0 00:00:00 grep --color=auto redis
[root@s1 ~]#
假如日志中出现如下警告信息
4668:S 17 Feb 20:28:42.107 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
4668:S 17 Feb 20:28:42.107 # Server initialized
4668:S 17 Feb 20:28:42.108 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
4668:S 17 Feb 20:28:42.108 * DB loaded from disk: 0.000 seconds
4668:S 17 Feb 20:28:42.110 * Before turning into a slave, using my master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer.
解决办法
The TCP backlog...
方法1: 临时设置生效:
shell> sysctl -w net.core.somaxconn=1024
方法2: 永久生效:
修改/etc/sysctl.conf文件,增加一行
net.core.somaxconn=1024
然后执行命令
sysctl -p
WARNING overcommit_memory ...
方法1: 临时设置生效:
shell> sysctl -w vm.overcommit_memory=1
方法2: 永久生效:
修改/etc/sysctl.conf文件,增加一行
vm.overcommit_memory=1
然后执行命令
sysctl -p
e. 查看主从复制信息
image.png2. 配置 sentinel
获取程序
Sentinel 程序可以在编译后的 src 文档中发现, 它是一个命名为 redis-sentinel 的程序。
运行一个 Sentinel 所需的最少配置如下所示:
Redis 源码中包含了一个名为 sentinel.conf
的文件, 这个文件是一个带有详细注释的 Sentinel 配置文件示例。
运行一个 Sentinel 所需的最少配置如下所示:
// 监控一个 Redis 服务器
// 名称为 mymaster ,IP 为 127.0.0.1 端口为 6379
// 最后的 2 是指最少有 2 给 Sentinel 实例同意一台 redis 服务器宕机,才会执行故障转义。
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 3000
// 180 秒后开始故障自动装换
sentinel failover-timeout mymaster 5000
sentinel parallel-syncs mymaster 1
各个选项的功能如下:
down-after-milliseconds 选项指定了 Sentinel 认为服务器已经断线所需的毫秒数。
如果服务器在给定的毫秒数之内, 没有返回 Sentinel 发送的 PING 命令的回复, 或者返回一个错误, 那么 Sentinel 将这个服务器标记为主观下线(subjectively down,简称 SDOWN )。不过只有一个 Sentinel 将服务器标记为主观下线并不一定会引起服务器的自动故障迁移: 只有在足够数量的 Sentinel 都将一个服务器标记为主观下线之后, 服务器才会被标记为客观下线(objectively down, 简称 ODOWN ), 这时自动故障迁移才会执行。
将服务器标记为客观下线所需的 Sentinel 数量由对主服务器的配置决定。
parallel-syncs
选项指定了在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步, 这个数字越小, 完成故障转移所需的时间就越长。
a. 获取并修改配置文件
快速创建三个 sentinel 配置文件
进入到 Redis 源码的目录下,执行如下命令
image.png
修改监听端口
image.png之后在每个 sentinel
配置文件中添加守护进程方式运行,
并修改dir
配置项的目录,
daemonize yes
dir /redis/data/
logfile "sentinel-${port}.log"
最后别忘了修改监控的主服务器的 IP 和端口正确的 6380
最终其中一个的配置文件应该是这样的
image.png
b. 启动服务并验证
启动服务的语法:
shell> redis-sentinel sentinel的配置文件
image.png
image.png
可以使用以下命令查看哨兵的信息
[root@s1 ~]# redis-cli -p 27001 info
...略...
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=127.0.0.1:6380,slaves=2,sentinels=3
[root@s1 ~]#
3. 客户端如何连接使用 Sentinel
客户端需要知道所有 Sentinel 所有节点的 IP和一个 Master Name。
第一步从所有的 Sentinel 列表中得到一个有效的 Sentinel 节点。
image.png第二步向得到的 Sentinel 节点发送查询一个已知的 Master Name 的信息到请求,并得到 Master 节点的信息
image.png第三步向 Master 节点验证 Maset 角色的真实性
image.png第四步 客户端 和 Sentiel 之间建立发布订阅关系。
客户端订阅 Sentinel 的频道,一旦 Master 的 IP 信息有变化,客户端就会通过此频道发布的信息得知。
image.png
4. 故障演练
停止 Master 节点的服务
[root@s1 ~]# redis-cli -p 6380 shutdown
不断的刷新其中一个 Sentinel 节点的信息,观察最后一行信息的变化
[root@s1 ~]# redis-cli -p 27001 info
...略...
master0:name=mymaster,status=ok,address=127.0.0.1:6382,slaves=2,sentinels=3
三、 集群
1. 数据分区介绍
image.pnga. 数据分区的方式
image.png两者的对比
image.pngb. 哈希分区的三种方式
-
节点取余
-
一致性哈希
-
虚拟槽哈希
① 节点取余(不推荐使用)
image.png问题: 当向集群重添加一个节点时,数据迁移率太大
迁移前
迁移后
建议添加节点时,采用多倍扩容的方式
多倍扩容② 一致性哈希分区方式
基本规则,顺时针的方式式
image.png
一致性哈希的扩容
扩容前
扩容后
image.png特点总结
image.png③ 虚拟槽分区方式(Redis Cluster 使用了此方式)
虚拟槽的分配
image.png2.Redis 集群的优势
自动分割数据到不同的节点上。
整个集群的部分节点失败或者不可达的情况下能够继续处理命令。
特点
主从复制
实现了高可用
数据分片存储
集群节点的 meet
过程
三个节点
六个节点
指派槽
image.png客户端和槽
image.png3. Redis 集群的安装
原生命令安装
步骤
-
配置开启集群节点
-
配置
meet
-
指派槽
-
配置主从
实例操作
准备两台虚拟机:
一台启动三个 Redis 实例作为 主节点
另一台启动三个 Redis 实例作为 从节点
架构图
集群拓扑图实验步骤
- 先编辑一个集群的配置文件
编译配置文件 /etc/redis/cluster-redis-7001.conf
, 添加如下内容:
bind 0.0.0.0
port 7001
daemonize yes
# 允许任何地址不使用密码访问我
protected-mode no
dir "/redis/data/"
logfile "cluster-7001.log"
dbfilename "cluster-dump-7001.log"
cluster-enabled yes
cluster-config-file nodes-7001.conf
# 不需要集群的全部节点完好才提供服务
cluster-require-full-coverage no
-
再创建其他集群的配置文件
image.png
[root@s1 redis]# sed 's/7001/7002/g' cluster-redis-7001.conf > cluster-redis-7002.conf
[root@s1 redis]# sed 's/7001/7003/g' cluster-redis-7001.conf > cluster-redis-7003.conf
[root@s1 redis]# sed 's/7001/7011/g' cluster-redis-7001.conf > cluster-redis-7011.conf
[root@s1 redis]# sed 's/7001/7012/g' cluster-redis-7001.conf > cluster-redis-7012.conf
[root@s1 redis]# sed 's/7001/7013/g' cluster-redis-7001.conf > cluster-redis-7013.conf
拷贝从节点的配置文件到另外一台主机上
需要保证另一台主机上有目录 /etc/redis/
, 因为这里计划把所有的配置文件放在此目录下
[root@s1 redis]# scp -r cluster-redis-701* root@172.16.153.179:/etc/redis/
- 首先,需要启动主节点的服务进程
[root@s1 ~]# redis-server /etc/redis/cluster-redis-7001.conf
[root@s1 ~]# redis-server /etc/redis/cluster-redis-7002.conf
[root@s1 ~]# redis-server /etc/redis/cluster-redis-7003.conf
- 之后,再启动从节点的服务进程
[root@s2 ~]# mkdir -p /redis/data
[root@s2 ~]# redis-server /etc/redis/cluster-redis-7011.conf
[root@s2 ~]# redis-server /etc/redis/cluster-redis-7012.conf
[root@s2 ~]# redis-server /etc/redis/cluster-redis-7013.conf
检查进程
ps -ef | grep redis-server
假设你现在去连接到任意一个节点上执行操作会返回集群目前是没有启动的信息。
原因是目前集群各节点之间没有进行 meet
操作,都是各自孤立的状态。
可以使用如下命令查看集群的相关信息
image.png还可以查看某一个集群节点信息,第一列是集群节点 ID
image.png- 集群节点之间的
meet
我们下面使用主节点 172.16.153.178:7001
去依次的 meet
其他 5 个节点。
查看集群信息和节点 信息
image.png image.png- 给集群节点分配
数据槽
集群的槽号是 从0
开始,到16383
结束,共16384
个。
槽的分配是拿 16384
除以集群中主节点的个数,得到每个主节点应该被分配给槽的数量。
所以现在的计划是:
image.png命令
redis-cli -h 被添加的主机 IP -p 端口 cluster addslots 槽号
假如给
7001
分配 0 号槽。命令应该是:redis-cli -h 172.16.153.178 -p 7001 cluster addslots 0
每次只能分配一个 槽号,所以我们可以写个脚本,当然这种方式是不会在生产环境中使用的,这里只是为了理解集群的架构关系。
脚本
#!/bin/sh
target_host_ip=$1
target_host_port=$2
star=$3
end=$4
for slot in $(seq ${star} ${end})
do
echo "正在给 ${target_host_ip} ${target_host_port} 添加${slot}"
redis-cli -h ${target_host_ip} -p ${target_host_port} cluster addslots ${slot}
done
使用脚本
sh mutil-addslots.sh 172.16.153.178 7002 5462 10922
sh mutil-addslots.sh 172.16.153.178 7003 10923 16383
多线程版
image.png最后查看集群信息
image.png可以发现此时集群的状态是
OK
的。
查看节点信息
image.png- 给集群节点配置主从关系
命令语法
redis-cli -p 从节点端口 cluster replicate 主节点的 ID
实操
切换到从节点所在的主机,这样有便于操作
先获取到集群各个节点的 ID
image.png
再按照计划好的进行复制关系的设置
[root@s2 ~]# redis-cli -p 7011 cluster replicate 587b37f1bbe86dcce2b21e3890a61e9b5cdabade
OK
[root@s2 ~]# redis-cli -p 7012 cluster replicate 9d2617ed1892ad08d0bc66b50dada6d53901cce3
OK
[root@s2 ~]# redis-cli -p 7013 cluster replicate e3f9b763619c0f94ce943e57766001f0283f6c51
OK
查看集群节点信息,验证主从关系
redis-cli -p 7011 cluster nodes
image.png
完全配置好后,可以观察集群的数据槽的分配情况
redis-cli -p 7011 cluster slots
最后用客户端登录集群的方式登录到集群中的任意一个节点,设置键值对进行测试。
image.png官方工具安装
官方工具依赖于 Ruby
1. 下载、编译、安装 Ruby
[root@s1 ~]# wget https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.1.tar.gz
安装依赖包
yum install zlib-devel readline openssl-devel
$ ./configure
$ make
$ sudo make install
2. 安装 rubygem redis
一个 ruby 语言实现的访问 Redis 集群的客户端
wget https://rubygems.org/rubygems/rubygems-3.0.2.tgz
tar -xf rubygems-3.0.2.tgz
cd rubygems-3.0.2/
ruby setup.rb
gem install redis
3. 安装 redis-trib.rb
redis-trib
位于 Redis 源码的 src
文件夹中, 它是一个 Ruby 程序, 这个程序通过向实例发送特殊命令来完成创建新集群, 检查集群, 或者对集群进行重新分片(reshared
)等工作。
cp ~/redis-4.0.10/src/redis-trib.rb /url/local/bin/
配置集群
假如你完全安装这个文档做的实验的换,此时配置集群之前,需要把之前的集群进程都停掉。
先在从节点上执行,再到主节点上执行
ps -ef | grep redis-server | grep -v 'grep' | awk '{print $2}' |xargs kill
接着分别在两台主机上,把之前集群产生的数据清除
[root@s1 ~]# rm -rf /redis/data/
[root@s2 ~]# rm -rf /redis/data/
再重新启动这些节点的服务进程
先在主节点上执行
image.png
再在从节点上执行
image.png之后使用如下命令创建集群
redis-trib-rb create --replicas 主节点1IP:端口 主节点2P::端口 主节点3P::端口 从节点1P::端口 从节点2P::端口 从节点3P::端口
选项–replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。
redis-trib.rb create --replicas 1 172.16.153.178:7001 172.16.153.178:7002 172.16.153.178:7003 172.16.153.179:7011 172.16.153.179:7012 172.16.153.179:7013
image.png
image.png
image.png
4. 深入集群
集群的伸缩
添加节点(扩容)
-
准备节点
image.png
2.加入集群中
image.png image.png- 实例操作
- 完成后观察各主节点的数据槽的分配情况
减少节点(缩容)
image.png缩容时的迁移槽
image.png忘记节点操作
image.png实验
命令:
./redis-trib.rb reshard --from 下线节点 ID --to 集群中的任意主节点 ID --slots 迁移到槽数 目前集群中任意节点 IP:端口
注意:
需要把下线节点的槽数平均迁移到剩余的所有节点,所以需要分配分次执行上面的命令。
并且,每次都集群中的主节点应该不同。
删除节点
当我们使用 redis-trib.rb
工具时,只需要在目前集群中的任意一个节点中执行如下命令即可。
image.png注意:
你应该始终先删除从节点,再删除主节点
九、缓存设计和优化
敬请期待_
: