上篇文章为大家总结了redis命令并讲述了持久化,今天我们来看一下redis的三种集群模式:主从复制,哨兵集群,Cluster集群
本篇文章先介绍redis-cluster集群模式,然后再依次介绍它的哨兵集群与主从复制
一、Cluster集群模式概念
redis集群是一个分布式与容错的redis实现、在集群中不存在代理节点与中心节点、后期可以很好的将其进行扩展
此模式也解决了redis高可用与可扩展的问题、但是redis集群不支持需要同时处理多个Key的redis命令
因为执行这些命令需要在多个redis节点之间移动数据、如果是在服务器高负载的情况下、那么这将影响redis的集群性能、并可能会导致不可预测的行为
1)集群模式中的数据共享
redis集群使用数据分片、而非一致性HASH、一个集群包含16384个哈希槽(Hash Slot)、库中的每个K都属于 这16384的其中一个、集群使用公式CRC16(Key)%16384来计算K属于哪个槽 redis集群把所有物理节点都映射到了[0-16383]个哈希槽上、每个节点负责处理一部分哈希槽、客户端连接集群中的任何一个节点即可发送指令 如果某个节点收到自己不负责的槽的请求时、它会将负责这个槽的redis节点的IP地址返回给客户端、客户端收到之后会将请求重新发往这个地址、如下所示: (1)节点 A 负责处理 0 号至5500 号哈希槽 (2)节点 B 负责处理 5501 号至 11000 号哈希槽 (3)节点 C 负责处理 11001 号至 16384 号哈希槽 这种将哈希槽分布到不同节点的做法可以让用户更加容易的向集群中添加与删除节点 如果需要往集群中添加一个新的节点、这个节点名为D、那么只需将集群中节点A、B、C中的某些槽移动到这个节点D即可 如果需要在集群中删除节点B、那么只需将节点B中的所有哈希槽移动到其它节点上、然后在移除空白(不包含任何哈希槽)的节点B即可
2)集群中的主从模式
为了让集群在一部分节点下线的情况下、仍然可以正常工作、redis集群模式对节点使用了主从复制功能 在群集当中都有一个或多个复制组、一个复制组中又有一个Master与N个Slave、Master提供数据存取、Slave向其同步数据 以此来实现数据备份、如果Master出现故障、那么这个Master的Slave将会被提升为新的Master、这样即可保证集群中某个节点出现故障以后、集群还能正常运作 下面我们来举个例子: 在上面的概述中我们提到了3个节点、分别为A、B、C、这三个也都是集群中的Master 假设A节点出现故障、那么集群的工作将无法进行、因为集群找不到节点来处理0-5500号的哈希槽 但如果我们在创建集群的时候或者在A节点下线之前为节点A添加一个从节点A1 那么这个时候A节点下线了、集群就会将A1提升为新的Master、并让其接替A的工作、以继续处理0-5500号的哈希槽 这样集群就不会因为节点A的下线而导致整个集群不可运行、如果运气不好、A与A1都出现了故障、那么redis集群还是会停止运作、这个时候就需要人工处理了
3)集群模式的其它特点与细节
(1)所有节点彼此互联(PING-PONG机制)、内部使用二进制协议优化传输速度与带宽 (2)节点的失效、是通过集群中超过半数的节点检测失效时才生效 (3)集群中任意Master故障、且当前Master下无Slave、则整个集群进入Fail状态 (4)集群中半数Master故障、无论是否有Slave、集群也将进入Fail状态 (5)集群不可用时、所有对集群的操作都将不可用、将收到((error) ClusterDown The Cluster is down)错误 (6)客户端与redis节点直连、无需代理层、也不需要连接集群的所有节点、连接集群中任何一个可用的节点即可
二、Cluster集群模式部署
1)实验说明
在部署集群的时候、至少需要六台节点、才能构成一个集群、虽然有6台、但也只能部署三主三从的集群、也就是一个主对应一个从的结构
为了节约资源、有时候在一台服务器上可运行多个redis实例、下面的实验环境、我用了三台服务器、在这三台服务器上分别跑了三个实例、IP一样、端口不同
三台服务器上均有一套主从环境、后期添加节点时、也可以这样来进行添加、不过真实环境也有可能会单台服务器只运行一个redis实例
在创建集群的时候、可以让其默认进行配置、也可以按照自己的习惯与思路来添加节点、比如先添加Master、后添加Slave、在添加Slave的时候、再去明确指定这个Slave属于哪个Master
2)测试环境
主机 | 系统 | 地址 | 端口 | 角色 |
node1 | CentOS-7.5 | 10.2.3.11 | 6371 | Master |
node1 | CentOS_7.5 | 10.2.3.11 | 6372 | Slave-1 |
node1 | CentOS_7.5 | 10.2.3.11 | 6373 | Slave-2 |
node2 | CentOS_7.5 | 10.2.3.12 | 6371 | Master |
node2 | CentOS_7.5 | 10.2.3.12 | 6372 | Slave-1 |
node2 | CentOS_7.5 | 10.2.3.12 | 6373 | Slave-2 |
node3 | CentOS_7.5 | 10.2.3.13 | 6371 | Master |
node3 | CentOS_7.5 | 10.2.3.13 | 6372 | Slave-1 |
node3 | CentOS_7.5 | 10.2.3.13 | 6373 | Slave-2 |
3)redis多实例部署
提示:总共三台服务器、操作基本一样、这里我只配置一台、其它两台我将不再赘述、需要修改的地方下面我会说明
1、创建目录、下面的子目录以端口命名、用于区分不同实例
[root@node1 ~]# mkdir /etc/redis
2、安装第一个实例、端口为6371
[root@node1 ~]# yum -y install gcc gcc-c++ pcre-devel tcl tcl-devel zlib zlib-devel openssl openssl-devel gdbm gdbm-devel [root@node1 ~]# wget -c download.redis.io/releases/redis-3.2.13.tar.gz [root@node1 ~]# tar xf redis-3.2.13.tar.gz -C /usr/src/ [root@node1 ~]# cd /usr/src/redis-3.2.13/ [root@node1 redis-3.2.13]# make -j 8 && make PREFIX=/etc/redis/6371 install && cd ~
3、为第一个实例创建对应的存储目录、并复制相应的文件
[root@node1 ~]# mkdir /etc/redis/6371/log [root@node1 ~]# mkdir /etc/redis/6371/pid [root@node1 ~]# mkdir /etc/redis/6371/tmp [root@node1 ~]# mkdir /etc/redis/6371/data [root@node1 ~]# mkdir /etc/redis/6371/conf [root@node1 ~]# cp /usr/src/redis-3.2.13/src/redis-trib.rb /etc/redis/6371/bin/ [root@node1 ~]# cp /etc/redis/6371/bin/* /usr/local/bin/ [root@node1 ~]# cp /usr/src/redis-3.2.13/redis.conf /etc/redis/6371/conf/ [root@node1 ~]# cp /etc/redis/6371/conf/redis.conf /etc/redis/6371/conf/redis.conf.bak
4、将第一个实例添加到系统服务、并命名为redis-6371、后面的实例以此类推
[root@node1 ~]# cat > /usr/lib/systemd/system/redis-6371.service << EOF [Unit] Description=redis After=network.target [Service] Type=forking LimitNOFILE=65535 ExecStart=/usr/local/bin/redis-server /etc/redis/6371/conf/redis.conf [Install] WantedBy=multi-user.target EOF
5、为第一个实例定义配置文件、按照需求以及情况修改监听的地址、端口、存储目录即可
[root@node1 ~]# cat > /etc/redis/6371/conf/redis.conf << EOF bind 0.0.0.0 port 6371 #以此类推 timeout 180 daemonize yes maxclients 6500 protected-mode yes requirepass abc-123 tcp-backlog 2048 tcp-keepalive 300 databases 16 supervised no syslog-enabled yes syslog-ident redis-6371 #以此类推 syslog-facility local0 loglevel notice logfile "/etc/redis/6371/log/redis.log" #以此类推 pidfile "/etc/redis/6371/pid/redis.pid" #以此类推 unixsocketperm 755 unixsocket "/etc/redis/6371/tmp/redis.sock" #以此类推 slowlog-log-slower-than 5000 slowlog-max-len 128 dir "/etc/redis/6371/data" #以此类推 save 900 1 save 300 10 save 60 10000 rdbcompression yes rdbchecksum no dbfilename dump.rdb stop-writes-on-bgsave-error no appendonly yes appendfsync everysec aof-load-truncated yes appendfilename appendonly.aof no-appendfsync-on-rewrite no auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb aof-rewrite-incremental-fsync yes repl-diskless-sync no repl-diskless-sync-delay 5 repl-disable-tcp-nodelay no repl-backlog-size 1mb repl-backlog-ttl 3600 slave-priority 100 hz 10 maxmemory-policy noeviction activerehashing yes hash-max-ziplist-value 64 hash-max-ziplist-entries 512 list-compress-depth 0 lua-time-limit 5000 notify-keyspace-events "" list-max-ziplist-size -2 latency-monitor-threshold 0 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 hll-sparse-max-bytes 3000 client-output-buffer-limit normal 0 0 0 client-output-buffer-limit pubsub 32mb 8mb 60 client-output-buffer-limit slave 256mb 64mb 60 EOF
6、解决警告提示
[root@node1 ~]# echo never > /sys/kernel/mm/transparent_hugepage/enabled [root@node1 ~]# echo "echo never > /sys/kernel/mm/transparent_hugepage/enabled" >> /etc/rc.d/rc.local [root@node1 ~]# echo net.core.somaxconn = 4096 >> /etc/sysctl.conf [root@node1 ~]# echo vm.overcommit_memory = 1 >> /etc/sysctl.conf [root@node1 ~]# echo vm.swappiness = 0 >> /etc/sysctl.conf [root@node1 ~]# sysctl -p
7、启动redis、并将其设置为开机自启
[root@node1 ~]# systemctl enable redis-6371 [root@node1 ~]# systemctl start redis-6371 [root@node1 ~]# netstat -anput | grep redis tcp 0 0 0.0.0.0:6371 0.0.0.0:* LISTEN 4326/redis-server 0
提示:下面为多实例需要修改的地方
(1)、 按照需求创建不同的存储目录、为了加以区分、可以用端口号命名不同的目录
(2)、 因为是同一台服务器、第一个实例创建时已经解决了警告、所以后面两个实例就无需重复步骤6
(3)、 添加系统服务时、第一个实例命名为redis-6371、第二个就为redis-6372即可、其它的以此类推
(4)、 修改监听端口、以及日志标签、第一个实例的标签为redis-6371、第二个实例的标签为redis-6372
(5)、 下面的实例就无需执行make之类的命令了、只需只需make PREFIX=目录 将执行文件复制到相应的目录即可
4)集群配置项定义
提示:在这9个实例中、都需要添加以下配置、操作基本一样、但是需要为Cluster配置文件定义存储路径
cluster-enabled yes masterauth abc-123 cluster-node-timeout 15000 cluster-require-full-coverage no cluster-config-file "/etc/redis/6371/conf/cluster_6371.conf" #以不同的端口号命名即可
下面为配置项说明:
cluster-enabled yes: #表示开启redis集群 masterauth abc-123: #配置认证、因为上面定义了连接密码 cluster-node-timeout 15000: #请求超时、默认15秒 cluster-config-file: #定义集群配置文件的路径 cluster-require-full-coverage no: #Master下线、没有Slave时、集群仍然可用
重新启动redis服务、使用netstat -anput | grep redis命令查看状态、即可出现如下内容:
netstat -anput | grep redis tcp 0 0 0.0.0.0:6371 0.0.0.0:* LISTEN 1418/redis-server 0 tcp 0 0 0.0.0.0:6372 0.0.0.0:* LISTEN 1410/redis-server 0 tcp 0 0 0.0.0.0:6373 0.0.0.0:* LISTEN 1411/redis-server 0 tcp 0 0 0.0.0.0:16371 0.0.0.0:* LISTEN 1418/redis-server 0 tcp 0 0 0.0.0.0:16372 0.0.0.0:* LISTEN 1410/redis-server 0 tcp 0 0 0.0.0.0:16373 0.0.0.0:* LISTEN 1411/redis-server 0
5)安装并配置Ruby工具
[root@node1 ~]# wget -c https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.7.tar.gz [root@node1 ~]# tar xf ruby-2.3.7.tar.gz -C /usr/src/ [root@node1 ~]# cd /usr/src/ruby-2.3.7/ [root@node1 ruby-2.3.7]# ./configure --prefix=/usr/local/ruby && make -j 8 && make install -j 8 && cd [root@node1 ~]# cp /usr/local/ruby/bin/* /usr/local/bin/ [root@node1 ~]# ruby -v ruby 2.3.7p456 (2018-03-28 revision 63024) [x86_64-linux] [root@node1 ~]# wget -c https://rubygems.org/downloads/redis-3.3.5.gem && gem install redis-3.3.5.gem #注意看,下载以后后面是要执行的命令
6)创建集群并添加节点
注意:如果为redis设置了连接密码、就需要找到client.rb文件、在里面填写连接redis的密码即可
路径:/usr/local/ruby/lib/ruby/gems/2.3.0/gems/redis-3.3.5/lib/redis/client.rb
提示:创建集群并添加节点的时候,有两种方法,下面我们一起来看一下:
1、按照默认模式添加、--replicas为一个Master有多少个Slave
[root@node1 ~]# redis-trib.rb create --replicas 2 10.2.3.11:6371 10.2.3.11:6372 10.2.3.11:6373 10.2.3.12:6371 10.2.3.12:6372 10.2.3.12:6373 10.2.3.13:6371 10.2.3.13:6372 10.2.3.13:6373
2、先添主、后添从、添加Slave时指定自己属于哪个Master、前面为要添加的Slave、后面为指定属于哪个Master
redis-trib.rb create 10.2.3.11:6371 10.2.3.12:6371 10.2.3.13:6371 redis-trib.rb add-node --slave 10.2.3.11:6372 10.2.3.11:6371 redis-trib.rb add-node --slave 10.2.3.11:6373 10.2.3.11:6371 redis-trib.rb add-node --slave 10.2.3.12:6372 10.2.3.12:6371 redis-trib.rb add-node --slave 10.2.3.12:6373 10.2.3.12:6371 redis-trib.rb add-node --slave 10.2.3.13:6372 10.2.3.13:6371 redis-trib.rb add-node --slave 10.2.3.13:6373 10.2.3.13:6371
7)检查并验证集群
1、检查集群、命令为:redis-trib.rb check IP+PORT、随便连接一台可用节点即可
[root@node1 ~]# redis-trib.rb check 10.2.3.11:6371 >>> Performing Cluster Check (using node 10.2.3.11:6371) M: 4908bb23606bd5867a83928926cd92866541e54b 10.2.3.11:6371 slots:0-5460 (5461 slots) master 2 additional replica(s) M: 528eba2ea5057cba170662d3c6b1795100ac7b71 10.2.3.12:6371 slots:5461-10922 (5462 slots) master 2 additional replica(s) M: bc0f2af83e6a3cbdd8c058c1ee18ece877ed3eaa 10.2.3.13:6371 slots:10923-16383 (5461 slots) master 2 additional replica(s) S: 92b567505d57095f66018effb8bd3aa4ed3e8d94 10.2.3.11:6372 slots: (0 slots) slave replicates 4908bb23606bd5867a83928926cd92866541e54b S: 1f2fee46d9504d7d9cc6b02c333d56ce5a1c83cf 10.2.3.11:6373 slots: (0 slots) slave replicates bc0f2af83e6a3cbdd8c058c1ee18ece877ed3eaa S: 4bf82217934cea41250ce67a9f23928bcd68bb66 10.2.3.12:6372 slots: (0 slots) slave replicates 528eba2ea5057cba170662d3c6b1795100ac7b71 S: f93e375577fc90bdae58f13c6eb70d3f4190da0d 10.2.3.13:6372 slots: (0 slots) slave replicates bc0f2af83e6a3cbdd8c058c1ee18ece877ed3eaa S: beb3d9c1b33adbc5d0662d19f2cc4dace908a7fc 10.2.3.12:6373 slots: (0 slots) slave replicates 528eba2ea5057cba170662d3c6b1795100ac7b71 S: 7db50c5c6b303d36ba493b0993780328d51b4ec8 10.2.3.13:6373 slots: (0 slots) slave replicates 4908bb23606bd5867a83928926cd92866541e54b [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
2、查看主从复制状态
redis-cli -c -h 10.2.3.11 -p 6371 -a abc-123 info replication | grep -v "#" #第一台Master role:master connected_slaves:2 slave0:ip=10.2.3.11,port=6372,state=online,offset=1849,lag=0 slave1:ip=10.2.3.13,port=6373,state=online,offset=1849,lag=0 master_repl_offset:1849 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:2 repl_backlog_histlen:1848 redis-cli -c -h 10.2.3.12 -p 6371 -a abc-123 info replication | grep -v "#" #第二台Master role:master connected_slaves:2 slave0:ip=10.2.3.12,port=6372,state=online,offset=1863,lag=1 slave1:ip=10.2.3.12,port=6373,state=online,offset=1863,lag=1 master_repl_offset:1863 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:2 repl_backlog_histlen:1862 redis-cli -c -h 10.2.3.13 -p 6371 -a abc-123 info replication | grep -v "#" #第三台Master role:master connected_slaves:2 slave0:ip=10.2.3.11,port=6373,state=online,offset=1891,lag=1 slave1:ip=10.2.3.13,port=6372,state=online,offset=1891,lag=1 master_repl_offset:1891 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:2 repl_backlog_histlen:1890
3、验证集群的数据读取与写入
注意:连接集群时可以随便连接一台可用的节点、但是一定要使用-c选项来开启集群模式
[root@node1 ~]# redis-cli -h 10.2.3.11 -p 6371 -a abc-123 -c 10.2.3.11:6371> set k1 v1 #写入数据时、随机分配到不同节点 -> Redirected to slot [12706] located at 10.2.3.13:6371 OK 10.2.3.13:6371> set k2 v2 -> Redirected to slot [449] located at 10.2.3.11:6371 OK 10.2.3.11:6371> get k1 #读取数据时、也会进行相应的转向 -> Redirected to slot [12706] located at 10.2.3.13:6371 "v1" 10.2.3.13:6371> get k2 -> Redirected to slot [449] located at 10.2.3.11:6371 "v2"
三、集群维护
1)集群命令
1、显示集群中的信息
10.2.3.11:6371> cluster info cluster_state:ok cluster_slots_assigned:16384 cluster_slots_ok:16384 cluster_slots_pfail:0 cluster_slots_fail:0 cluster_known_nodes:9 cluster_size:3 cluster_current_epoch:3 cluster_my_epoch:1 cluster_stats_messages_sent:3319 cluster_stats_messages_received:3319
2、显示集群中的的所有节点、以及它们的信息
10.2.3.11:6371> cluster nodes bc0f2af83e6a3cbdd8c058c1ee18ece877ed3eaa 10.2.3.13:6371 master - 0 1575527176138 3 connected 10923-16383 beb3d9c1b33adbc5d0662d19f2cc4dace908a7fc 10.2.3.12:6373 slave 528eba2ea5057cba170662d3c6b1795100ac7b71 0 1575527175125 2 connected f93e375577fc90bdae58f13c6eb70d3f4190da0d 10.2.3.13:6372 slave bc0f2af83e6a3cbdd8c058c1ee18ece877ed3eaa 0 1575527171573 3 connected 7db50c5c6b303d36ba493b0993780328d51b4ec8 10.2.3.13:6373 slave 4908bb23606bd5867a83928926cd92866541e54b 0 1575527177150 1 connected 1f2fee46d9504d7d9cc6b02c333d56ce5a1c83cf 10.2.3.11:6373 slave bc0f2af83e6a3cbdd8c058c1ee18ece877ed3eaa 0 1575527174112 3 connected 4908bb23606bd5867a83928926cd92866541e54b 10.2.3.11:6371 myself,master - 0 0 1 connected 0-5460 528eba2ea5057cba170662d3c6b1795100ac7b71 10.2.3.12:6371 master - 0 1575527178163 2 connected 5461-10922 4bf82217934cea41250ce67a9f23928bcd68bb66 10.2.3.12:6372 slave 528eba2ea5057cba170662d3c6b1795100ac7b71 0 1575527172083 2 connected 92b567505d57095f66018effb8bd3aa4ed3e8d94 10.2.3.11:6372 slave 4908bb23606bd5867a83928926cd92866541e54b 0 1575527173099 1 connected
4、节点操作
10.2.3.11:6371> CLUSTER meet <IP> <PORT> #往集群中添加节点 10.2.3.11:6371> cluster forget <node_id> #在集群中删除节点 10.2.3.11:6371> cluster saveconfig #将节点的配置文件保存到硬盘 10.2.3.11:6371> cluster replicate <master_node_id> #为当前Slave重新设置Master、这个只能对Slave操作
5、Slot操作
10.2.3.11:6371> cluster addslots <slot> <slot> #将一个或多个槽指派给当前节点 10.2.3.11:6371> cluster delslots <slot> <slot> #将当前节点一个或多个槽删除 10.2.3.11:6371> cluster setslot <slot> stable #取消对槽的导入与迁移 10.2.3.11:6371> cluster flushslots #移除当前节点的所有slot 10.2.3.11:6371> cluster setslot <slot> node <node_id> #将slot指派给node_id节点 10.2.3.11:6371> cluster setslot <slot> migrating <node_id> #将本节点的slot迁移到node_id节点 10.2.3.11:6371> cluster setslot <slot> importing <node_id> #从node_id节点中导入slot到本节点
6、键操作
10.2.3.11:6371> cluster keyslot k1 #计算出Key属于哪个槽 10.2.3.11:6371> cluster countkeysinslot <slot> #计算槽中有多少个Key 10.2.3.11:6371> cluster getkeysinslot <slot> <count> #返回槽中的Key、count为个数
2)添加节点
1、向集群中添加主节点
(1)添加新的节点
提示:前者为需要添加的节点、后者为集群中任意的旧节点
[root@node1 ~]# redis-trib.rb add-node 10.2.3.14:6371 10.2.3.11:6371
(2)为新添加的主节点指派槽
[root@node1 ~]# redis-trib.rb reshard 10.2.3.14:6371 How many slots do you want to move (from 1 to 16384)? 1600 #设置分配槽的数量 What is the receiving node ID? 485fd9c20ff14b19da9e90cca1f2ab33f304e663 #需要分配槽的ID Source node #1:all #输入all表示全部节点重新洗牌 Do you want to proceed with the proposed reshard plan (yes/no)? yes #确认重新洗牌
2、向集群中添加从节点
提示:--master-id指定主节点的ID、后面两个IP为:第一个IP为要添加的节点、第二个IP为集群中的旧节点
[root@node1 ~]# redis-trib.rb add-node --slave --master-id 485fd9c20ff14b19da9e90cca1f2ab33f304e663 10.2.3.14:6372 10.2.3.11:6371 [root@node1 ~]# redis-trib.rb add-node --slave --master-id 485fd9c20ff14b19da9e90cca1f2ab33f304e663 10.2.3.14:6373 10.2.3.11:6371
3)更改节点
作用1:可以让某个Master的Slave数量与集群中其它Master成正比
作用2:删除主节点的时候、如果这个主节点还有从节点、那么就可以更改它的属主
1、指定新的Master
提示:因为这个操作是针对Slave的、所以要先登录Slave、后面那串ID为指定主节点的ID
[root@node1 ~]# redis-cli -h 10.2.3.14 -p 6372 -a abc-123 -c 10.2.3.14:6372> cluster replicate ee6c506e40fb739c4d031ccf6f01001fe2843e17
2、确认已经添加
[root@node1 ~]# redis-cli -h 10.2.3.11 -p 6371 -a abc-123 -c 10.2.3.11:6371> info replication role:master connected_slaves:2 slave0:ip=10.2.3.13,port=6373,state=online,offset=2787,lag=0 slave1:ip=10.2.3.14,port=6372,state=online,offset=2787,lag=1
4)删除节点
1、删除集群中的从节点
[root@node1 ~]# redis-trib.rb del-node 10.2.3.14:6373 8d737cf226d8e8f9aad3f397bd86f35eea6c5265
2、删除集群中的主节点
提示:删除主节点的时、需要先清空slot、然后才能删除
(1)将槽指派给其它主节点
[root@node1 ~]# redis-trib.rb reshard 10.2.3.14:6371 How many slots do you want to move (from 1 to 16384)? 1600 #被删除Master的槽数量 What is the receiving node ID? ab2512dcf7a58f406601272b32c42dc919b3152f #接收槽的其它Master Source node #1:485fd9c20ff14b19da9e90cca1f2ab33f304e663 #被删除Master的ID Source node #2:done Do you want to proceed with the proposed reshard plan (yes/no)? yes #确认执行 [root@node1 ~]# redis-trib.rb check 10.2.3.11:6371 #再次检查 M: 485fd9c20ff14b19da9e90cca1f2ab33f304e663 10.2.3.14:6371 slots: (0 slots) master #可以看见槽已经被移除 0 additional replica(s)
(2)删除主节点
[root@node1 ~]# redis-trib.rb del-node 10.2.3.14:6371 485fd9c20ff14b19da9e90cca1f2ab33f304e663 >>> Removing node 485fd9c20ff14b19da9e90cca1f2ab33f304e663 from cluster 10.2.3.14:6371 >>> Sending CLUSTER FORGET messages to the cluster... >>> SHUTDOWN the node.
四、redis哨兵集群概念
Sentinel为redis官方提供的一种高可用解决方案、目前Sentinel哨兵模式已被集成于redis-2.4之后的版本中
Sentinel系统负责监控主从的状态、当主节点出现异常、自动选择一个最优的从节点变为新的主节点、而其它的从节点也会与新的主节点建立主从关系
当客户端连接redis时、首先连接Sentinel、因为需要通过Sentinel来查询主节点的IP、然后再连接主节点进行交互
如果主节点发生故障、客户端会重新向Sentinel查询主节点的IP、Sentinel会将最新的主节点IP告知客户端如此一来线上的应用程序无需重启、即可自动完成节点之间的切换
1)Sentinel的作用
1、状态检测:Sentinel会定期的检查主节点与从节点运行是否正常 2、故障切换:当主节点出现故障、Sentinel会选择一台最优的从节点作为新的主节点 3、消息通知:当被监控的redis出现故障、Sentinel可向管理员或应用程序发送通知信息
2)Sentinel命令
提示:连接sentinel:redis-cli -h 10.2.3.11 -p 6379
10.2.3.11:26379> sentinel masters #列出被监控的Master、以及它的信息 10.2.3.11:26379> sentinel slaves m1 #列出主服务器中的从服务器、以及它们的信息 10.2.3.11:26379> sentinel get-master-addr-by-name m1 #返回给定名字的主服务器的IP+PORT 10.2.3.11:26379> sentinel remove m1 #放弃对这个Master的监听
3)Sentinel的工作方式
要想灵活的使用Sentinel集群,首先我们得了解一下它的工作原理,下面我们一起来看一下
1、SDOWN与ODOWN
(1)SDOWN
为主观下线、指的是单个Sentinel对redis节点做出的下线判断
(2)ODOWN
为客观下线、指的是多个Sentinel对redis节点做出的下线判断、也是通过down-after-milliseconds命令交流之后所得出的结果
也就是说如果一个服务器没有在down-after-milliseconds选项所指定的时间内、对向它发送PING命令的Sentinel返回一个有效的恢复、那么Sentinel就会将这个redis节点标记为下主观下线
2、Sentinel需要定期执行的任务
(1)每个Sentinel以每秒一次的频率向它所知的MS以及其它的Sentinel发送一个PING命令 (2)如果一个节点在down-after-milliseconds选项所指定的时间内没有响应、那么这个节点将会被标记为SDOWN、一个有效的响应包括:+PONG、-LOADING、-MASTERDOWN (3)如果一个Master被标记为SDOWN、那么正在监视这个Master的所有Sentinel都要以每秒一次的频率确认Master确实进入了SDOWN (4)如果一个Master被标记为SDOWN、并且有足够多的Sentinel检测到这个Master处于SDOWN、那么这个Master将被标记为ODOWN、注意:Sentinel的数量要达到配置文件中所指定的数量 (5)在正常情况下、每个Sentinel以每10秒一次的频率向它已知的MS发送INFO命令、当一个Master被标记为ODOWN、则Sentinel向下线Master的所有Slave发送INFO命令的频率由10秒一次改为每秒一次 (6)如果没有足够的Sentinel同意Master下线、则Master的ODOWN状态就会被移除 (7)如果Master重新向Sentinel的PING命令返回有效恢复时、则Master的SDOWN状态也会被移除
3、自动发现Sentinel与Slave
(1)每个Sentinel以每秒一次的频率、通过发布与订阅功能、向被它监视的MS节点的_sentinel_:hello频道发送一条信息、信息的内容包含:Sentinel的IP+PORT+Runid (2)每个Sentinel都订阅了被它监视的MS的_sentinel_:hello频道、以查找从未出现过的Sentinel、当一Sentinel发现一个新的Sentinel时、它会将这个新的Sentinel添加到一个列表中、这个列表保存了Sentinel已知的、以及监视同一个Master的所有其它Sentinel (3)Sentinel发送的信息中也包括完整的Master当前配置、如果一个Sentinel包含的Master配置要比另一个Sentinel发送的配置要旧、那么这个Sentinel会立即升级到新配置上 (4)在添加新Sentinel到监视Master的列表上面之前、Sentinel会先检查列表中是否已经存在将要添加的Sentinel、如果存在则先移除列表中已有的拥有相同运行ID或者相同IP的Sentinel、然后再添加新的Sentinel
4、Sentinel故障转移过程
在开始故障转移之前、首先等待0-5秒、以便让其它的Sentinel节点准备和调整
如果一切正常、那么leader就会开始将一个Slave提升为Master、这个Slave的权重值要低、且不能处于SDOWN与ODOWN状态、当Master身份确认后、将开始故障转移
(1)+sdown master m1 10.2.3.14 6379 给定的服务器现在处于主观下线状态 (2)+odown master m1 10.2.3.14 6379 #quorum 1/1 给定的服务器现在处于客观下线状态 (3)+try-failover master m1 10.2.3.14 6379 故障转移操作正在执行中 (4)+failover-state-select-slave master m1 10.2.3.14 6379 Sentinel正在寻找合适的Slave提升为Master (5)+selected-slave slave 10.2.3.12:6379 10.2.3.12 6379 @ m1 10.2.3.14 6379 Sentinel已经找到合适提升为Master的Slave (6)+failover-state-send-slaveof-noone slave 10.2.3.12:6379 10.2.3.12 6379 @ m1 10.2.3.14 6379 Sentinel正在将指定的Slave提升为Master (7)+failover-state-wait-promotion slave 10.2.3.12:6379 10.2.3.12 6379 @ m1 10.2.3.14 6379 等待其它的Sentinel确认这个Slave (8)+promoted-slave slave 10.2.3.12:6379 10.2.3.12 6379 @ m1 10.2.3.14 6379 确认完成 (9)+failover-state-reconf-slaves master m1 10.2.3.14 6379 开始对Slaves进行reconfig操作 (10)+slave-reconf-sent slave 10.2.3.13:6379 10.2.3.13 6379 @ m1 10.2.3.14 6379 Sentinel向该节点发送了SLAVEOF host port命令、为其设置新的Master (11)+slave-reconf-inprog slave 10.2.3.13:6379 10.2.3.13 6379 @ m1 10.2.3.14 6379 此节点正在将自己设置为指定主服务器的从服务器 (12)+slave-reconf-done slave 10.2.3.13:6379 10.2.3.13 6379 @ m1 10.2.3.14 6379 该从服务器已经完成对新主服务器的同步 (13)+failover-end master m1 10.2.3.14 6379 故障转移操作顺利完成 (14)+switch-master m1 10.2.3.14 6379 10.2.3.12 6379 故障转移成功后、配置已经变更、各个Sentinel节点开始监控新的Master
五、redis哨兵集群部署与使用
1)实验环境说明
主机 | 地址 | 系统 | 角色 |
node1 | 10.2.3.11 | CentOS-7.5 | Sentinel |
node2 | 10.2.3.12 | CentOS-7.5 | Master |
node3 | 10.2.3.13 | CentOS-7.5 | Slave-1 |
node4 | 10.2.3.14 | CentOS-7.5 | Slave-2 |
2)主从复制部署
1、Master配置
requirepass abc-123 save 900 1 appendonly yes
2、Slave配置
requirepass abc-123 slaveof 10.2.3.12 379 masterauth abc-123 slave-read-only yes
3)Sentinel部署与配置
1、Sentinel安装
tar xf redis-3.2.13.tar.gz -C /usr/src/ cd /usr/src/redis-3.2.13/ && make && cd mkdir /usr/local/sentinel mkdir /usr/local/sentinel/pid mkdir /usr/local/sentinel/log mkdir /usr/local/sentinel/bin mkdir /usr/local/sentinel/tmp mkdir /usr/local/sentinel/data mkdir /usr/local/sentinel/conf cp /usr/src/redis-3.2.13/src/redis-cli /usr/local/sentinel/bin/ cp /usr/src/redis-3.2.13/src/redis-server /usr/local/sentinel/bin/ cp /usr/src/redis-3.2.13/src/redis-sentinel /usr/local/sentinel/bin/ cp /usr/src/redis-3.2.13/src/redis-trib.rb /usr/local/sentinel/bin/ cp /usr/src/redis-3.2.13/src/redis-check-rdb /usr/local/sentinel/bin/ cp /usr/src/redis-3.2.13/src/redis-check-aof /usr/local/sentinel/bin/ cp /usr/src/redis-3.2.13/src/redis-benchmark /usr/local/sentinel/bin/ cp /usr/local/sentinel/bin/* /usr/local/bin/ cp /usr/src/redis-3.2.13/sentinel.conf /usr/local/sentinel/conf/ cp /usr/local/sentinel/conf/sentinel.conf /usr/local/sentinel/conf/sentinel.conf.bak
2、将Sentinel添加为系统服务
cat >> /usr/lib/systemd/system/sentinel.service << EOF [Unit] Description=sentinel After=network.target [Service] Type=forking LimitNOFILE=65535 ExecStart=/usr/local/bin/redis-sentinel /usr/local/sentinel/conf/sentinel.conf [Install] WantedBy=multi-user.target EOF
3、配置Sentinel
cat > /usr/local/sentinel/conf/sentinel.conf << EOF bind 10.2.3.11 port 26379 daemonize yes protected-mode yes loglevel notice syslog-enabled yes syslog-ident sentinel syslog-facility local0 dir "/usr/local/sentinel/data" logfile "/usr/local/sentinel/log/sentinel.log" pidfile "/usr/local/sentinel/pid/sentinel.pid" unixsocket "/usr/local/sentinel/tmp/sentinel.sock" sentinel monitor m1 10.2.3.12 6379 1 sentinel auth-pass m1 abc-123 sentinel parallel-syncs m1 1 sentinel failover-timeout m1 180000 sentinel down-after-milliseconds m1 10000 EOF
4、Sentinel配置文件讲解
sentinel monitor m1 10.2.3.12 6379 1
m1为名字、如果要监控多个Master就以名字来区分、后面接着Master的IP、其次是Master的端口、后面的1表示Sentinel的数量
也就是说如果要将此Master判断为下线、在Sentinel中至少要有1个Sentinel同意才行
我这里设置为、因为我只用了一台Sentinel、在盛生产环境中为了解决单点故障与误判、通常会配备多个Sentinel、在填写Sentinel数量的时候需要注意、填写的数量不能多于启动的Sentinel实例数量
sentinel auth-pass m1 abc-123
定义连接Master与Slave的密码、这里的密码需要与MS配置文件当中设置的保持一致、同时MS之间的密码要一样
sentinel parallel-syncs m1 1
在故障转移时、最多可有多少个Slave同时对新的Master进行同步、默认为1
值越大、集群响应客户端请求的时间总和较大、因为有很多个Slave对新Master进行复制
值越小、集群在故障转移期间、客户端可能会读到旧的数据、因为有些Slave可能还没有将数据同步过来
sentinel failover-timeout m1 180000
执行故障转移的超时时间、故障转移开始后、在此期间仍然没有触发任何故障转移操作、那么当前Sentinel将会认为此次的故障转移操作失败
sentinel down-after-milliseconds m1 10000
指定了Sentinel认为redis节点已经断线所需要的毫秒数
5、解决警告提示
echo net.core.somaxconn = 4096 >> /etc/sysctl.conf echo vm.overcommit_memory = 1 >> /etc/sysctl.conf echo vm.swappiness = 0 >> /etc/sysctl.conf sysctl -p
6、启动Sentinel服务
systemctl enable sentinel systemctl start sentinel netstat -anput | grep sentinel tcp 0 0 10.2.3.11:26379 0.0.0.0:* LISTEN 892/redis-sentinel tcp 0 0 10.2.3.11:38090 10.2.3.14:6379 ESTABLISHED 892/redis-sentinel tcp 0 0 10.2.3.11:12806 10.2.3.14:6379 ESTABLISHED 892/redis-sentinel tcp 0 0 10.2.3.11:20686 10.2.3.13:6379 ESTABLISHED 892/redis-sentinel tcp 0 0 10.2.3.11:55214 10.2.3.13:6379 ESTABLISHED 892/redis-sentinel tcp 0 0 10.2.3.11:8896 10.2.3.12:6379 ESTABLISHED 892/redis-sentinel tcp 0 0 10.2.3.11:23905 10.2.3.12:6379 ESTABLISHED 892/redis-sentinel
4)验证故障转移
1、在node2上停掉当前的redis
[root@node2 ~]# systemctl stop redis
2、查看Sentinel服务器上的日志、可观察故障转移的过程
[root@node1 ~]# tail -f /usr/local/sentinel/log/sentinel.log +sdown master m1 10.2.3.12 6379 +odown master m1 10.2.3.12 6379 #quorum 1/1 +new-epoch 3 +try-failover master m1 10.2.3.12 6379 +vote-for-leader 2175313e5165e3b0d1020f9f666c669a95f699d4 3 +elected-leader master m1 10.2.3.12 6379 +failover-state-select-slave master m1 10.2.3.12 6379 +selected-slave slave 10.2.3.14:6379 10.2.3.14 6379 @ m1 10.2.3.12 6379 +failover-state-send-slaveof-noone slave 10.2.3.14:6379 10.2.3.14 6379 @ m1 10.2.3.12 6379 +failover-state-wait-promotion slave 10.2.3.14:6379 10.2.3.14 6379 @ m1 10.2.3.12 6379 +promoted-slave slave 10.2.3.14:6379 10.2.3.14 6379 @ m1 10.2.3.12 6379 +failover-state-reconf-slaves master m1 10.2.3.12 6379 +slave-reconf-sent slave 10.2.3.13:6379 10.2.3.13 6379 @ m1 10.2.3.12 6379 +slave-reconf-inprog slave 10.2.3.13:6379 10.2.3.13 6379 @ m1 10.2.3.12 6379 +slave-reconf-done slave 10.2.3.13:6379 10.2.3.13 6379 @ m1 10.2.3.12 6379 +failover-end master m1 10.2.3.12 6379 +switch-master m1 10.2.3.12 6379 10.2.3.14 6379
3、在各个节点上查看复制信息、以确认复制是否成功
(1)从节点查看
[root@node3 ~]# redis-cli -h 10.2.3.13 -a abc-123 info replication | grep -v "#" #node3上查看 role:slave master_host:10.2.3.14 #新的Master为10.2.3.14 master_port:6379 master_link_status:up master_last_io_seconds_ago:0 master_sync_in_progress:0 slave_repl_offset:10140 slave_priority:100 slave_read_only:1 connected_slaves:0 master_repl_offset:0 repl_backlog_active:0 repl_backlog_size:1048576 repl_backlog_first_byte_offset:0 repl_backlog_histlen:0
(2)主节点查看
[root@node4 ~]# redis-cli -h 10.2.3.14 -a abc-123 info replication | grep -v "#" #node4上查看 role:master #当前角色为Master connected_slaves:1 #总共有一个Slave slave0:ip=10.2.3.13,port=6379,state=online,offset=13907,lag=0 master_repl_offset:13907 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:2 repl_backlog_histlen:13906 #在node2上重新指定Master的位置、然后再来查看、可看见恢复的节点已经成为Slave [root@node4 ~]# redis-cli -h 10.2.3.14 -a abc-123 info replication | grep -v "#" role:master connected_slaves:2 slave0:ip=10.2.3.13,port=6379,state=online,offset=23933,lag=0 slave1:ip=10.2.3.12,port=6379,state=online,offset=23919,lag=0 master_repl_offset:23933 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:2 repl_backlog_histlen:23932
注意:应用程序连接的时候、连接的是sentinel、而不是redis
六、redis主从同步
redis的主从同步与MySQL的主从同步差不多、也是将一台Master的数据、复制到其它的Slave当中
在redis中主库可以进行读写、而从库一般只为读、一个主库可以有多个从库、而一个从库只能有一个主库
redis的主从同步不仅很好的实现了数据的读写分离、提高了服务器的负载能力、同时也对数据实现了冗余
1)主从同步过程
在主从同步中分为两种同步、一种为全量同步、一种为增量同步
(1)全量同步
全量同步是一个比较耗资源的操作、它发生于Slave的初始化阶段、首先需要在Master上执行一次bgsave 即将内存中的数据保存到磁盘、然后在将保存的文件传送到Slave中、Slave接收以后会执行一次全量加载 加载之前它会把内存中的数据清空、以此来保证数据的一致性、加载完毕之后通知Master继续进行增量同步
(2)增量同步
Slave连接到Master之后、首先进行全量同步、全量同步之后才进行增量同步 增量同步为复制过程当中、Master只要执行一个写的指令、就会向Slave发送相同的指令、Slave收到后并执行
2)主从同步实现
1、实验环境
主机 | 地址 | 系统 | 角色 |
node1 | 10.2.3.11 | CentOS-7.5 | Master |
node2 | 10.2.3.12 | CentOS-7.5 | Slave-1 |
node3 | 10.2.3.13 | CentOS-7.5 | Slave-2 |
2、Master配置文件定义
注意:Master要设置登录密码、等下在Slave中需要添加
requirepass abc-123 #Master定义登录密码 save 900 1 #开启RDB快照 save 300 10 save 60 10000 rdbcompression yes rdbchecksum no dbfilename dump.rdb stop-writes-on-bgsave-error no appendonly yes #开启AOF快照 appendfsync everysec aof-load-truncated yes appendfilename appendonly.aof no-appendfsync-on-rewrite no auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb aof-rewrite-incremental-fsync yes repl-diskless-sync no repl-diskless-sync-delay 5 repl-disable-tcp-nodelay no repl-backlog-size 1mb repl-backlog-ttl 3600 slave-priority 100
3、Slave配置文件定义
注意:Slave自己也要设置访问密码、否则会出现授权问题、为了数据的安全、Slave最好也开启持久化
requirepass abc-123 #Slave定义登录密码 slaveof 10.2.3.11 6379 #Master的IP masterauth abc-123 #Master的密码 slave-read-only yes #是否为只读 repl-ping-slave-period 10 #定义心跳间隔 slave-serve-stale-data yes #Slave可以响应Client请求
4、验证主从同步
(1)Master日志
Starting BGSAVE for SYNC with target: disk DB saved on disk Background saving terminated with success Synchronization with slave 10.2.3.12:6379 succeeded DB saved on disk Background saving terminated with success Synchronization with slave 10.2.3.13:6379 succeeded
(2)Slave日志
MASTER <-> SLAVE sync: Flushing old data MASTER <-> SLAVE sync: Loading DB in memory MASTER <-> SLAVE sync: Finished with success
(3)Master操作
[root@node1 ~]# redis-cli -h 10.2.3.11 -a abc-123 10.2.3.11:6379> info replication role:master #角色为主 connected_slaves:2 #从节点有两台 slave0:ip=10.2.3.12,port=6379,state=online,offset=406,lag=1 slave1:ip=10.2.3.13,port=6379,state=online,offset=406,lag=1 10.2.3.11:6379> rpush linux centos redhat #写入数据 10.2.3.11:6379> lrange linux 0 -1 1) "centos" 2) "redhat"
(3)Slave操作
[root@node2 ~]# redis-cli -h 10.2.3.12 -a abc-123 10.2.3.12:6379> keys l* 1) "linux" 10.2.3.12:6379> lrange linux 0 -1 1) "centos" 2) "redhat" 10.2.3.12:6379> info replication role:slave #角色为从 master_host:10.2.3.11 #主的IP master_port:6379 #主的端口 master_link_status:up #主的状态 10.2.3.12:6379> rpush centos 7.5 #Slave不能写入数据 (error) READONLY You can't write against a read only slave.
5、模拟手动主从切换
(1)停止node1上的redis服务
[root@node1 ~]# systemctl stop redis
(2)将node2设置为临时的Master、重启后失效
10.2.3.12:6379> slaveof no one
(3)将node3的Master指向node2、并重启redis
slaveof 10.2.3.12 6379 masterauth abc-123 slave-read-only yes repl-ping-slave-period 10 slave-serve-stale-data yes [root@node3 ~]# systemctl restart redis
(4)此时的node2已成为临时的Master、所以可以写入数据
10.2.3.12:6379> set k1 v1 10.2.3.12:6379> set k2 v2 10.2.3.12:6379> keys k* 1) "k2" 2) "k1
(5)在node3上查看、可以查看数据已正常同步过来
10.2.3.13:6379> keys k* 1) "k2" 2) "k1" 10.2.3.13:6379> get k1 "v1" 10.2.3.13:6379> get k2 "v2"
(6)假设以前的Master恢复了、那就将临时Master的数据拷贝到以前Master的数据目录下
[root@node2 ~]# scp root@10.2.3.12:/usr/local/redis/data/* root@10.2.3.11:/usr/local/redis/data/
(7)在node1上重启redis、可以看见数据恢复正常
[root@node1 ~]# systemctl restart redis redis-cli -h 10.2.3.11 -a abc-123 keys k* 1) "k2" 2) "k1"
(8)因为是将node2临时设置为Master、所以只需重启redis即可
[root@node2 ~]# systemctl restart redis
(9)将node3的Master指向node1、并重启redis
slaveof 10.2.3.11 6379 masterauth abc-123 slave-read-only yes repl-ping-slave-period 10 slave-serve-stale-data yes [root@node3 ~]# systemctl restart redis
(10)在node1上查看复制情况、可以看见一切恢复正常
10.2.3.11:6379> info replication role:master connected_slaves:2 slave0:ip=10.2.3.12,port=6379,state=online,offset=547,lag=1 slave1:ip=10.2.3.13,port=6379,state=online,offset=547,lag=1
【只是为了打发时间】