本次案例实验环境使用 redis 5.0.7(目前最新版本)为了实验环境简单明了、方便部署使用六台服务器,然后启动六个 Redis 实例组成集群,集群包括三组,每组都是一主一从的关系。在实际生产环境考虑到架构的高可用能,在实验环境至少需要六台服务器192.168.245.201-192.168.245.206,只在一台服务器上创建集群即可,所有服务器都安装并启动redis
安装redis,安装之前需要安装c++编译工具
[root@localhost ~]# yum -y install gcc gcc-c++ make
解压tar包,编译安装二进制文件,指定安装路径
通常情况下,在 Linux 系统中进行源码编译安装,需要先执行./configure 进行环境检查与配置,从而生成 Makefile 文件,再执行 make && make install 命令进行编译安装。而 Redis 源码包中直接提供了 Makefile 文件,所以在解压完软件包后,可直接进入解压后的软件包目录,执行 make 与 make install 命令进行安装
[root@localhost opt]# tar xzvf redis-5.0.7.tar.gz
[root@localhost opt]# cd redis-5.0.7/
[root@localhost opt]# make
[root@localhost redis-5.0.7]# make PREFIX=/usr/local/redis install
为命令建立软链接方便使用
[root@localhost redis-5.0.7]# ln -s /usr/local/redis/bin/* /usr/local/bin
make install 只是安装了二进制文件到系统中,并没有启动脚本和配置文件。软件包中默认提供了一个 install_server.sh 脚本文件,通过该脚本文件可以设置 Redis 服务所需要的相关配置文件。当脚本运行完毕,Redis 服务就已经启动,默认监听端口为 6379
[root@localhost redis-5.0.7]# cd /opt/redis-5.0.7/utils/
[root@localhost utils]# ./install_server.sh
Welcome to the redis service installer
This script will help you easily set up a running redis server
Please select the redis port for this instance: [6379] <---回车
Selecting default: 6379
Please select the redis config file name [/etc/redis/6379.conf] <---回车
Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log] <---回车
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379] <---回车
Selected default - /var/lib/redis/6379
Please select the redis executable path [] /usr/local/redis/bin/redis-server <---需要手动指定
Selected config:
Port : 6379
Config file : /etc/redis/6379.conf
Log file : /var/log/redis_6379.log
Data dir : /var/lib/redis/6379
Executable : /usr/local/redis/bin/redis-server
Cli Executable : /usr/local/redis/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!
查看服务已启动
[root@localhost utils]# netstat -anpt | grep 6379
tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 106064/redis-server
修改配置文件,开启群集功能
[root@localhost utils]# vim /etc/redis/6379.conf
70 #bind 127.0.0.1 <-----需要注释掉bind否则集群创建会失败,如果保护模式设置了yes,就不能注释
89 protected-mode no <-----关闭保护模式,默认yes:redis只接收来自于bind里的ip的请求,如果不进行设置,那么将处理所有外部网络请求
833 cluster-enabled yes <-----开启集群功能
841 cluster-config-file nodes-6379.conf <-----此配置文件不能人工编辑,它是集群节点自动维护的文件,主要用于记录集群中有哪些节点、他们的状态以及一些持久化参数等,方便在重启时恢复这些状态。通常是在收到请求之后这个文件就会被更新
847 cluster-node-timeout 15000 <-----群集超时时间设置,默认是毫秒,这里设置15秒,意思是当master宕掉之后,slave尝试连接master的时间
700 appendonly yes <-----开启aof持久化
重启服务
[root@localhost utils]# /etc/init.d/redis_6379 restart
Stopping ...
Redis stopped
Starting Redis server...
查看实例的数据目录,就多了appendonly.aof和nodes-6379.conf文件
[root@localhost utils]# cd /var/lib/redis/
[root@localhost redis]# cd 6379/
[root@localhost 6379]# ls
appendonly.aof dump.rdb nodes-6379.conf
redis-trib.rb是redis官方推出的管理redis集群的工具,集成在redis的源码src目录下,是基于redis提供的集群命令封装成简单、便捷、实用的操作工具。创建集群需要用到它,它是用ruby完成的,所以使用之前需要安装Ruby依赖环境,先安装Ruby语言环境和Ruby的包管理器Gems,然后使用gem安装Redis和Ruby的接口。
导入key文件
[root@localhost 6379]# gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
gpg: 已创建目录‘/root/.gnupg’
gpg: 新的配置文件‘/root/.gnupg/gpg.conf’已建立
gpg: 警告:在‘/root/.gnupg/gpg.conf’里的选项于此次运行期间未被使用
gpg: 钥匙环‘/root/.gnupg/secring.gpg’已建立
gpg: 钥匙环‘/root/.gnupg/pubring.gpg’已建立
gpg: 下载密钥‘D39DC0E3’,从 hkp 服务器 keys.gnupg.net
gpg: /root/.gnupg/trustdb.gpg:建立了信任度数据库
gpg: 密钥 D39DC0E3:公钥“Michal Papis (RVM signing) <mpapis@gmail.com>”已导入
gpg: 没有找到任何绝对信任的密钥
gpg: 合计被处理的数量:1
gpg: 已导入:1 (RSA: 1)
安装rvm(Ruby Version Manager,Ruby版本管理器,包括Ruby的版本管理和Gem库管理(gemset)。目前支持Ruby的大多数版本)
[root@localhost 6379]# chmod +x rvm-installer.sh
[root@localhost 6379]#
[root@localhost 6379]# ./rvm-installer.sh <---rvm的安装脚本,自己编写的
[root@localhost 6379]# source /etc/profile.d/rvm.sh
安装ruby2.4.10
[root@localhost 6379]# rvm list known <----列出所有的rvm
# MRI Rubies
[ruby-]1.8.6[-p420]
[ruby-]1.8.7[-head] # security released on head
[ruby-]1.9.1[-p431]
[ruby-]1.9.2[-p330]
[ruby-]1.9.3[-p551]
[ruby-]2.0.0[-p648]
[ruby-]2.1[.10]
[ruby-]2.2[.10]
[ruby-]2.3[.8]
[ruby-]2.4[.10]
[ruby-]2.5[.8]
[ruby-]2.6[.6]
[ruby-]2.7[.1]
ruby-head
# for forks use: rvm install ruby-head-<name> --url https://github.com/github/ruby.git --branch 2.2
# JRuby
jruby-1.6[.8]
jruby-1.7[.27]
jruby-9.1[.17.0]
jruby[-9.2.13.0]
jruby-head
# Rubinius
rbx-1[.4.3]
rbx-2.3[.0]
rbx-2.4[.1]
rbx-2[.5.8]
rbx-3[.107]
rbx-4[.20]
rbx-5[.0]
rbx-head
# TruffleRuby
truffleruby[-20.2.0]
# Opal
opal
# Minimalistic ruby implementation - ISO 30170:2012
mruby-1.0.0
mruby-1.1.0
mruby-1.2.0
mruby-1.3.0
mruby-1[.4.1]
mruby-2.0.1
mruby-2[.1.1]
mruby[-head]
# Ruby Enterprise Edition
ree-1.8.6
ree[-1.8.7][-2012.02]
# Topaz
topaz
# MagLev
maglev-1.0.0
maglev-1.1[RC1]
maglev[-1.2Alpha4]
maglev-head
# Mac OS X Snow Leopard Or Newer
macruby-0.10
macruby-0.11
macruby[-0.12]
macruby-nightly
macruby-head
# IronRuby
ironruby[-1.1.3]
ironruby-head
[root@localhost 6379]# rvm install 2.4.10 <-----安装ruby2.4.10
省略下载过程,建议用移动网络
[root@localhost 6379]# rvm use 2.4.10 <------查看当前使用的ruby版本
Using /usr/local/rvm/gems/ruby-2.4.10
查看当前使用的ruby版本
[root@localhost 6379]# ruby -v
ruby 2.4.10p364 (2020-03-31 revision 67879) [x86_64-linux]
用gem安装Redis和Ruby的接口
Gem是一个管理Ruby库和程序的标准包,它通过Ruby Gem(如 http://rubygems.org/ )源来查找、安装、升级和卸载软件包,非常的便捷
[root@localhost 6379]# gem install redis
Fetching redis-4.2.2.gem
Successfully installed redis-4.2.2
Parsing documentation for redis-4.2.2
Installing ri documentation for redis-4.2.2
Done installing documentation for redis after 0 seconds
1 gem installed
创建集群
[root@redis04 opt]# redis-cli --cluster create 192.168.245.204:6379 192.168.245.205:6379 192.168.245.206:6379 192.168.245.201:6379 192.168.245.202:6379 192.168.245.203:6379 --cluster-replicas 1
在redis 5中redis-trib.rb的功能被集成到了redis-cli中,大大简化了redis的集群部署,加快了进群部署的速度,也方便后期维护与扩容。
create命令可选replicas参数,replicas表示1个master对应几个slave
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460 <-----给master分配slots
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 192.168.245.202:6379 to 192.168.245.204:6379 <----给master分配slave
Adding replica 192.168.245.203:6379 to 192.168.245.205:6379
Adding replica 192.168.245.201:6379 to 192.168.245.206:6379
M: cdab8558d5278ed6901b25240efa3349fc820186 192.168.245.204:6379
slots:[0-5460] (5461 slots) master
M: a6e13cf8a6b77b40765c36981c1a76cec0eaa457 192.168.245.205:6379
slots:[5461-10922] (5462 slots) master
M: e662100ba129dd093cb4d80ce08aa4b8993a5880 192.168.245.206:6379
slots:[10923-16383] (5461 slots) master
S: 4a01c1317fe504c0931272712d01c176a35cb5b0 192.168.245.201:6379
replicates e662100ba129dd093cb4d80ce08aa4b8993a5880
S: 568d79cffdefd877b5e64e066a720db36d6949ca 192.168.245.202:6379
replicates cdab8558d5278ed6901b25240efa3349fc820186
S: 53815ee3d3a4081f61a9e685bdbd1c7096b3ebb3 192.168.245.203:6379
replicates a6e13cf8a6b77b40765c36981c1a76cec0eaa457
Can I set the above configuration? (type 'yes' to accept): yes <---这里需要交互,输入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.245.204:6379)
M: cdab8558d5278ed6901b25240efa3349fc820186 192.168.245.204:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 568d79cffdefd877b5e64e066a720db36d6949ca 192.168.245.202:6379
slots: (0 slots) slave
replicates cdab8558d5278ed6901b25240efa3349fc820186
S: 53815ee3d3a4081f61a9e685bdbd1c7096b3ebb3 192.168.245.203:6379
slots: (0 slots) slave
replicates a6e13cf8a6b77b40765c36981c1a76cec0eaa457
S: 4a01c1317fe504c0931272712d01c176a35cb5b0 192.168.245.201:6379
slots: (0 slots) slave
replicates e662100ba129dd093cb4d80ce08aa4b8993a5880
M: e662100ba129dd093cb4d80ce08aa4b8993a5880 192.168.245.206:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
M: a6e13cf8a6b77b40765c36981c1a76cec0eaa457 192.168.245.205:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
创建集群的简要流程:
创建好的集群结构:
主:192.168.245.204----->备:192.168.245.202
主:192.168.245.205----->备:192.168.245.203
主:192.168.245.206----->备:192.168.245.201
创建好集群,集群结构ok之后,用ps查看进程,可以看到端口号后面多了一个[cluster]表示它属于一个集群了不是单实例了
[root@redis05 ~]# ps -ef | grep redis
root 106526 1 0 9月09 ? 00:00:35 /usr/local/redis/bin/redis-server *:6379 [cluster]
第一种方式进入实例redis-cli(进入本地redis实例的传统模式)
进入204节点的redis实例,创建一个key,但是他分配到了205来存储它
[root@redis04 opt]# redis-cli
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set name zhangsan
(error) MOVED 5798 192.168.245.205:6379
127.0.0.1:6379> exit
所以要在205节点上来存储它,直接在204节点进入到205的redis实例
[root@redis04 opt]# redis-cli -h 192.168.245.205 -p 6379
192.168.245.205:6379> set name zhangsan
OK
192.168.245.205:6379> get name
"zhangsan"
但是这种方式只会告诉你去哪里存储去哪里查看,并不会直接查询到结果,因为203节点是205节点的slave,所以key同步了过来,但是却get不到
[root@redis03 opt]# redis-cli
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> get name
(error) MOVED 5798 192.168.245.205:6379
第二种方式(用redis-cli -c进入实例,-c选项表示启用集群模式,比较科学的方式)
在205节点上进入redis,存入数据haha的值为shengjie,他被存入到了204节点上,204节点上就有了这个key,并且直接跳到了204的redis实例中操作,能get到这个key的值
[root@redis05 ~]# redis-cli -c
127.0.0.1:6379> set haha shengjie
-> Redirected to slot [3662] located at 192.168.245.204:6379
OK
192.168.245.204:6379> keys *
1) "haha"
2) "score"
3) "address"
192.168.245.204:6379> get haha
"shengjie"
再回到205节点上,205节点上并没有这个key
[root@redis05 ~]# redis-cli -c
127.0.0.1:6379>
127.0.0.1:6379> keys *
1) "name"
因为202节点是204的slave,在进入202节点的redis实例查看,202节点也同步到了haha这个key
[root@redis02 ~]# redis-cli -c
127.0.0.1:6379>
127.0.0.1:6379> keys *
1) "address"
2) "score"
3) "haha"
总结:只有一对master和slave会同步各自的key和值,集群里的其他master和slave并不能同步到,但是都可以get到这个key的值,所以当一个master宕掉之后,并不会影响数据的存取
查看日志:
[root@redis02 src]# tail -f /var/log/redis_6379.log
如图所示,查看202节点的日志,显示204是master,它本身是slave
查看204节点的日志,显示202是Replica副本即slave
接着,我们将204这台master模拟宕机,再查看202节点的日志,发现他成为了master,另外其他节点存取数据没有影响
而重新让这台204节点上线,它并没有抢占master,而是变成了202节点的slave
将201和206节点开机,两个节点又重新加入了集群,201为master,206为slave,集群又能正常存取了
在201节点上此刻所有节点master和slave的状态,可以看到哪些为master哪些为slave
[root@redis01 ~]# cd /var/lib/redis/6379/
[root@redis01 6379]# vim nodes-6379.conf
4a01c1317fe504c0931272712d01c176a35cb5b0 192.168.245.201:6379@16379 myself,master - 0 1599682208000 8 connected 10923-16383
e662100ba129dd093cb4d80ce08aa4b8993a5880 192.168.245.206:6379@16379 slave 4a01c1317fe504c0931272712d01c176a35cb5b0 0 1599682209450 8 connected
53815ee3d3a4081f61a9e685bdbd1c7096b3ebb3 192.168.245.203:6379@16379 slave a6e13cf8a6b77b40765c36981c1a76cec0eaa457 0 1599682209892 6 connected
a6e13cf8a6b77b40765c36981c1a76cec0eaa457 192.168.245.205:6379@16379 master - 0 1599682209000 2 connected 5461-10922
568d79cffdefd877b5e64e066a720db36d6949ca 192.168.245.202:6379@16379 slave cdab8558d5278ed6901b25240efa3349fc820186 0 1599682208444 1 connected
cdab8558d5278ed6901b25240efa3349fc820186 192.168.245.204:6379@16379 master - 0 1599682207437 1 connected 0-5460
vars currentEpoch 8 lastVoteEpoch 0
在206节点上存入数据key=hahaha,value=sj
[root@redis06 ~]# redis-cli -c
127.0.0.1:6379>
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set hahaha sj
-> Redirected to slot [12185] located at 192.168.245.201:6379
OK
可以看到key被存到了201节点上,同时206节点也同步到了
[root@redis06 ~]# redis-cli -c
127.0.0.1:6379>
127.0.0.1:6379> keys *
1) "hahaha"
随便进入另外一个redis实例203节点上,可以get到了新建的key
[root@redis03 bin]# redis-cli -c
127.0.0.1:6379>
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> get hahaha
-> Redirected to slot [12185] located at 192.168.245.201:6379
"sj"
总结:同时宕掉一对master之后集群随即宕掉,无法存取数据,但是再次启动之后会立即加入集群,另外如果宕掉所有master之后,集群也是宕掉