redis集群的搭建
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redis集群的搭建相关的知识,希望对你有一定的参考价值。
redis集群的搭建
本文使用的是3台主机,每台主机2个节点,3台maser,3台salve的环境。
1. 环境介绍:
3台CentOS release 6.9服务器
192.168.1.35 192.168.1.36 192.168.1.37
redis-4.0.9.tar.gz
ruby-2.4.4.tar.gz
2. 软件安装
安装redis:
本文中的环境默认是不能连接外网的。所以软件包只能通过跳板机或者其他的机器通过scp上传。
编译安装:
tar -xf redis-4.0.9.tar.gz mkdir -p /usr/local/redis mv redis-4.0.9/* /usr/local/redis/ cd /usr/local/redis/ make && make install
创建redis节点:
mkdir -p redis_cluster/{7000,7001} cp redis.conf redis_cluster/7000 cp redis.conf resis_cluster/7001
分别修改7000/7001里面的配置文件的内容:
port 7000 //端口7000,7001 bind 192.168.1.35 //改为35,36,37 daemonize yes //redis后台运行 pidfile /var/run/redis_7000.pid //pid对应7000,7001 cluster-enabled yes //开启集群 cluster-config-file nodes_7000.conf //指定集群的配置文件,自动生成 cluster-node-timeout 15000 //设置集群超时时间 appendonly yes //aof日志开启,它会每次写操作都记录一条日志
在另外的两台机器上重复上面的配置规则
启动各个节点(另外两台也是同样地):
redis-server redis_cluster/7000/redis.conf
redis-server redis_cluster/7001/redis.conf
查看各个节点是否起来: $ ss -tnlp|grep redis LISTEN 0 511 192.168.1.35:17000 *:* users:(("redis-server",24909,9)) LISTEN 0 511 192.168.1.35:17001 *:* users:(("redis-server",24914,9)) LISTEN 0 511 192.168.1.35:7000 *:* users:(("redis-server",24909,6)) LISTEN 0 511 192.168.1.35:7001 *:* users:(("redis-server",24914,6))
安装ruby:
tar -xf ruby-2.4.4.tar.gz cd ruby-2.4.4 ./configure --prefix=/usr/local/ruby make && make install /usr/local/ruby/bin/gem install redis
或者
安装gem和redis的插件(https://rubygems.global.ssl.fastly.net/gems/redis-3.2.2.gem) # gem install -l redis-3.2.2.gem
3. 集群创建
redis-trib.rb是redis官方推出的redis集群管理的工具,这个工具在redis的src目录下。
/usr/local/ruby/bin/ruby /usr/local/redis/src/redis-trib.rb create --replicas 1 192.168.1.35:7000 192.168.1.35:7001 192.168.1.36:7000 192.168.1.36:70001 192.168.1.37:7000 192.168.1.37:7001
--replicas:指定每个主节点有几个从节点 注意:需要有3个或者以上的主节点,否则在创建集群是会失败,并且存活的主节点数小于总节点数的一半时,整个集群就无法提供服务了。 原理:redis cluster在设计的时候,就考虑到了去中心化去中间件,就是说,集群中的每个节点都是平等的关系,都是对等的,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据。 Redis 集群没有并使用传统的一致性哈希来分配数据,而是采用另外一种叫做哈希槽 (hash slot)的方式来分配的。redis cluster 默认分配了 16384 个slot,当我们set一个key 时,会用CRC16算法来取模得到所属的slot,然后将这个key 分到哈希槽区间的节点上,具体算法就是:CRC16(key) % 16384。所以我们在测试的时候看到set 和 get 的时候,直接跳转到了7000端口的节点。 Redis 集群会把数据存在一个 master 节点,然后在这个 master 和其对应的salve 之间进行数据同步。当读取数据时,也根据一致性哈希算法到对应的 master 节点获取数据。只有当一个master 挂掉之后,才会启动一个对应的 salve 节点,充当 master 。
4.集群验证:
可以通过随便在一台机器上创建数据来验证整个集群。
通过redis-cli命令来登陆 $ redis-cli -h 192.168.1.35 -c -p 7000 192.168.1.37:7000> set hello world -> Redirected to slot [866] located at 192.168.1.35:7000 OK 192.168.1.35:7000> keys * 1) "hello"
然后登陆另外一台的7000端口,查看key的内容。
$ redis-cli -h 192.168.1.36 -c -p 7000 192.168.1..36:7000> get hello -> Redirected to slot [866] located at 192.168.1.35:7000 "world" 192.168.1.35:7000>
如果其他节点可以读取得到就说明集群运行正常。
5.redis集群管理工具redis-trib.rb
redis-trib.rb是redis官方推出的管理redis集群的工具,集成在redis的源码src目录下,是基于redis提供的集群命令封装成简单、便捷、实用的操作工具。
redis-trib.rb的功能参数:
Usage: redis-trib <command> <options> <arguments ...> create host1:port1 ... hostN:portN --replicas <arg> check host:port info host:port fix host:port --timeout <arg> reshard host:port --from <arg> --to <arg> --slots <arg> --yes --timeout <arg> --pipeline <arg> rebalance host:port --weight <arg> --auto-weights --use-empty-masters --timeout <arg> --simulate --pipeline <arg> --threshold <arg> add-node new_host:new_port existing_host:existing_port --slave --master-id <arg> del-node host:port node_id set-timeout host:port milliseconds call host:port command arg arg .. arg import host:port --from <arg> --copy --replace help (show this help) For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.
简单来看:redis-trib.rb提供了以下的功能:
create | 创建集群 |
check | 检查集群 |
info | 查看集群信息 |
fix | 修复集群 |
reshard | 在线迁移集群 |
rebalance | 平衡集群节点的slot数量 |
add-node | 将节点加入新的集群 |
del-node | 从集群中删除节点 |
set-timout | 设置集群节点间的心跳连接超时时间 |
call | 在集群全部节点上执行命令 |
import | 将外部的redis数据导入集群 |
create创建集群:
可选参数为replicas,表示需要几个slave。
简单用法:
ruby redis-trib.rb create 192.168.1.20:7000 192.168.1.21:7000 192.168.1.22:7000
有一个从节点的创建命令:
ruby redis-trib.rb create --replicas 1 192.168.1.20:7000 192.168.1.21:7000 192.168.1.22:7000 192.168.1.23:7000 192.168.1.24:7000 192.168.1.25:7000
创建流程如下:
1、首先为每个节点创建ClusterNode对象,包括连接每个节点。检查每个节点是否为独立且db为空的节点。执行load_info方法导入节点信息。
2、检查传入的master节点数量是否大于等于3个。只有大于3个节点才能组成集群。
3、计算每个master需要分配的slot数量,以及给master分配slave。分配的算法大致如下: 先把节点按照host分类,这样保证master节点能分配到更多的主机中。 不停遍历遍历host列表,从每个host列表中弹出一个节点,放入interleaved数组。直到所有的节点都弹出为止。 master节点列表就是interleaved前面的master数量的节点列表。保存在masters数组。 计算每个master节点负责的slot数量,保存在slots_per_node对象,用slot总数除以master数量取整即可。 遍历masters数组,每个master分配slots_per_node个slot,最后一个master,分配到16384个slot为止。 接下来为master分配slave,分配算法会尽量保证master和slave节点不在同一台主机上。对于分配完指定slave数量的节点,还有多余的节点,也会为这些节点寻找master。分配算法会遍历两次masters数组。 第一次遍历masters数组,在余下的节点列表找到replicas数量个slave。每个slave为第一个和master节点host不一样的节点,如果没有不一样的节点,则直接取出余下列表的第一个节点。 第二次遍历是在对于节点数除以replicas不为整数,则会多余一部分节点。遍历的方式跟第一次一样,只是第一次会一次性给master分配replicas数量个slave,而第二次遍历只分配一个,直到余下的节点被全部分配出去。
4、打印出分配信息,并提示用户输入“yes”确认是否按照打印出来的分配方式创建集群。
5、输入“yes”后,会执行flush_nodes_config操作,该操作执行前面的分配结果,给master分配slot,让slave复制master,对于还没有握手(cluster meet)的节点,slave复制操作无法完成,不过没关系,flush_nodes_config操作出现异常会很快返回,后续握手后会再次执行flush_nodes_config。
6、给每个节点分配epoch,遍历节点,每个节点分配的epoch比之前节点大1。
7、节点间开始相互握手,握手的方式为节点列表的其他节点跟第一个节点握手。
8、然后每隔1秒检查一次各个节点是否已经消息同步完成,使用ClusterNode的get_config_signature方法,检查的算法为获取每个节点cluster nodes信息,排序每个节点,组装成node_id1:slots|node_id2:slot2|...的字符串。如果每个节点获得字符串都相同,即认为握手成功。
9、此后会再执行一次flush_nodes_config,这次主要是为了完成slave复制操作。
10、最后再执行check_cluster,全面检查一次集群状态。包括和前面握手时检查一样的方式再检查一遍。确认没有迁移的节点。确认所有的slot都被分配出去了。
11、至此完成了整个创建流程,返回[OK]
check检查集群
使用check来检查集群的状态。只需要选择其中的一个节点即可:
$ /usr/local/ruby/bin/ruby /usr/local/redis/src/redis-trib.rb check 192.168.1.36:7000 >>> Performing Cluster Check (using node 192.168.1.36:7000) M: 631e3b56a0895f5ac62b15ad7467752877d8079e 1192.168.1.36:7000 slots:5461-10922 (5462 slots) master 1 additional replica(s) M: d35e7bd3a31054b96dfe2d08d7472731753d6ceb 192.168.1.37:7000 slots:10923-16383 (5461 slots) master 1 additional replica(s) M: 06fbb8062252b78093d4ef50188199a580bb86bd 192.168.1.35:7000 slots:0-5460 (5461 slots) master 1 additional replica(s) S: 4e26eac416d32421800f91f78a9df070aa7d0855 192.168.1.35:7001 slots: (0 slots) slave replicates d35e7bd3a31054b96dfe2d08d7472731753d6ceb S: 8090354b1b3575ae1e331841964c6c33c55897da 192.168.1.37:7001 slots: (0 slots) slave replicates 631e3b56a0895f5ac62b15ad7467752877d8079e S: 0909bb82f88e0755bab3bc06f1cc3b4325c2a869 192.168.1.36:7001 slots: (0 slots) slave replicates 06fbb8062252b78093d4ef50188199a580bb86bd [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
info查看集群的信息
info命令用来查看集群的信息,同样只需要指定一个节点即可:
/usr/local/ruby/bin/ruby /usr/local/redis/src/redis-trib.rb info 192.168.1.36:7000 192.168.1.36:7000 (631e3b56...) -> 1 keys | 5462 slots | 1 slaves. 192.168.1.37:7000 (d35e7bd3...) -> 0 keys | 5461 slots | 1 slaves. 192.168.1.35:7000 (06fbb806...) -> 1 keys | 5461 slots | 1 slaves. [OK] 2 keys in 3 masters. 0.00 keys per slot on average.
fix修复集群:
fix命令的流程跟check的流程很像,显示加载集群信息,然后在check_cluster方法内传入fix为 true的变量,会在集群检查出现异常的时候执行修复流程。目前fix命令能修复两种异常,一种是集群有处于迁移中的slot的节点,一种是slot未完全分配的异常。
fix_open_slot方法是修复集群有处于迁移中的slot的节点异常:
1、先检查该slot是谁负责的,迁移的源节点如果没完成迁移,owner还是该节点。没有owner的slot无法完成修复功能。
2、遍历每个节点,获取哪些节点标记该slot为migrating状态,哪些节点标记该slot为importing状态。对于owner不是该节点,但是通过cluster countkeysinslot获取到该节点有数据的情况,也认为该节点为importing状态。
3、如果migrating和importing状态的节点均只有1个,这可能是迁移过程中redis-trib.rb被中断所致,直接执行move_slot继续完成迁移任务即可。传递dots和fix为true。
4、如果migrating为空,importing状态的节点大于0,那么这种情况执行回滚流程,将importing状态的节点数据通过move_slot方法导给slot的owner节点,传递dots、fix和cold为true。接着对importing的节点执行cluster stable命令恢复稳定。
5、如果importing状态的节点为空,有一个migrating状态的节点,而且该节点在当前slot没有数据,那么可以直接把这个slot设为stable。
6、如果migrating和importing状态不是上述情况,目前redis-trib.rb工具无法修复,上述的三种情况也已经覆盖了通过redis-trib.rb工具迁移出现异常的各个方面,人为的异常情形太多,很难考虑完全。 fix_slots_coverage方法能修复slot未完全分配的异常:
未分配的slot有三种状态:
1、所有节点的该slot都没有数据。该状态redis-trib.rb工具直接采用随机分配的方式,并没有考虑节点的均衡。本人尝试对没有分配slot的集群通过fix修复集群,结果slot还是能比较平均的分配,但是没有了连续性,打印的slot信息非常离散。
2、有一个节点的该slot有数据。该状态下,直接把slot分配给该slot有数据的节点。
3、有多个节点的该slot有数据。此种情况目前还处于TODO状态,不过redis作者列出了修复的步骤,对这些节点,除第一个节点,执行cluster migrating命令,然后把这些节点的数据迁移到第一个节点上。清除migrating状态,然后把slot分配给第一个节点。
reshard在线迁移slot:
reshard命令可以在线把集群的一些slot从集群原来slot负责节点迁移到新的节点,利用reshard可以完成集群的在线横向扩容和缩容。
reshard的参数介绍:
reshard host:port 指定从哪个节点获取集群的信息 --from 需要从哪些节点上迁移slot。--from all 所有节点 --to slot需要迁移的目的节点node id --slots 需要迁移的slot数量 --yes 设置该参数,会提示输入yes后再执行reshard --timeout 设置migrate命令的超时时间 --pipeline 定义cluster getkeysinslot一次取出的key数量,默认为10
参考文献
redis集群教程
redis集群规范
https://redis.io/topics/cluster-spec
https://redis.io/topics/cluster-tutorial
以上是关于redis集群的搭建的主要内容,如果未能解决你的问题,请参考以下文章