文章目录
- 1 Redis Cluster 介绍
- 1 Redis cluster 架构
- 2 Redis cluster的工作原理
- 2.1 数据分区
- 2.2 集群通信
- 2.3 集群伸缩
- 2.3.1 集群扩容
- 2.3.2 集群缩容
- 2.4 故障转移
- 2.4.1 主观下线
- 2.4.2 客观下线
- 3 Redis Cluster 部署架构说明
- 3.1 部署方式介绍
- 3.2 实战案例:基于Redis 5 以上版本的 redis cluster 部署
- 3.2.1 范例: 查看 --cluster 选项帮助
- 3.2.2 范例: 查看CLUSTER 指令的帮助
- 3.2.3 创建 redis cluster集群
- 3.2.3.1 源码编译
- 3.2.3.2 创建配置文件目录,并添加相关配置文件
- 3.2.3.2.1 redis.conf参数说明:
- 3.2.3.2.2 redis.service
- 3.2.3.2.3 kernel优化配置
- 3.2.3.3 环境配置
- 3.2.3.4 启动检测个节点服务
- 3.2.3.5 初始化集群
- 3.2.3.5.1 查看集群信息meet之前
- 3.2.3.5.2 cluster meet ip port 所有redis实例
- 3.2.3.5.3 查看meet后集群信息
- 3.2.3.5.4 分配数据槽位slot(在所有规划的master实例执行)
- 3.2.3.5.5 验证master信息
- 3.2.3.5.6 配置从节点同步主节点数据
- 3.2.3.5.7 集群验证
- 3.2.3.6 方法二自带命令初始化
- 3.2.3.6.1 查看主从状态
- 3.2.3.6.2 验证集群状态,查看对应关系
- 3.2.4 集群伸缩
- 3.2.4.1 扩容
- 3.2.4.1.1 添加新节点
- 3.2.4.1.2 在新的master上重新分配槽位
- 3.2.4.1.3 为新的master指定新的slave节点
- 3.2.4.2 集群缩容
- 3.2.4.2.1迁移要删除的master节点上面的槽位到其它master
- 3.2.4.2.2 从集群中删除服务器
- 4 ansible 一键部署redis cluster(3台机器,每台双实例交叉部署)
- 4.1 目录结构
- 4.2 使用方法
- 4.2.1 更新 inventory.ini 和 playbook.yml 文件:
- 4.2.2 运行 playbook 并等待集群初始化确认
- 4.2.3 卸载
- 4.2.4 特性功能介绍
1 Redis Cluster 介绍
使用哨兵sentinel 只能解决Redis高可用问题,实现Redis的自动故障转移,但仍然无法解决Redis Master 单节点的性能瓶颈问题
为了解决单机性能的瓶颈,提高Redis 服务整体性能,可以使用分布式集群的解决方案
早期 Redis 分布式集群部署方案:
- 客户端分区:由客户端程序自己实现写入分配、高可用管理和故障转移等,对客户端的开发实现较为
复杂 - 代理服务:客户端不直接连接Redis,而先连接到代理服务,由代理服务实现相应读写分配,当前代
理服务都是第三方实现.此方案中客户端实现无需特殊开发,实现容易,但是代理服务节点仍存有单点
故障和性能瓶颈问题。比如:豌豆荚开发的 codis
Redis 3.0 版本之后推出无中心架构的 Redis Cluster ,支持多个master节点并行写入和故障的自动转移
动能.
1 Redis cluster 架构
Redis cluster 需要至少 3个master节点才能实现,slave节点数量不限,当然一般每个master都至少对应的
有一个slave节点
如果有三个主节点采用哈希槽 hash slot 的方式来分配16384个槽位 slot
此三个节点分别承担的slot 区间可以是如以下方式分配
节点M1 0-5460
节点M2 5461-10922
节点M3 10923-16383
2 Redis cluster的工作原理
2.1 数据分区
数据分区通常采取顺序分布和hash分布
顺序分布保障了数据的有序性,但是离散性低,可能导致某个分区的数据热度高,其他分区数据的热度
低,分区访问不均衡。(偏斜)
哈希分布也分为多种分布方式,比如区域哈希分区,一致性哈希分区等。而redis cluster采用的是虚拟
槽分区的方式。
虚拟槽分区
redis cluster设置有0~16383的槽,每个槽映射一个数据子集,通过hash函数,将数据存放在不同的槽
位中,每个集群的节点保存一部分的槽。
每个key存储时,先经过哈希函数CRC16(key)得到一个整数,然后整数与16384取余,得到槽的数值,
然后找到对应的节点,将数据存放入对应的槽中。
2.2 集群通信
但是寻找槽的过程并不是一次就命中的,比如上图key将要存放在14396槽中,但是并不是一下就锁定了
node3节点,可能先去询问node1,然后才访问node3。
而集群中节点之间的通信,保证了最多两次就能命中对应槽所在的节点。因为在每个节点中,都保存了
其他节点的信息,知道哪个槽由哪个节点负责。这样即使第一次访问没有命中槽,但是会通知客户端,
该槽在哪个节点,这样访问对应节点就能精准命中。
- 节点A对节点B发送一个meet操作,B返回后表示A和B之间能够进行沟通。
- 节点A对节点C发送meet操作,C返回后,A和C之间也能进行沟通。
- 然后B根据对A的了解,就能找到C,B和C之间也建立了联系。
- 直到所有节点都能建立联系。
这样每个节点都能互相知道对方负责哪些槽。
2.3 集群伸缩
集群并不是建立之后,节点数就固定不变的,也会有新的节点加入集群或者集群中的节点下线,这就是
集群的扩容和缩容。但是由于集群节点和槽息息相关,所以集群的伸缩也对应了槽和数据的迁移
2.3.1 集群扩容
当有新的节点准备好加入集群时,这个新的节点还是孤立节点,加入有两种方式。一个是通过集群节点
执行命令来和孤立节点握手,另一个则是使用脚本来添加节点。
- cluster_node_ip:port: cluster meet ip port new_node_ip:port
- redis-trib.rb add-node new_node_ip:port cluster_node_ip:port
通常这个新的节点有两种身份,要么作为主节点,要么作为从节点:
- 主节点:分摊槽和数据
- 从节点:作故障转移备份
2.3.2 集群缩容
2.4 故障转移
除了手动下线节点外,也会面对突发故障。下面提到的主要是主节点的故障,因为从节点的故障并不影
响主节点工作,对应的主节点只会记住自己哪个从节点下线了,并将信息发送给其他节点。故障的从节
点重连后,继续官复原职,复制主节点的数据。
只有主节点才需要进行故障转移。在之前学习主从复制时,我们需要使用redis sentinel来实现故障转
移。而redis cluster则不需要redis sentinel,其自身就具备了故障转移功能。
根据前面我们了解到,节点之间是会进行通信的,节点之间通过ping/pong交互消息,所以借此就能发
现故障。集群节点发现故障同样是有主观下线和客观下线的
集群同样具备了自动转移故障的功能,和哨兵有些类似,在进行客观下线之后,就开始准备让故障节点
的从节点“上任”了。
首先是进行资格检查,只有具备资格的从节点才能参加选举:
- 故障节点的所有从节点检查和故障主节点之间的断线时间
- 超过cluster-node-timeout * cluster-slave-validati-factor(默认10)则取消选举资格
然后是准备选举顺序,不同偏移量的节点,参与选举的顺位不同。offset最大的slave节点,选举顺位最
高,最优先选举。而offset较低的slave节点,要延迟选举。
当有从节点参加选举后,主节点收到信息就开始投票。偏移量最大的节点,优先参与选举就更大可能获
得最多的票数,称为主节点。
当有从节点参加选举后,主节点收到信息就开始投票。偏移量最大的节点,优先参与选举就更大可能获
得最多的票数,称为主节点。
当从节点走马上任变成主节点之后,就要开始进行替换主节点:
- 让该slave节点执行slaveof no one变为master节点
- 将故障节点负责的槽分配给该节点
- 向集群中其他节点广播Pong消息,表明已完成故障转移
- 故障节点重启后,会成为new_master的slave节点
2.4.1 主观下线
对于每个节点有一个故障列表,故障列表维护了当前节点接收到的其他所有节点的信息。当半数以上的
持有槽的主节点都标记某个节点主观下线,就会尝试客观下线。
2.4.2 客观下线
3 Redis Cluster 部署架构说明
测试环境:3台服务器,每台服务器启动6379和6380两个redis 服务实例,适用于测试环境
生产环境:6台服务器,分别是三组master/slave,适用于生产环境
#集群节点
10.0.0.8
10.0.0.18
10.0.0.28
10.0.0.38
10.0.0.48
10.0.0.58
#预留服务器扩展使用
10.0.0.68
10.0.0.78
3.1 部署方式介绍
redis cluster 有多种部署方法
- 原生命令安装,理解Redis Cluster架构,生产环境不使用
- 官方工具安装,高效、准确,生产环境可以使用
- 自主研发,可以实现可视化的自动化部署
3.2 实战案例:基于Redis 5 以上版本的 redis cluster 部署
官方文档:https://redis.io/topics/cluster-tutorial
redis cluster 相关命令
3.2.1 范例: 查看 --cluster 选项帮助
redis-cli --cluster help
Cluster Manager Commands:create host1:port1 ... hostN:portN--cluster-replicas <arg>check host:port--cluster-search-multiple-ownersinfo host:portfix host:port--cluster-search-multiple-ownersreshard host:port--cluster-from <arg>--cluster-to <arg>--cluster-slots <arg>--cluster-yes--cluster-timeout <arg>--cluster-pipeline <arg>--cluster-replacerebalance host:port--cluster-weight <node1=w1...nodeN=wN>--cluster-use-empty-masters--cluster-timeout <arg>--cluster-simulate--cluster-pipeline <arg>--cluster-threshold <arg>--cluster-replaceadd-node new_host:new_port existing_host:existing_port--cluster-slave--cluster-master-id <arg>del-node host:port node_idcall host:port command arg arg .. argset-timeout host:port millisecondsimport host:port--cluster-from <arg>--cluster-copy--cluster-replacehelp
For check, fix, reshard, del-node, set-timeout you can specify the host and port
of any working node in the cluster.
3.2.2 范例: 查看CLUSTER 指令的帮助
redis-cli CLUSTER HELP
1) CLUSTER <subcommand> arg arg ... arg. Subcommands are:
2) ADDSLOTS <slot> [slot ...] -- Assign slots to current node.
3) BUMPEPOCH -- Advance the cluster config epoch.
4) COUNT-failure-reports <node-id> -- Return number of failure reports for
<node-id>.
5) COUNTKEYSINSLOT <slot> - Return the number of keys in <slot>.
6) DELSLOTS <slot> [slot ...] -- Delete slots information from current node.
7) FAILOVER [force|takeover] -- Promote current replica node to being a master.
8) FORGET <node-id> -- Remove a node from the cluster.
9) GETKEYSINSLOT <slot> <count> -- Return key names stored by current node in a
slot.
10) FLUSHSLOTS -- Delete current node own slots information.
11) INFO - Return onformation about the cluster.
12) KEYSLOT <key> -- Return the hash slot for <key>.
13) MEET <ip> <port> [bus-port] -- Connect nodes into a working cluster.
14) MYID -- Return the node id.
15) NODES -- Return cluster configuration seen by node. Output format:
16) <id> <ip:port> <flags> <master> <pings> <pongs> <epoch> <link> <slot>
... <slot>
17) REPLICATE <node-id> -- Configure current node as replica to <node-id>.
18) RESET [hard|soft] -- Reset current node (default: soft).
19) SET-config-epoch <epoch> - Set config epoch of current node.
20) SETSLOT <slot> (importing|migrating|stable|node <node-id>) -- Set slot
state.
21) REPLICAS <node-id> -- Return <node-id> replicas.
22) SLOTS -- Return information about slots range mappings. Each range is made
of:
23) start, end, master and replicas IP addresses, ports and ids
3.2.3 创建 redis cluster集群
每个Redis 节点采用相同的相同的Redis版本、相同的密码、硬件配置、时间同步
所有Redis服务器必须没有任何数据
准备三台主机,地址如下:
10.0.0.129
10.0.0.130
10.0.0.131
3.2.3.1 源码编译
- 三主三从是cluster ha的最小要求,每个节点部署两个redis实例即一个为master,一个为其他节点master的slave,以增加容错可靠行,避免同一节点两个实例都为主。生产环境如果资源允许建议每个实例部署在单独的主机上。
- Master实例使用7001端口,Slave实例使用8002,便于管理和查看
- 关闭redis存储功能一级opensips目前只用到了它的缓存功能,暂不需要数据持久保存,禁用rdb、aof
- 每个redis实例需要设置密码鉴权(并且符合一定的安全复杂度)、最大使用内存、超出最大内存的清理策略建议为allkeys-lru、最大客户端连接数限制
两个实例实现方式:第一种通过指定不通的配置文件区分;第二种部署多个运行目录,比如redis-7001,redis-8002此种方式不能使用软连接,为了统一管理生产cluster多实例部署采用了方式一 - /data挂载单独的磁盘用于数据存储
下载redis6.2源码包
官网地址:https://download.redis.io/releases/redis-6.2.2.tar.gz
cd /usr/local/src ### 上传源码到此目录
Shell>tar xfv redis-6.2.2.tar.gz ### 解压
Shell>cd redis-6.2.2
Shell>make -j 2 PREFIX=/usr/local/redis install ## 指定安装目录编译并安装
3.2.3.2 创建配置文件目录,并添加相关配置文件
Shell>mkdir -pv /usr/local/redis/{etc,deps} ## 默认安装目录只有bin
Shell>mkdir -pv /usr/local/redis/etc/{7001,8002}#不同实例配置文件放在端口号命名的目录下
Shell>mkdir -pv /data/redis/{7001,8002}/{data,log} #创建数据目录
Shell>cp deps/hiredis/hiredis.h /usr/local/redis/deps/ ## 拷贝hiredis.h
Shell>cp -r /usr/local/src/redis-6.2.2/*.conf /usr/local/redis/etc ## 拷贝配置文件
Shell>cp /usr/local/redis/etc/redis.conf{,.ori} ## 备份原始配置
Shell>cp /usr/local/redis/etc/sentinel.conf{,.ori} ### 备份哨兵配置
Shell>cp /usr/local/redis/etc/redis.conf /usr/local/redis/etc/7001/redis.conf
egrep -v “#|$” /usr/local/redis/etc/7001/redis.conf
## 提供redis7001配置文件,其他剩余节点参考此节点配置,红色标注为实例间不同配置或者重点关注配置 bind 0.0.0.0 requirepass 123456 masterauth 123456 port 7001 dir
/data/redis/7001/data logfile /data/redis/7001/log/redis.log pidfile
/usr/local/redis/etc/7001/redis.pid cluster-enabled yes
cluster-config-file nodes-7001.conf cluster-node-timeout 5000
appendonly no protected-mode yes tcp-backlog 511 timeout 0
tcp-keepalive 300 daemonize yes loglevel notice databases 16
always-show-logo no set-proc-title yes proc-title-template “{title}
{listen-addr} {server-mode}” save “” stop-writes-on-bgsave-error yes
rdbcompression yes rdbchecksum yes dbfilename dump.rdb
rdb-del-sync-files no replica-serve-stale-data yes replica-read-only
yes repl-diskless-sync no repl-diskless-sync-delay 5
repl-diskless-load disabled repl-disable-tcp-nodelay no
replica-priority 100 acllog-max-len 128 maxclients 10000 maxmemory
10485760kb maxmemory-policy allkeys-lru lazyfree-lazy-eviction no
lazyfree-lazy-expire no lazyfree-lazy-server-del no replica-lazy-flush
no lazyfree-lazy-user-del no lazyfree-lazy-user-flush no oom-score-adj
no oom-score-adj-values 0 200 800 disable-thp yes appendfilename
“appendonly.aof” appendfsync everysec no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb
aof-load-truncated yes aof-use-rdb-preamble yes lua-time-limit 5000
slowlog-log-slower-than 10000 slowlog-max-len 128
latency-monitor-threshold 0 notify-keyspace-events “”
hash-max-ziplist-entries 512 hash-max-ziplist-value 64
list-max-ziplist-size -2 list-compress-depth 0 set-max-intset-entries
512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64
hll-sparse-max-bytes 3000 stream-node-max-bytes 4096
stream-node-max-entries 100 activerehashing yes
client-output-buffer-limit normal 0 0 0 client-output-buffer-limit
replica 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60 hz
10 dynamic-hz yes aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes jemalloc-bg-thread yes
3.2.3.2.1 redis.conf参数说明:
- 集群相关:
cluster-enabled yes ## 开启集群模式
cluster-config-file nodes-7001.conf ## 集群配置信息
cluster-node-timeout 15000 ## 集群探活超时时间单位毫秒 - 安全相关
masterauth xxx ### slave连接master用到的密码
requirepass xxx ### 客户端连接master用到的密码,6.x还支持acl
maxclients 10000 ### 客户端最大连接数
maxmemory 10485760kb ### redis使用的最大内存,如果是同一节点部署多个实例需要考虑每个实例的内存
maxmemory-policy allkeys-lru ###当redis使用的内存大于maxmemory,回收逻辑所有keys采用LRU算法 - 持久相关
save “” ##关闭rbd写盘
appendonly no ##关闭aof写盘 - 8002实例不同配置
##shell>sed -r 's@7001@8002@g' /usr/local/redis/etc/7001/redis.conf > /usr/local/redis/etc/8002/redis.conf
打包部署文件到另外集群机器
for i in $(seq 130 131);do scp -r /usr/local/redis 10.0.0.${i}:/tmp/; echo "------------";done
3.2.3.2.2 redis.service
cat /lib/systemd/system/redis*
[Unit]
Description=Redis persistent key-value database
After=network.target[Service]
ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/etc/7001/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT
Type=forking
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
LimitNOFILE=1000000[Install]
WantedBy=multi-user.target[Unit]
Description=Redis persistent key-value database
After=network.target[Service]
ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/etc/8002/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT
Type=forking
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
LimitNOFILE=1000000[Install]
WantedBy=multi-user.target
3.2.3.2.3 kernel优化配置
echo "* - nofile 65535" >> /etc/security/limits.conf
echo "net.core.somaxconn = 10240" >> /etc/sysctl.conf
echo "vm.overcommit_memory = 1" >> /etc/sysctl.conf
sysctl -p
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
echo 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >> /etc/rc.local
echo 'echo never > /sys/kernel/mm/transparent_hugepage/defrag' >> /etc/rc.local
chmod +x /etc/rc.d/rc.local
存储系统中的块优化
在存储系统中,数据通常以固定大小的块(blocks)为单位进行读写操作。如果数据被划分为很多小块(比如4KB),那么每次读写都需要处理大量的元数据和管理操作,可能会导致性能开销增加。因此,有些存储系统会采取块优化策略,比如将多个小块合并成一个大块,以减少管理开销和提高读写效率。
类比 Transparent Huge Pages (THP)
- THP 背景
:内存页表是操作系统管理内存地址和物理内存对应关系的结构。通常,Linux 系统使用 4KB 的小内存页。如果程序使用大量内存,这会导致大量的内存页表项,从而增加 CPU 的工作量(尤其是 TLB 缓存未命中的情况)。THP 是一种优化,通过将多个 4KB 小页合并为 2MB 或更大的大页,减少页表项的数量,进而减少页表管理的开销,提高内存访问性能。 - 与块优化的相似点
:
a.减少管理开销:两者的主要目的都是通过减少小块的管理开销来提升系统性能。存储系统中减少对小块的操作,而内存管理中减少小页的管理。
b.性能提升:在存储系统中,块优化可以减少磁盘I/O操作的次数,提高数据吞吐量;在内存中,使用 THP 则减少了 TLB 未命中的几率,提高了 CPU 内存访问的效率。
为什么禁用 THP?
虽然 THP 理论上是一种优化,但在一些高性能应用中(如 Redis、数据库等),THP 的大页分配和碎片整理反而会带来额外的性能损耗,特别是在动态分配和整理大页时,可能会导致长时间的卡顿或性能抖动。因此,类似于存储系统中在某些场景下不使用大块优化,Redis 官方也推荐禁用 THP,以保持内存管理的稳定性和性能可预测性。
总结
THP 和块级优化的原理确实类似,都是通过合并小单位来减少系统的管理开销和性能损耗。但在特定应用场景下,禁用这类优化策略(如禁用 THP)可能会带来更好的性能表现。
3.2.3.3 环境配置
主机名
hostnamectl set-hostname redis1;exec bash
hostnamectl set-hostname redis2;exec bash
hostnamectl set-hostname redis3;exec bash
本地主机名解析
cat >> /etc/hosts <<EOF
10.0.0.129 xxx redis-n1 cluster-n1
10.0.0.130 xxx redis-n2 cluster-n2
10.0.0.131 xxx redis-n3 cluster-n3
EOF
时间同步
ntpdate ntp.aliyun.com
添加环境变量
shell>cp -r /tmp/redis /usr/local/redis-6.2.2
Shell>cd /usr/local
Shell>ln -sv redis-6.2.2 redis ##创建软连接
Shell> echo 'export PATH=/usr/local/redis/bin:$PATH' > /etc/profile.d/redis.sh ##导入到环境变量
Shell>source /etc/profile
3.2.3.4 启动检测个节点服务
systemctl enable --now redis7001 redis8002
systemctl is-active redis7001 redis8002
active
active
netstat -tnpl | grep redis ### 查看实例端口是否正常监听,如果没有查看日志/data/redis/7001/log/redis.log
- 7001,8002对外提供服务
- 17001,18002 集群内部事务通信
- 以上并不能说明已经运行为集群模式,只是申明支持(cluster enalbe=yes),需要相关配置后才能运行为cluster
- 请确保三个节点上的所有redis实例正常启动
3.2.3.5 初始化集群
- 默认有两种配置方式:第一种通过redis server内置命令cluster subcommand完成上述三个部分;第二种通过redis client工具redis-cli --cluster完成
- 服务端内置命令可以理解cluster形成的过程,操作相对繁琐并且要登录到至少一半的实例上(主要是slave上);客户端工具命令不需要关心过程傻瓜式创建,速度比较快不需要登录到每一个实例,支撑一键生成。为了更好的理解redis cluster这里我使用第一种方式进行集群配置。
#加入集群(登录任意一个redis实例,这里以10.0.0.129:7001说明)
Shell>/usr/local/redis/bin/redis-cli -h 10.135.81.33 -p 7001
Redis>auth xxx ### 输入requirepass 指定的密码
3.2.3.5.1 查看集群信息meet之前
10.135.81.33:7001>cluster info ###
cluster_state:fail ## 因为slot没有分配完所以状态是失败的
cluster_slots_assigned:0 ## 集群已分配的slot,目前是0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:1 ## meet一个增加1
cluster_size:0
cluster_current_epoch:0 ## 版本
cluster_my_epoch:0
cluster_stats_messages_sent:0
cluster_stats_messages_received:0查看集群信息meet之前
3.2.3.5.2 cluster meet ip port 所有redis实例
10.135.81.33:7001>cluster meet 10.135.81.34 7001
10.135.81.33:7001>cluster meet 10.135.81.35 7001
10.135.81.33:7001>cluster meet 10.135.81.33 8002
10.135.81.33:7001>cluster meet 10.135.81.34 8002
10.135.81.33:7001>cluster meet 10.135.81.34 8002
3.2.3.5.3 查看meet后集群信息
10.135.81.33:7001> cluster info
cluster_state:fail ##没有分配完16384个槽位,状态依旧是fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6 ## 三主三存
cluster_size:0
cluster_current_epoch:4
cluster_my_epoch:1
cluster_stats_messages_ping_sent:108
cluster_stats_messages_pong_sent:122
cluster_stats_messages_meet_sent:5
cluster_stats_messages_sent:235
cluster_stats_messages_ping_received:122
cluster_stats_messages_pong_received:113
cluster_stats_messages_received:235
3.2.3.5.4 分配数据槽位slot(在所有规划的master实例执行)
##cluster addslots 槽位,一个槽位只能分配一个节点,16384个槽位必须分配完,不同节点不能冲突,按节点规划进行分配##
Shell>redis-cli -h 10.135.81.33 -p 7001 -a "xxxxx" cluster addslots {0..5461}
Shell>redis-cli -h 10.135.81.34 -p 7001 -a "xxxxx" cluster addslots {5462..10922}
Shell>redis-cli -h 10.135.81.35 -p 7001 -a "xxxxx" cluster addslots {10923..16383}
3.2.3.5.5 验证master信息
##登录任意redis节点查看集群信息,如果不考虑mater的HA,那么到此步骤cluster分片就算配置完成###
10.135.81.33:7001> cluster info
cluster_state:ok ## 集群状态ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:1
cluster_current_epoch:5
cluster_my_epoch:1
cluster_stats_messages_ping_sent:1052
cluster_stats_messages_pong_sent:1021
cluster_stats_messages_meet_sent:5
cluster_stats_messages_sent:2078
cluster_stats_messages_ping_received:1021
cluster_stats_messages_pong_received:1057
cluster_stats_messages_received:2078
3.2.3.5.6 配置从节点同步主节点数据
配置主从说白了就是mater的ha,mater只解决了数据分布读写,但并没有解决集群的高可用,加入其中一个master实例关掉,那么在这个mater上的slot key都不能读写。主从主要解决当master故障备用节点提升为master依旧能提供服务的问题,需要在所有的slave节点进行操作。
cluster nodes查看集群成员关系,默认没有配置主从前都认为自己是master,并且有些实例分配到了slot,有些master并没有分配到slot,这些没有分配到slot的实例就是我们用来作为slave角色来同步master的,因为在写此文档之前已经部署完成,这里暂时省略,这步主要是查看规划成为master角色的实例id,后面配置使用
###cluster replicate masterid ##
Shell>redis-cli -h 10.135.81.33 -p 8002 ###登录所有规划为slave节点的实例
Shell>auth xxxx
10.135.81.33:8002>cluster nodes ### 查看主节点id
10.135.81.33:8002>cluster replicate xxxx ## 按规划应为10.135.81.35:7001实例的id
## 按照上述方式 登录其他从节点完成复制配置最终结果如下###
10.135.81.33:7001>cluster nodes
结果说明:
- 530xxxx824d表示实例在集群内的id
- Myself: 表示登录的当前实例
- Master: 表示实例角色为master
- Slave xxxx: 表示实例角色为salve,xxx表示对应的master id是什么
3.2.3.5.7 集群验证
集群状态检查
Shell>redis-cli -a ‘xxxx’ --cluster check 10.135.81.33:7001 ### 任意一个实例
测试key的分配
Shell>redis-cli -c -h 10.0.0.129 -p 7001 ## -c使用智能客户端支持moved
Shell>auth xxxx
Shell>set k1 v1 ## 设置一个key名字为k1 值为 v1
Shell>set k2 v2
Shell>set k3 v3
Shell>cluster keyslot k1 ## 查看k1落在哪个槽位,其实可以使用CRC(key)/16384
Shell>cluster keyslot k2
Shell>cluster keyslot k3
3.2.3.6 方法二自带命令初始化
#命令redis-cli的选项 --cluster-replicas 1 表示每个master对应一个slave节点
redis-cli --cluster create 10.0.0.129:7001 10.0.0.129:8002 10.0.0.130:7001 10.0.0.130:8002 10.0.0.131:7001 10.0.0.131:8002 --cluster-replicas 1 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface
may not be safe.
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 10.0.0.38:6379 to 10.0.0.8:6379
Adding replica 10.0.0.48:6379 to 10.0.0.18:6379
Adding replica 10.0.0.58:6379 to 10.0.0.28:6379
......
免交操作如下:
redis-cli --cluster create 10.0.0.129:7001 10.0.0.129:8002 10.0.0.130:7001 10.0.0.130:8002 10.0.0.131:7001 10.0.0.131:8002 --cluster-replicas 1 -a 123456 --cluster-yes
3.2.3.6.1 查看主从状态
3.2.3.6.2 验证集群状态,查看对应关系
3.2.4 集群伸缩
3.2.4.1 扩容
扩容适用场景:
当前客户量激增,现有的Redis cluster架构已经无法满足越来越高的并发访问请求,为解决此问题,新购
置两台服务器,要求将其动态添加到现有集群,但不能影响业务的正常访问。
注意: 生产环境一般建议master节点为奇数个,比如:3,5,7,以防止脑裂现象
3.2.4.1.1 添加新节点
#将一台新的主机10.0.0.68加入集群,以下示例中10.0.0.58可以是任意存在的集群节点
[root@redis-node1 ~]#redis-cli -a 123456 --cluster add-node 10.0.0.68:6379 <当前
任意集群节点>:6379
#观察到该节点已经加入成功,但此节点上没有slot位,也无从节点,而且新的节点是master
[root@redis-node1 ~]#redis-cli -a 123456 --cluster info 10.0.0.8:6379
Warning: Using a password with '-a' or '-u' option on the command line interface
may not be safe.
10.0.0.8:6379 (cb028b83...) -> 6672 keys | 5461 slots | 1 slaves.
10.0.0.68:6379 (d6e2eca6...) -> 0 keys | 0 slots | 0 slaves.
10.0.0.48:6379 (d04e524d...) -> 6679 keys | 5462 slots | 1 slaves.
10.0.0.28:6379 (d34da866...) -> 6649 keys | 5461 slots | 1 slaves.
[OK] 20000 keys in 5 masters.
1.22 keys per slot on average.
[root@redis-node1 ~]#redis-cli -a 123456 --cluster check 10.0.0.8:6379
3.2.4.1.2 在新的master上重新分配槽位
新的node节点加到集群之后,默认是master节点,但是没有slots,需要重新分配,否则没有槽位将无法访
问
注意: 重新分配槽位需要清空数据,所以需要先备份数据,扩展后再恢复数据
计算16384/总节点数槽位、新的masterID、从原有哪几个节点分担槽点
redis-cli -a 123456 --cluster reshard <当前任意集群节点>:6379 … How many
slots do you want to move (from 1 to 16384)?4096 #新分配多少个槽位
=16384/master个数 What is the receiving node ID? d6e2eca6b338b717923f64866bd31d42e52edc98 #新的 master的ID Please enter
all the source node IDs. Type ‘all’ to use all the nodes as source
nodes for the hash slots. Type ‘done’ once you entered all the source
nodes IDs. Source node #1: all #输入all,将哪些源主机的槽位分配给新的节点,all是自动在所有的redis
node选择划分,如果是从redis cluster删除某个主机可以使用此方式将指定主机上的槽位全部移动到别的redis主机
3.2.4.1.3 为新的master指定新的slave节点
方法1:在新加节点到集群时,直接将之设置为slave
redis-cli -a 123456 --cluster add-node 10.0.0.78:6379 <任意集群节点>:6379 --
cluster-slave --cluster-master-id d6e2eca6b338b717923f64866bd31d42e52edc98
方法2:先将新节点加入集群,再修改为slave为新的master添加slave节点
[root@redis-node1 ~]#redis-cli -h 10.0.0.78 -p 6379 -a 123456 #登录到新添加节点
10.0.0.78:6380> CLUSTER NODES #查看当前集群节点,找到目标master 的ID
10.0.0.78:6380> CLUSTER REPLICATE 886338acd50c3015be68a760502b239f4509881c #将其设
置slave,命令格式为cluster replicate MASTERID
10.0.0.78:6380> CLUSTER NODES #再次查看集群节点状态,验证节点是否已经更改为指定master 的
slave
3.2.4.2 集群缩容
缩容适用场景:
随着业务萎缩用户量下降明显,和领导商量决定将现有Redis集群的8台主机中下线两台主机挪做它用,缩容
后性能仍能满足当前业务需求
删除节点过程:
扩容时是先添加node到集群,然后再分配槽位,而缩容时的操作相反,是先将被要删除的node上的槽
位迁移到集群中的其他node上,然后 才能再将其从集群中删除,如果一个node上的槽位没有被完全迁
移空,删除该node时也会提示有数据出错导致无法删除。
3.2.4.2.1迁移要删除的master节点上面的槽位到其它master
注意: 被迁移Redis master源服务器必须保证没有数据,否则迁移报错并会被强制中断。
取之于民,还之于民(多出来的4096不能直接写,因为移动目标只能操作对象只能是一个,所以移3次每次移到不同对象,槽位为多出来4096/现在主节点)
redis-cli -a 123456 --cluster reshard 10.0.0.18:6379
.....
How many slots do you want to move (from 1 to 16384)? 1356 #共4096/3分别给其它三个
master节点
3.2.4.2.2 从集群中删除服务器
上面步骤完成后,槽位已经迁移走,但是节点仍然还属于集群成员,因此还需从集群删除该节点
注意: 删除服务器前,必须清除主机上面的槽位,否则会删除主机失败
4 ansible 一键部署redis cluster(3台机器,每台双实例交叉部署)
项目地址如下:
https://gitee.com/song-yao/remote-shell-script-backup
https://github.com/songyao199681/ansible-redis-cluster
4.1 目录结构
tree ansible-redis-cluster/
ansible-redis-cluster/
├── ansible.cfg
├── playbooks
│ ├── inventory.ini
│ ├── playbook.yml
│ └── uninstall.yml
├── README.md
└── roles└── redis_cluster├── defaults├── files│ └── redis-6.2.2.tar.gz├── handlers│ └── main.yml├── hell├── meta├── tasks│ └── main.yml├── templates│ ├── redis.conf.j2│ └── redis.service.j2└── vars└── main.yml
4.2 使用方法
4.2.1 更新 inventory.ini 和 playbook.yml 文件:
cat ansible-redis-cluster/playbooks/inventory.ini
[redis_servers]
server1 ansible_host=10.0.0.129
server2 ansible_host=10.0.0.130
server3 ansible_host=10.0.0.131
4.2.2 运行 playbook 并等待集群初始化确认
cd ansible-redis-cluster/playbooks/
ansible-playbook -i inventory.ini playbook.yml
4.2.3 卸载
ansible-playbook -i inventory.ini uninstall.yml
4.2.4 特性功能介绍
- 安装时初始化支持确认
- 自动确定是否从本地、外网拉包
- 仅server1执行安装编译依赖、编译安装
- 修改相关配置文件触发重启
- 卸载前确认