测试环境: centos7.6

redis集群详细知识请参见:redis官方集群教程

由于redis每个集群中至少需要三个主数据库才能正常运行,所以这里用两台虚拟机创建6个redis节点,每台机器3个节点。创建出3 master、3 salve 的环境。

两台测试服务器ip为 192.168.73.128,192.168.73.129

1、下载安装redis

redis集群需要3.0或更高版本,这里使用的使用的是redis3.2.1版本。

  1. cd /usr/local/src
  2. wget http://download.redis.io/releases/redis-3.2.1.tar.gz
  3. tar -xvf redis-3.2.1
  4. cd redis-3.2.1
  5. make
  6. make install

2、创建redis节点

1、 在其中一台机器创建redis_cluster目录

  1. mkdir redis_cluster

2、 在redis_cluster目录下创建名为7000、7001、7002(为三个redis节点的端口号,可自行选择),并将 redis.conf 拷贝到这三个目录中并根据端口重命名

  1. cp redis.conf redis_cluster/redis_7000.conf
  2. cp redis.conf redis_cluster/redis_7001.conf
  3. cp redis.conf redis_cluster/redis_7002.conf

3、 分别修改这三个配置文件,修改如下内容

  1. port 7000 //端口7000,7001,7002
  2. bind 本机ip //默认ip为127.0.0.1 需要改为其他节点机器可访问的ip 否则创建集群时无法访问对应的端口,无法创建集群,这里作为测试改的为 0.0.0.0
  3. daemonize yes //redis后台运行
  4. pidfile /var/run/redis_7000.pid //pidfile文件对应7000,7001,7002
  5. cluster-enabled yes //开启集群 把注释#去掉
  6. cluster-config-file nodes_7000.conf //集群的配置 配置文件首次启动自动生成 7000,7001,7002
  7. cluster-node-timeout 15000 //请求超时 默认15秒,可自行设置
  8. appendonly yes //aof日志开启 有需要就开启,它会每次写操作都记录一条日志

另一台机器操作重复上面三步。把以上三个端口改成7003、7004、7005,配置文件也按照上面规则。

3、启动节点

  1. # 在第一台机器
  2. ./src/redis-server ./redis_cluster/redis_7000.conf
  3. ./src/redis-server ./redis_cluster/redis_7001.conf
  4. ./src/redis-server ./redis_cluster/redis_7002.conf
  5. # 另外一台机器
  6. ./src/redis-server ./redis_cluster/redis_7003.conf
  7. ./src/redis-server ./redis_cluster/redis_7004.conf
  8. ./src/redis-server ./redis_cluster/redis_7005.conf

查看redis启动情况

  1. # 第一台机器
  2. [root@localhost redis-3.2.1]# netstat -tnlp | grep redis
  3. tcp 0 0 0.0.0.0:17000 0.0.0.0:* LISTEN 22966/./src/redis-s
  4. tcp 0 0 0.0.0.0:17001 0.0.0.0:* LISTEN 22971/./src/redis-s
  5. tcp 0 0 0.0.0.0:17002 0.0.0.0:* LISTEN 22976/./src/redis-s
  6. tcp 0 0 0.0.0.0:7000 0.0.0.0:* LISTEN 22966/./src/redis-s
  7. tcp 0 0 0.0.0.0:7001 0.0.0.0:* LISTEN 22971/./src/redis-s
  8. tcp 0 0 0.0.0.0:7002 0.0.0.0:* LISTEN 22976/./src/redis-s
  9. # 另外一台机器
  10. [root@localhost redis-3.2.1]# netstat -tnlp | grep redis
  11. tcp 0 0 0.0.0.0:17003 0.0.0.0:* LISTEN 22021/./src/redis-s
  12. tcp 0 0 0.0.0.0:17004 0.0.0.0:* LISTEN 22025/./src/redis-s
  13. tcp 0 0 0.0.0.0:17005 0.0.0.0:* LISTEN 22029/./src/redis-s
  14. tcp 0 0 0.0.0.0:7003 0.0.0.0:* LISTEN 22021/./src/redis-s
  15. tcp 0 0 0.0.0.0:7004 0.0.0.0:* LISTEN 22025/./src/redis-s
  16. tcp 0 0 0.0.0.0:7005 0.0.0.0:* LISTEN 22029/./src/redis-s
  17. [root@localhost redis-3.2.4]#

