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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章