目录
一、案例分析
1.1、案例概述
现今 Redis 在很多业务场景,使用越来越广泛。在互联网发展的今天,网站的稳定性和高可用性不言而喻。随着技术的发展,集群方案层出不穷,目前 Redis 集群的实现方法 一般有客户端分片、代理分片和服务器端分片三种解决方案。
1.2、案例前置知识点
1)客户端分片
客户端分片方案是将分片工作放在业务程序端。程序代码根据预先设置的路由规则,直接对多个 Redis 实例进行分布式访问。这样的好处是,群集不依赖于第三方分布式中间件,实现方法和代码都自己掌控,可随时调整,不用担心踩到坑。这实际上是一种静态分片技术, Redis 实例的增减,都得手工调整分片程序。基于此分片机制的开源产品,现在仍不多见。 这种分片机制的性能比代理式更好(少了一个中间分发环节),但缺点是升级麻烦,对研发人员的个人依赖性强,需要有较强的程序开发能力做后盾。如果主力程序员离职,可能新的负责人会选择重写一遍。所以这种方式下可运维性较差,一旦出现故障,定位和解决都得研发人员和运维人员配合解决,故障时间变长。因此这种方案,难以进行标准化运维,不太适合中小公司。
2)代理分片
代理分片方案是将分片工作交给专门的代理程序来做。代理程序接收到来自业务程序的数据请求,根据路由规则,将这些请求分发给正确的 Redis 实例并返回给业务程序。这种机制下,一般会选用第三方代理程序(而不是自己研发)。因为后端有多个 Redis 实例, 所以这类程序又称为分布式中间件。这种分片机制的好处是业务程序不用关心后端 Redis 实例,维护起来也方便。虽然会因此带来些性能损耗,但对于 Redis 这种内存读写型应用, 相对而言是能容忍的。这是比较推荐的集群实现方案。像 Twemproxy、Codis 就是基于该 机制的开源产品的其中代表,应用非常广泛。
- Twemproxy 代理分片机制
Twemproxy 是一种代理分片机制,由 Twitter 开源。Twemproxy 作为代理,可接受来自多个程序的访问,按照路由规则,转发给后台的各个 Redis 服务器,再原路返回。这个方案顺理成章地解决了单个 Redis 单实例问题。当然 Twemproxy 本身也是单点,需要用 Keepalived 做高可用方案。在很长的时间内,Twemproxy 是应用范围最广、稳定性最高、 最久经考验的分布式中间件。
当然 Twemproxy 还有诸多的缺点,具体如下所示。
- 无法平滑地扩容/缩容,增加了运维难度。当业务量突增需要增加 Redis 服务器或业务量萎缩需要减少 Redis 服务器时,Twemproxy 都无法平滑地进行扩容或缩容等操作。
- 运维操作不友好,甚至没有控制面板。由于使用了中间件代理,相比客户端直接连接服务器方式,性能上有所损耗,实测性能效果降低了 20%左右。
- Codis 代理分片机制
Codis 由豌豆荚于 2014 年 11 月开源,基于 Go 语言和 C 语言开发,是近期涌现的、 国人开发的优秀开源软件之一,现已广泛用于豌豆荚的各种 Redis 业务场景。从各种压力测试来看,Codis 的稳定性符合高效运维的要求。实测 Codis 集群业务处理性能改善很多, 最初集群处理数据性能要比Twemproxy差20%左右,现在比Twemproxy好很多。并且Codis 具有可视化运维管理界面。因此综合方面会优于 Twemproxy 很多。目前越来越多的公司选 择 Codis。
Codis 引入了 Group 的概念,每个 Group 包括 1 个 Redis Master 及至少 1 个 Redis Slave,这是和 Twemproxy 的区别之一。这样做的好处是,如果当前 Master 有问题,则运维人员可通过 Dashboard“自助式”切换到 Slave,而不需要小心翼翼地修改程序配置文件。 为支持数据热迁移(Auto Rebalance),出品方修改了 Redis Server 源码,并称之为 Codis Server。Codis 采用预先分片(Pre-Sharding)机制,事先规定分成 1024 个 slots(也就是说,最多能支持后端 1024 个 Codis Server),这些路由信息保存在 zookeeper 中。
3)服务端分片
Redis-Cluster 是 Redis 官方的集群分片技术。Redis-Cluster 将所有 Key 映射到 16384 个 slot 中,集群中每个 Redis 实例负责一部分,业务程序是通过集成的 Redis-Cluster 客户端进行操作。客户端可以向任一实例发出请求,如果所需数据不在该实例中,则该实例引导 客户端自动去对应实例读写数据。Redis-Cluster 成员之间的管理包括节点名称、IP、端口、 状态、角色等,都通过节点与之间两两通讯,定期交换信息并更新。
Redis-Cluster 是在 Redis3.0 版中推出,支持 Redis 分布式集群部署模式,采用无中心分布式架构。所有的 Redis 节点彼此互联(PING-PONG 机制),内部使用二进制协议优化传输速度和带宽。节点的 fail 是通过集群中超过半数的节点检测失败时才生效。客户端与 Redis 节点直连,不需要中间代理层。客户端也不需要连接集群所有节点,连接集群中任何一个可用节点即可,这样即减少了代理层,也大大提高了 Redis 集群性能。
1.3、案例环境
1)本实验案例环境
目前 Redis 官网最新稳定版本已经更新到 5.0.7,本次案例实验环境就使用 4.0.9。为了实验环境简单明了、方便部署使用六台服务器,然后启动六个 Redis 实例组成集群,集群 包括三组,每组都是一主一从的关系。在实际生产环境考虑到架构的高可用能,在实验环境至少需要六台服务器。具体环境参考下表。
系统版本 | CentOS7.6(最小化安装) |
Redis 版本 | 4.0.9 |
服务器 IP 地址 | 192.168.23.208——213 |
主机名 | master1-3,slave1-3 |
Firewalld | 关闭 |
Selinux | 禁用 |
Redis 实例端口 | 6379 |
案例环境
案例拓扑如下图所示:
实验拓扑图
2)案例需求
- 使用六台 Redir 搭建一个 Redis 集群。
- 要求任意宕机一组实例,集群写入或读取数据不受任何影响。
- 要求理解 Redis 的性能管理。
3)案例实现思路
- 下载安装 Redis。
- 配置启动六个 Redis 实例。
- 将六个 Redis 实例组成集群。
- 集群结构微调。
- 破坏性测试。
二、案例实施
2.1、下载并安装 Redis
Redis 常见的安装方式也分为两种:YUM 安装和源码安装。这里部署集群建议采用源码安装的方式。
所有节点上操作:
[root@master1 ~]# tar zxf redis-4.0.9.tar.gz -C /usr/src/
[root@master1 ~]# cd /usr/src/redis-4.0.9/
[root@master1 redis-4.0.9]# make
[root@master1 redis-4.0.9]# make PREFIX=/usr/local/redis install
[root@master1 redis-4.0.9]# ln -s /usr/local/redis/bin/* /usr/local/bin/
[root@master1 redis-4.0.9]# cd utils/
[root@master1 utils]# ./install_server.sh
2.2、修改 Redis 配置文件
所有节点上操作:
修改 master1-3、slave1-3 的配置文件,以下配置文件参数需要根据机器环境修改。
[root@master1 ~]# vim /etc/redis/6379.conf
# bind 127.0.0.1 //注释掉 bind 项,Redis 中 bind 选项默认监听所有网卡
protected-mode no //关闭保护模式
port 6379 //端口号
daemonize yes //以独立进程启动
cluster-enabled yes //打开集群
cluster-config-file nodes-6379.conf //集群配置文件名称设置
cluster-node-timeout 15000 //集群超时时间设置
appendonly yes //开启 aof 持久化
[root@master1 ~]# /etc/init.d/redis_6379 restart 重启服务
[root@master1 ~]# ss -anpt | grep redis
LISTEN 0 128 *:16379 *:* users:(("redis-server",pid=20164,fd=11))
LISTEN 0 128 *:6379 *:* users:(("redis-server",pid=20164,fd=7))
LISTEN 0 128 [::]:16379 [::]:* users:(("redis-server",pid=20164,fd=10))
LISTEN 0 128 [::]:6379 [::]:* users:(("redis-server",pid=20164,fd=6))
正常启动后/var/lib/redis/6379/目录下会多出两个文件,一个是持久化 appendonly.aof 文件,另外一个是节点首次启动生成的 nodes-6379.conf
[root@master1 ~]# ls /var/lib/redis/6379/
appendonly.aof dump.rdb nodes-6379.conf
2.3、创建 Redis 集群
仅在 master1 上操作
创建集群要用到 ruby 的一个脚本,在创建集群前,需要先安装 ruby 的运行环境和 ruby 的 redis 客户端,该操作在其中一台服务器上进行即可(这里在master1上操作)。gem命令是提前下载的 redis-3.2.0.gem 软件包提供的,直接上传即可使用。
[root@master1 ~]# ls
anaconda-ks.cfg redis-3.2.0.gem redis-4.0.9.tar.gz
[root@master1 ~]# yum -y install ruby rubygems
[root@master1 ~]# gem install redis --version 3.2.0
Successfully installed redis-3.2.0
Parsing documentation for redis-3.2.0
Installing ri documentation for redis-3.2.0
1 gem installed
创建集群
使用源码解压目录中的 redis-trib.rb 工具创建群集。六个实例分为三组,每组一主一从, --replicas 1 表示每组一个从,下面交互的时候需要输入 yes 才可以创建。
[root@master1 ~]# cd /usr/src/redis-4.0.9/src/
[root@master1 src]# ./redis-trib.rb create --replicas 1 192.168.23.208:6379 192.168.23.209:6379 192.168.23.210:6379 192.168.23.211:6379 192.168.23.212:6379 192.168.23.213:6379
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
192.168.23.208:6379
192.168.23.209:6379
192.168.23.210:6379
Adding replica 192.168.23.212:6379 to 192.168.23.208:6379
Adding replica 192.168.23.213:6379 to 192.168.23.209:6379
Adding replica 192.168.23.211:6379 to 192.168.23.210:6379
M: 35a9152a7abbf511d7867d43600598ae0b23e198 192.168.23.208:6379
slots:0-5460 (5461 slots) master
M: 11147fea9d52437d3b26ca19f0689c3fc4f02d1f 192.168.23.209:6379
slots:5461-10922 (5462 slots) master
M: 1f60ae3203c794bb61c5cf066dff73ecaed7e79c 192.168.23.210:6379
slots:10923-16383 (5461 slots) master
S: 34a1c7e7c8fb5ccae1040db3e3032dc722b527e9 192.168.23.211:6379
replicates 1f60ae3203c794bb61c5cf066dff73ecaed7e79c
S: bc1b96e3fed105d4991e2bd14ad1071912fa6560 192.168.23.212:6379
replicates 35a9152a7abbf511d7867d43600598ae0b23e198
S: b733301329cfb79c2fb06007262f1fb00a134409 192.168.23.213:6379
replicates 11147fea9d52437d3b26ca19f0689c3fc4f02d1f
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join....
>>> Performing Cluster Check (using node 192.168.23.208:6379)
M: 35a9152a7abbf511d7867d43600598ae0b23e198 192.168.23.208:6379
slots:0-5460 (5461 slots) master
1 additional replica(s)
M: 11147fea9d52437d3b26ca19f0689c3fc4f02d1f 192.168.23.209:6379
slots:5461-10922 (5462 slots) master
1 additional replica(s)
M: 1f60ae3203c794bb61c5cf066dff73ecaed7e79c 192.168.23.210:6379
slots:10923-16383 (5461 slots) master
1 additional replica(s)
S: b733301329cfb79c2fb06007262f1fb00a134409 192.168.23.213:6379
slots: (0 slots) slave
replicates 11147fea9d52437d3b26ca19f0689c3fc4f02d1f
S: 34a1c7e7c8fb5ccae1040db3e3032dc722b527e9 192.168.23.211:6379
slots: (0 slots) slave
replicates 1f60ae3203c794bb61c5cf066dff73ecaed7e79c
S: bc1b96e3fed105d4991e2bd14ad1071912fa6560 192.168.23.212:6379
slots: (0 slots) slave
replicates 35a9152a7abbf511d7867d43600598ae0b23e198
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
查看群集状态
[root@master1 src]# ./redis-trib.rb check 192.168.23.208:6379
>>> Performing Cluster Check (using node 192.168.23.208:6379)
M: 35a9152a7abbf511d7867d43600598ae0b23e198 192.168.23.208:6379
slots:0-5460 (5461 slots) master
1 additional replica(s)
M: 11147fea9d52437d3b26ca19f0689c3fc4f02d1f 192.168.23.209:6379
slots:5461-10922 (5462 slots) master
1 additional replica(s)
M: 1f60ae3203c794bb61c5cf066dff73ecaed7e79c 192.168.23.210:6379
slots:10923-16383 (5461 slots) master
1 additional replica(s)
S: b733301329cfb79c2fb06007262f1fb00a134409 192.168.23.213:6379
slots: (0 slots) slave
replicates 11147fea9d52437d3b26ca19f0689c3fc4f02d1f
S: 34a1c7e7c8fb5ccae1040db3e3032dc722b527e9 192.168.23.211:6379
slots: (0 slots) slave
replicates 1f60ae3203c794bb61c5cf066dff73ecaed7e79c
S: bc1b96e3fed105d4991e2bd14ad1071912fa6560 192.168.23.212:6379
slots: (0 slots) slave
replicates 35a9152a7abbf511d7867d43600598ae0b23e198
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
从上面 replicates 的值可以看到相对应的主从关系:192.168.23.211 是 192.168.23.210 的从、192.168.23.212 是 192.168.2.208 的从、192.168.23.213 是 192.168.23.209 的从。但是,这样创建的集群在生产环境可能会有一个问题,每一组的主从都是随机产生的。那随机产生的弊端就是,有些服务器性能参差不齐,一但主节点分配到性能不佳的服务器上,可能就会影响 Redis 集群整体的性能。
2.4、调整组的主从
使用上述方法创建群集时的主从关系是随机生成的,下面介绍通过命令工具调整为如下表所示的主从对应关系。
主 | 从 |
192.168.23.208 | 192.168.23.211 |
192.168.23.209 | 192.168.23.212 |
192.168.23.210 | 192.168.23.213 |
主从 ip 分配
1)删除原有集群中的所有从节点
[root@master1 ~]# /usr/src/redis-4.0.9/src/redis-trib.rb del-node 192.168.23.211:6379 34a1c7e7c8fb5ccae1040db3e3032dc722b527e9
>>> Removing node 34a1c7e7c8fb5ccae1040db3e3032dc722b527e9 from cluster 192.168.23.211:6379
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
[root@master1 ~]# /usr/src/redis-4.0.9/src/redis-trib.rb del-node 192.168.23.212:6379 bc1b96e3fed105d4991e2bd14ad1071912fa6560
>>> Removing node bc1b96e3fed105d4991e2bd14ad1071912fa6560 from cluster 192.168.23.212:6379
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
[root@master1 ~]# /usr/src/redis-4.0.9/src/redis-trib.rb del-node 192.168.23.213:6379 b733301329cfb79c2fb06007262f1fb00a134409
>>> Removing node b733301329cfb79c2fb06007262f1fb00a134409 from cluster 192.168.23.213:6379
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
2)删除节点配置文件和持久化配置文件
三台从节点上操作
[root@slave1 ~]# cd /var/lib/redis/6379/
[root@slave1 6379]# ls
appendonly.aof dump.rdb nodes-6379.conf
[root@slave1 6379]# rm -rf *
[root@slave1 ~]# /etc/init.d/redis_6379 restart
[root@slave2 ~]# cd /var/lib/redis/6379/
[root@slave2 6379]# ls
appendonly.aof dump.rdb nodes-6379.conf
[root@slave2 6379]# rm -rf *
[root@slave2 6379]# /etc/init.d/redis_6379 restart
[root@slave3 ~]# cd /var/lib/redis/6379/
[root@slave3 6379]# ls
appendonly.aof dump.rdb nodes-6379.conf
[root@slave3 6379]# rm -rf *
[root@slave3 6379]# /etc/init.d/redis_6379 restart
3)重新添加从节点
master1上面操作
[root@master1 ~]# /usr/src/redis-4.0.9/src/redis-trib.rb add-node --slave --master-id 35a9152a7abbf511d7867d43600598ae0b23e198 192.168.23.211:6379 192.168.23.208:6379
[root@master1 ~]# /usr/src/redis-4.0.9/src/redis-trib.rb add-node --slave --master-id 11147fea9d52437d3b26ca19f0689c3fc4f02d1f 192.168.23.212:6379 192.168.23.209:6379
[root@master1 ~]# /usr/src/redis-4.0.9/src/redis-trib.rb add-node --slave --master-id 1f60ae3203c794bb61c5cf066dff73ecaed7e79c 192.168.23.213:6379 192.168.23.210:6379
4)检查新的主从关系
[root@master1 ~]# /usr/src/redis-4.0.9/src/redis-trib.rb check 192.168.23.208:6379
>>> Performing Cluster Check (using node 192.168.23.208:6379)
M: 35a9152a7abbf511d7867d43600598ae0b23e198 192.168.23.208:6379
slots:0-5460 (5461 slots) master
1 additional replica(s)
S: 219aaf7419735dab06164c8c4da6b9467dad9eaf 192.168.23.212:6379
slots: (0 slots) slave
replicates 11147fea9d52437d3b26ca19f0689c3fc4f02d1f
M: 11147fea9d52437d3b26ca19f0689c3fc4f02d1f 192.168.23.209:6379
slots:5461-10922 (5462 slots) master
1 additional replica(s)
M: 1f60ae3203c794bb61c5cf066dff73ecaed7e79c 192.168.23.210:6379
slots:10923-16383 (5461 slots) master
1 additional replica(s)
S: fe3ed99ec2b50c1fa909289fd5d31172c53f483c 192.168.23.211:6379
slots: (0 slots) slave
replicates 35a9152a7abbf511d7867d43600598ae0b23e198
S: d1ea841cb1ea17c9d6b75188029cc9dbecaf3928 192.168.23.213:6379
slots: (0 slots) slave
replicates 1f60ae3203c794bb61c5cf066dff73ecaed7e79c
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
5)测试 Redis 集群
测试 Redis 集群是否可以写入数据,这里随便挑选一个 192.168.23.208 实例插入 key 为 name、value 为 zhangsan 这条数据,可以清楚看到从 192.168.23.208 实例跳转到了 192.168.23.209 实例。也就是说 Redis 会根据不同的类型数据存储到不同的 slot 里面。在执行测试命令时添加-c 选项表示群集模式。
[root@master1 ~]# /usr/local/redis/bin/redis-cli -c -h 192.168.23.208
192.168.23.208:6379> set name zhangsan
-> Redirected to slot [5798] located at 192.168.23.209:6379
OK
在192.168.23.210实例上查看
[root@master3 ~]# /usr/local/redis/bin/redis-cli -c -h 192.168.23.210
192.168.23.210:6379> get name
-> Redirected to slot [5798] located at 192.168.23.209:6379
"zhangsan"
至此,Redis 群集就部署完成。