4、安装ruby

redis 官方提供的 redis-trib.rb 这个工具依赖环境 ruby,所以需要安装 ruby。经过测试ruby的最低版本要求为2.2.2,所以我们使用源码进行安装,ruby下载地址

  1. cd /usr/local/src
  2. # 下载并进行编译
  3. wget https://cache.ruby-lang.org/pub/ruby/2.4/ruby-2.4.5.tar.gz
  4. tar -xvzf ruby-2.4.5.tar.gz
  5. cd ruby-2.4.5
  6. ./configure
  7. make && make install

安装完成测试出现了点小问题,解决办法如下(如果gem出现一样问题,解决方法一样)

  1. # 安装好了,查看版本结果提示
  2. [root@localhost ruby-2.4.5]# ruby -v
  3. -bash: /usr/bin/ruby: 没有那个文件或目录
  4. # 输入命令 如果有版本信息,那说明ruby被装到了该目录下,而非系统认为的 /usr/bin/ruby
  5. [root@localhost ruby-2.4.5]# /usr/local/bin/ruby --version
  6. ruby 2.4.5p335 (2018-10-18 revision 65137) [x86_64-linux]
  7. # 解决方法是在系统默认运行ruby的位置[/usr/bin/ruby]创建一个symlink(相当于win下的快捷方式),指向ruby的实际位置[/usr/local/bin/ruby]
  8. [root@localhost ruby-2.4.5]# ln -s /usr/local/bin/ruby /usr/bin/ruby
  9. # 显示版本
  10. [root@localhost ruby-2.4.5]# ruby -v
  11. ruby 2.4.5p335 (2018-10-18 revision 65137) [x86_64-linux]
  12. # gem和ruby都显示正常才可正常使用
  13. [root@localhost ruby-2.4.5]# gem -v
  14. 2.6.14.3

安装redis依赖

  1. gem install redis

创建集群

先把src目录下的redis-trib.rb工具复制到/usr/local/bin目录下

  1. cp src/redis-trib.rb /usr/local/bin

然后使用下面这个命令即可完成安装(其中前三个 ip:port 为第一台机器的节点,剩下三个为第二台机器的节点。)

  1. redis-trib.rb create --replicas 1 192.168.73.128:7000 192.168.73.128:7001 192.168.73.128:7002 192.168.73.129:7003 192.168.73.129:7004 192.168.73.129:7005

运行后会出现如下提示

  1. [root@localhost ruby-2.4.5]# redis-trib.rb create --replicas 1 192.168.73.128:7000 192.168.73.128:7001 192.168.73.128:7002 192.168.73.129:7003 192.168.73.129:7004 192.168.73.129:7005
  2. >>> Creating cluster
  3. >>> Performing hash slots allocation on 6 nodes...
  4. Using 3 masters:
  5. 192.168.73.128:7000
  6. 192.168.73.129:7003
  7. 192.168.73.128:7001
  8. Adding replica 192.168.73.129:7004 to 192.168.73.128:7000
  9. Adding replica 192.168.73.128:7002 to 192.168.73.129:7003
  10. Adding replica 192.168.73.129:7005 to 192.168.73.128:7001
  11. M: 25b73f562c83675f1eeec369ac0af81357688d00 192.168.73.128:7000
  12. slots:0-5460 (5461 slots) master
  13. M: db89d77496ac4f160298b0e194d3584680fd1abf 192.168.73.128:7001
  14. slots:10923-16383 (5461 slots) master
  15. S: eb0acce0a2805b182267758c11dd6786c4bd01c5 192.168.73.128:7002
  16. replicates 765c0aa1aee15da9b78ad93173c9d25e71f58919
  17. M: 765c0aa1aee15da9b78ad93173c9d25e71f58919 192.168.73.129:7003
  18. slots:5461-10922 (5462 slots) master
  19. S: 4ba38d87cc3599b33cd485e74b86b0cc2be3563d 192.168.73.129:7004
  20. replicates 25b73f562c83675f1eeec369ac0af81357688d00
  21. S: 6489fd359ed4b9abe10974e93bc2cf173b58c3ea 192.168.73.129:7005
  22. replicates db89d77496ac4f160298b0e194d3584680fd1abf
  23. Can I set the above configuration? (type 'yes' to accept):

