背景
在测试服务器(CentOS 系统)上搭建 Redis 集群,这里一步步实践并整理一些较好的步骤。
正文
简单安装请参照官方文档:Redis Quick Start。
- 前提
- 搭建
- 测试
- 维护
前提
在搭建集群之前,需要明确一下情况。
-
版本
目前安装的是3.2.11
版本,在有些 CentOS 上内置的就是它,所以导致目前项目都用的这个版本。 -
安装
默认的编译安装只需要使用make install
命令,所以依赖的无非是gcc
和gcc-c++
这两个编译工具,install
命令也仅仅是将redis-*
系列拷贝到/usr/local/bin
目录下。 -
更正确的配置
建立/etc/redis
和/var/redis
目录,拷贝redis.conf
为/etc/redis/6380.conf
。
在6380.conf
中,bind
设为192.168.1.57
,port
设为6380
,daemonize
设为yes
,pidfile
指向/var/run/redis_6380.pid
,logfile
指向/var/log/redis_6380.log
,dir
指向/var/redis/6380
。
搭建
有了前提条件,接下来就参考官方 Redis Cluster 文档来实践一番。
- 配置
- 创建
配置
集群的配置稍微比【更正确的配置】要多一些。
根据 Redis Cluster 以及 redis.conf
中的解释:
-
cluster-enable yes
yes
表示在特定实例(以此配置文件启动的实例)中启用集群支持;no
表示作为独立实例启动。 -
cluster-config-file nodes.conf
每个集群节点都有这个配置文件,但用户不能手动编辑内容,它是由节点自己创建和更新。每个节点需要有不同的配置文件,请确保同一个系统中的不同节点,不会覆盖这个配置文件(即:不同的实例,配置文件中的dir
必须指向不同的目录)。 -
cluster-node-timeout 5000
集群节点超时是节点在确认失败的状态下,持续不可访问的毫秒总时长,大多数其他内部时间限制是节点超时的倍数。 -
cluster-slave-validity-factor 0
对于主节点来说,这个因数乘以超时值,表示主节点最终确认故障的时间范围;对于从节点来说,在因数乘以超时值的时间范围内,将不会进行故障转移(成为主节点)。如果因数设为 0,则始终在主节点不可用时进行故障切换,这也是唯一能保证最大可用性的参数。 -
cluster-migration-barrier 1
默认是1,表示所有主节点在正常状态下,应当保持的从节点数量。比如当前主节点拥有 2 个从节点,另外有个主节点的从节点出现故障,又没有其他从节点可用,此时当前主节点下的一个从节点会自动迁移到另外的主节点下。如果当前主节点只有 1 个从节点,那么将不会进行切换。这个值可以是 0,在调试时可用,但在生产中很危险。 -
cluster-require-full-coverage yes
yes
是默认情况,表示只要有一个散列槽未被使用(没有节点服务于它),那么集群将不可用;no
表示服务于其他散列槽的节点继续接受查询。
完整的配置参数如下:
bind 192.168.1.57
protected-mode yes
port 6380
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
supervised no
pidfile /var/run/redis_6380.pid
loglevel notice
logfile "/var/log/redis_6380.log"
database 16
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /var/redis/6380
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay on
slave-priority 100
appendonly 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
lua-time-limit 5000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-slave-validity-factor 0
cluster-migration-barrier 1
cluster-require-full-coverage yes
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
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes
创建
为了建立主从模式,将 6380.conf
拷贝一份 6381.conf
,然后 修改所有端口相关参数,以及建立相应的 /var/redis/6380
和 /var/redis/6381
目录。
集群的创建需要先启动实例,可以拷贝启动脚本 /usr/local/redis/redis-3.2.11/utils/redis_init_script
为
/etc/init.d/redis_6380
和 /etc/init.d/redis_6381
,修改所有相关端口参数 后,再使用 sudo /etc/init.d/redis_6380 start
命令启动实例。
实例启动状态如下:
为了保证集群最小可用性,需要在 192.168.1.127
和 192.168.1.8
上面也启动 6380
和 6381
实例。
另外需要安装:
sudo gem install redis
对于 Redis 3.2.11
版本来说,应该安装(否则,会遇到后面【重新分片】的坑):
sudo gem install redis -v 3.3.3
注意:gem
需要 ruby 2.2.2
以上版本,请知悉。
随后使用命令创建集群:
redis-trib.rb create --replicas 1 192.168.1.8:6380 192.168.1.8:6381 192.168.1.127:6380 192.168.1.127:6381 192.168.1.57:6380 192.168.1.57:6381
注意:--replicas
参数表示希望每个主节点都有指定的从节点,这里是 1 个。后面的 IP 地址 + 端口号,就是初始创建的集群列表。
创建成功:
如果多台服务器配置起来很繁琐,可以试着用一下:Redis Cluster 脚本。
测试
参考官方文档进行测试。
尝试连接:
redis-cli -c -p 6380
连接失败:
这是集群 bind
了一个局域网地址,需要使用 -h
设置 IP 地址参数:
redis-cli -c -h 192.168.1.8 -p 6380
成功连接:
测试通过:
维护
首先,需要有 2.2.2
以上的 Ruby
环境,然后去 redis-rb-cluster 下载文件:
- 简单示例 + 重新分片
- 有趣示例 + 故障转移
- 其他维护命令
简单示例 + 重新分片
对于 example.rb
文件,需要修改的地方是:
if ARGV.length != 2
startup_nodes = [
{:host => "192.168.1.8", :port => 6380},
{:host => "192.168.1.8", :port => 6381}
]
else
然后开始运行 ruby ./example.rb
,接着会得到一长串的数字递增,此时可以保留这个窗口。
打开新的窗口,准备重新分片:
redis-trib.rb reshard 192.168.1.8:6380
显示结果:
移动 1000
个哈希槽(建议保持 example.rb
在运行状态):
需要一个目标节点的 ID,这从【显示结果】的图中可以找到:
输入 0471fb34c39dbb9338b56c474f59b3e745a1cc8f
之后,会被询问从哪些节点获取哈希槽:
官方指引输入 all
:
但我这边 出现错误,那么使用 check
参数检查哪里出了问题:
再按照提示,使用 fix
参数修复问题(我尝试过从编译文件更新 redis-trib.rb
文件):
问题依然存在,自动修复出错。
搜索 错误提示 后,找到:redis cluster3.2.0注意点。
登陆客户端:
redis-cli -c -h 192.168.1.8 -p 6380
执行命令:
cluster setslot 5461 stable
效果如图:
再检查一下:
有可能还需要对 192.168.1.127:6380
进行同样的操作:
OK!总算恢复了正常。
再试试在停止 example.rb
脚本的情况下,执行重新分片:
这是从 192.168.1.8
的 主节点 6380
开始,执行 1000
个哈希槽的重新分片,从所有节点转移到 192.168.1.127
的 主节点 6380
中,依然是同样的错误。
说明应该是 redis-trib.rb
脚本出了问题,但我尝试过拷贝相同版本编译后的文件,问题依然得不到解决。
百度不出来什么结果,于是谷歌一下,立即得到答案:
Just installing an earlier version of redis.rb fixes the issue. This worked for me:
gem install redis -v 3.3.3
原问题贴在这里:https://github.com/antirez/redis/issues/4272
执行效果:
那么,我最后再尝试一下 reshard
,再不行不搞了。
当然,得先启动 example.rb
,得到最佳效果,然后再重新分片:
完美!!!没有出错:
测试一下运行状态:
正如预期的那样,从其他主节点分配总共 1000
个哈希槽到 192.168.1.127
主节点中。
可以将 重新分片 的操作汇合成一条命令:
./redis-trib.rb reshard --from <node-id> --to <node-id> --slots <number of slots> --yes <host>:<port>
有趣示例 + 故障转移
接下来我们运行 consistency-test.rb
来看看一致性问题:
ruby ./consistency-test.rb 192.168.1.8 6380
效果如图:
手动重置计数器:
redis-cli -c -h 192.168.1.8 -p 6380 set key_217 0
并没有出现 114 lost
,但我已经不想追究根源,还不如测试一下故障转移:
redis-cli -c -h 192.168.1.8 -p 6380 debug segfault
看到了信息:
现在我们重新启动 192.168.1.8:6380
,然后查看集群状态:
可以发现:192.168.1.8:6380
成为新主节点 192.168.1.127:6381
的从节点,原来的从节点 192.168.1.8:6381
成为主节点 192.168.1.127:6380
的从节点(意味着并没有升级为主节点)。
其他维护命令
-
手动故障转移:
cluster failover
(需要用redis-cli
登录从节点)
通常在没有故障但需要切换主从节点时使用,具体细节参考:cluster-failover。
效果如图:
-
添加新节点:
redis-trib.rb add-node 192.168.1.8:6382 192.168.1.8:6380
第一个参数是新建立的 Redis 实例,它是一个空节点;第二个参数是集群中任何一个已存在的节点。
效果如图:
通过192.168.1.8:6382
客户端,检查集群:
提示:空节点已加入集群,但它没有分配哈希槽,因此也没有任何数据,不会被其他从节点选择作为主人。
可以重新分片,以便重新分配哈希槽,但基本上无用,只是在重新分区。 -
添加新节点为副本:
redis-trib.rb add-node --slave 192.168.1.8:6382 192.168.1.8:6380
但这是不可能有效的:
必须要是一个空节点,才能这样做,那已经成为主节点的192.168.1.8:6382
怎么办?
可以使用cluster replicate [id]
来成为目标节点的从节点:
-
删除节点:
redis-trib.rb del-node 192.168.1.8:6380 f049c4f7a81a34f5a66248306f82e6317404b84d
第一个参数是集群中任何一个节点;第二个参数是需要删除的节点 ID。
效果如图:
如果要用这个命令删除主节点,那么此主节点 必须为空,否则就要把它的数据重新分配给所有其他主节点。另外一种办法是使用cluster replicate [id]
将主节点降级,成为从节点之后,可以继续删除节点。如果你必须减少集群中的主节点数量,那么你应该重新分片,使某些主节点不再拥有哈希槽和数据,然后再删除它们。 -
副本迁移:
cluster replicate [id]
简单来说,当你不希望某个主节点下的从节点先挂掉,然后主节点相继挂掉,此时集群处于不可用状态(没有挂掉主节点的哈希槽副本),那么你就应该执行这些步骤:- 每个主节点至少分配一个从节点
- 额外增加一些从节点,可以是集群中的任意主节点
- 所有集群节点的配置参数,
cluster-migration-barrier
设为1
,保证迁移功能正常
-
升级节点:
cluster replicate [id]
同样的命令,但可以做很多事情。概念比较复杂,建议阅读官方文档 Redis Cluster,在此不做误人解释。 -
迁移群集
概念比较复杂,建议同上。
总结
Redis 集群比其他 NoSQL
数据库复杂得多,据我所知,Cassnadra
和 Elasticsearch
只需要修改配置,启动,然后便是正常使用。即使前面以单机形式启动过,也只需要刷新一下系统信息表而已。
复杂的事物总显得高大上,希望后面维护起来会比 Cassandra
和 Elasticsearch
要轻松很多吧。
网友评论