输入 yes 即可,然后出现如下内容,说明安装成功

  1. Can I set the above configuration? (type 'yes' to accept): yes
  2. >>> Nodes configuration updated
  3. >>> Assign a different config epoch to each node
  4. >>> Sending CLUSTER MEET messages to join the cluster
  5. Waiting for the cluster to join....
  6. >>> Performing Cluster Check (using node 192.168.73.128:7000)
  7. M: 25b73f562c83675f1eeec369ac0af81357688d00 192.168.73.128:7000
  8. slots:0-5460 (5461 slots) master
  9. 1 additional replica(s)
  10. S: 4ba38d87cc3599b33cd485e74b86b0cc2be3563d 192.168.73.129:7004
  11. slots: (0 slots) slave
  12. replicates 25b73f562c83675f1eeec369ac0af81357688d00
  13. S: eb0acce0a2805b182267758c11dd6786c4bd01c5 192.168.73.128:7002
  14. slots: (0 slots) slave
  15. replicates 765c0aa1aee15da9b78ad93173c9d25e71f58919
  16. M: 765c0aa1aee15da9b78ad93173c9d25e71f58919 192.168.73.129:7003
  17. slots:5461-10922 (5462 slots) master
  18. 1 additional replica(s)
  19. M: db89d77496ac4f160298b0e194d3584680fd1abf 192.168.73.128:7001
  20. slots:10923-16383 (5461 slots) master
  21. 1 additional replica(s)
  22. S: 6489fd359ed4b9abe10974e93bc2cf173b58c3ea 192.168.73.129:7005
  23. slots: (0 slots) slave
  24. replicates db89d77496ac4f160298b0e194d3584680fd1abf
  25. [OK] All nodes agree about slots configuration.
  26. >>> Check for open slots...
  27. >>> Check slots coverage...
  28. [OK] All 16384 slots covered.

集群验证

在一台机器上连接集群的7002端口的节点,另一台连接集群7005端口的节点,连接方式为

  1. redis-cli -h 192.168.73.128 -c -p 7002 # -c表示连接到集群,-h ip地址

在7005节点上设置一个key

  1. [root@localhost redis-3.2.1]# redis-cli -h 192.168.73.129 -c -p 7005
  2. 192.168.73.129:7005> set hello world
  3. -> Redirected to slot [866] located at 192.168.73.128:7000
  4. OK
  5. 192.168.73.128:7000> set hello world
  6. OK
  7. 192.168.73.128:7000> keys *
  8. 1) "hello"

在7002阶段上面进行查看,说明集群运行正常。

  1. [root@localhost ruby-2.4.5]# redis-cli -h 192.168.73.128 -c -p 7002
  2. 192.168.73.128:7002> get hello
  3. -> Redirected to slot [866] located at 192.168.73.128:7000
  4. "world"

简单说一下原理

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 。

需要注意的是:必须要3个或以上的主节点,否则在创建集群时会失败,并且当存活的主节点数小于总节点数的一半时,整个集群就无法提供服务了。


本文原理通过参考 邬兴亮个人博客,感谢作者辛勤付出。