集群介绍

Redis Cluster 是 redis的分布式解决方案,在3.0版本正式推出.当遇到单机、内存、并发、流量等瓶颈时,可以采用Cluster架构方案达到负载均衡目的

分布式数据库首先要解决把整个数据库集按照分区规则映射到多个节点的问题,即把数据集划分到多个节点上,每个节点负责整体数据的一个子集,需要关注的是数据分片规则,Redis Cluster采用哈希分片规则

目录规划

# redis安装目录
/opt/redis_cluster/redis_{PORT}/{conf,logs,pid}
# redis数据目录
/data/redis_cluster/redis_{PORT}/redis_{PORT}.rdb
# redis运维脚本
/root/scripts/redis_shell.sh

集群拓扑

决定使用3台虚拟机来搭建集群,每个虚拟机上拥有1主1从,需要让每个从库同步不同主机的主库,防止单机损坏造成集群不可用

  • 不太合理的拓扑

QQ图片20200526134353.png

  • 合理的拓扑

QQ图片20200526134357.png

手动搭建部署集群

QQ图片20200526134401.png

  • 搭建之前需要清空之前的数据文件
  • 部署一台服务器上的2个集群节点
  • 可以使用ansible批量部署
#杀掉其他redis进程
pkill redis
#rm -rf /data/redis_cluster/redis_6379/*

配置节点信息并启动

  • db01创建配置文件
#db01
mkdir -p /opt/redis_cluster/redis_{6380,6381}/{conf,logs,pid}
mkdir –p /data/redis_cluster/redis_{6380,6381}
cat >/opt/redis_cluster/redis_6380/conf/redis_6380.conf<<EOF
bind 10.0.0.51
port 6380
daemonize yes
pidfile "/opt/redis_cluster/redis_6380/pid/redis_6380.pid"
logfile "/opt/redis_cluster/redis_6380/logs/redis_6380.log"
dbfilename "redis_6380.rdb"
dir "/data/redis_cluster/redis_6380/"
cluster-enabled yes
cluster-config-file nodes_6380.conf
cluster-node-timeout 15000
EOF
cd /opt/redis_cluster/
cp redis_6380/conf/redis_6380.conf redis_6381/conf/redis_6381.conf
sed -i 's#6380#6381#g' redis_6381/conf/redis_6381.conf
  • db02创建配置文件
#db02
mkdir -p /opt/redis_cluster/redis_{6380,6381}/{conf,logs,pid}
mkdir –p /data/redis_cluster/redis_{6380,6381}
cat >/opt/redis_cluster/redis_6380/conf/redis_6380.conf<<EOF
bind 10.0.0.52
port 6380
daemonize yes
pidfile "/opt/redis_cluster/redis_6380/pid/redis_6380.pid"
logfile "/opt/redis_cluster/redis_6380/logs/redis_6380.log"
dbfilename "redis_6380.rdb"
dir "/data/redis_cluster/redis_6380/"
cluster-enabled yes
cluster-config-file nodes_6380.conf
cluster-node-timeout 15000
EOF
cd /opt/redis_cluster/
cp redis_6380/conf/redis_6380.conf redis_6381/conf/redis_6381.conf
sed -i 's#6380#6381#g' redis_6381/conf/redis_6381.conf
  • db03创建配置文件
#db03
mkdir -p /opt/redis_cluster/redis_{6380,6381}/{conf,logs,pid}
mkdir –p /data/redis_cluster/redis_{6380,6381}
cat >/opt/redis_cluster/redis_6380/conf/redis_6380.conf<<EOF
bind 10.0.0.53
port 6380
daemonize yes
pidfile "/opt/redis_cluster/redis_6380/pid/redis_6380.pid"
logfile "/opt/redis_cluster/redis_6380/logs/redis_6380.log"
dbfilename "redis_6380.rdb"
dir "/data/redis_cluster/redis_6380/"
cluster-enabled yes
cluster-config-file nodes_6380.conf
cluster-node-timeout 15000
EOF
cd /opt/redis_cluster/
cp redis_6380/conf/redis_6380.conf redis_6381/conf/redis_6381.conf
sed -i 's#6380#6381#g' redis_6381/conf/redis_6381.conf
  • 启动节点
#db01,db02,db03
redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf

手动配置节点发现

  • 当把所有节点都启动后查看进程会有cluster的字样,但是登录后执行CLUSTER NODES命令会发现只有每个节点自己的ID,目前集群内的节点还没有互相发现,所以搭建redis集群我们第一步要做的就是让集群内的节点互相发现
  • 在执行节点发现命令之前我们先查看一下集群的数据目录会发现有生成集群的配置文件
  • 查看后发现只有自己的节点内容,等节点全部发现后会把所发现的节点ID写入这个文件
  • 集群模式的Redis除了原有的配置文件之外又加了一份集群配置文件(配置文件中cluster-config-file参数指定).当集群内节点信息发生变化,如添加节点,节点下线,故障转移等.节点会自动保存集群状态到配置文件
  • 需要注意的是,Redis自动维护集群配置文件,不需要手动修改,防止节点重启时产生错乱
  • CLUSTER MEET {IP} {PORT} : 节点发现命令,可以在集群内任意一台机器执行命令
#登录redis
redis-cli -h db01 -p 6380

#添加节点
CLUSTER MEET 10.0.0.51 6381
CLUSTER MEET 10.0.0.52 6381
CLUSTER MEET 10.0.0.53 6381
CLUSTER MEET 10.0.0.53 6380
CLUSTER MEET 10.0.0.52 6380

#查看节点
CLUSTER NODES

Redis Cluster 通讯流程

QQ图片20200526134404.png

在分布式存储中需要提供维护节点元数据信息的机制,所谓元数据是指:节点负责哪些数据,是否出现故障灯状态信息,redis 集群采用 Gossip(流言)协议,Gossip协议工作原理就是节点彼此不断交换信息,一段时间后所有的节点都会知道集群完整信息,这种方式类似流言传播

  • 通信过程
  1. 集群中的每一个节点都会单独开辟一个 Tcp 通道,用于节点之间彼此通信,通信端口在基础端口上家10000.
  2. 每个节点在固定周期内通过特定规则选择结构节点发送 ping 消息
  3. 接收到 ping 消息的节点用 pong 消息作为响应.集群中每个节点通过一定规则挑选要通信的节点,每个节点可能知道全部节点,也可能仅知道部分节点,只要这些节点彼此可以正常通信,最终他们会打成一致的状态,当节点出现故障,新节点加入,主从角色变化等,它能够给不断的ping/pong消息,从而达到同步目的.
  • 通讯消息类型

Gossip 协议职责就是信息交换,信息交换的载体就是节点间彼此发送Gossip 消息.常见 Gossip 消息分为:ping、 pong、 meet、 fail 等

  • meet : 用于通知新节点加入,消息发送者通知接受者加入到当前集群,meet 消息通信正常完成后,接收节点会加入到集群中并进行ping、 pong 消息交换
  • ping : 集群内交换最频繁的消息,集群内每个节点每秒想多个其他节点发送 ping 消息,用于检测节点是否在线和交换彼此信息
  • pong : 当接收到 ping,meet 消息时,作为相应消息回复给发送方确认消息正常通信,节点也可以向集群内广播自身的 pong 消息来通知整个集群对自身状态进行更新
  • fail : 当节点判定集群内另一个节点下线时,回向集群内广播一个fail 消息,其他节点收到 fail 消息之后把对应节点更新为下线状态

Redis Cluster手动分配槽位

虽然节点之间已经互相发现了,但是此时集群还是不可用的状态,因为并没有给节点分配槽位,而且必须是所有的槽位都分配完毕后整个集群才是可用的状态.反之,也就是说只要有一个槽位没有分配,那么整个集群就是不可用的.

  • 不分配槽位的情况下使用
db01:6380> set k1 v1
(error) CLUSTERDOWN Hash slot not served
db01:6380> CLUSTER INFO
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:0
cluster_current_epoch:5
cluster_my_epoch:0
cluster_stats_messages_sent:1766
cluster_stats_messages_received:1766

虽然有6个节点,但是真正负责数据写入的只有3个节点,其他3个节点只是作为主节点的从节点,也就是说,只需要分配期中三个节点的槽位就可以了

  • 分配槽位需要在每个主节点上来配置,此时有2种方法执行:1.分别登录到每个主节点的客户端来执行命令2.在其中一台机器上用redis客户端远程登录到其他机器的主节点上执行命令
#分配槽位
redis-cli -h db01 -p 6380 cluster addslots {0..5461}
redis-cli -h db02 -p 6380 cluster addslots {5462..10922}
redis-cli -h db03 -p 6380 cluster addslots {10923..16383}
  • 分配完所有槽位后查看集群状态
[root@db02 redis_cluster]# redis-cli -h db01 -p 6380 CLUSTER INFO
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:5
cluster_my_epoch:0
cluster_stats_messages_sent:2195
cluster_stats_messages_received:2195

手动配置集群高可用

虽然这时候集群是可用的了,但是整个集群只要有一台机器坏掉了,那么整个集群都是不可用的. 所以这时候需要用到其他三个节点分别作为现在三个主节点的从节点,以应对集群主节点故障时可以进行自动切换以保证集群持续可用.

  • 不要让复制节点复制本机器的主节点,因为如果那样的话机器挂了集群还是不可用状态,所以复制节点要复制其他服务器的主节点.
  • 使用redis-trid工具自动分配的时候会出现复制节点和主节点在同一台机器上的情况,需要注意
#查看主节点
[root@db02 redis_cluster]# redis-cli -h db01 -p 6380 CLUSTER nodes| grep 6380
da408d4dd1e069de499e1f3170566fc3e00e9afd 10.0.0.53:6380 master - 0 1590474732260 4 connected 10923-16383
fd3a376fa7477bfc837ac9f64edab851f8b717b4 10.0.0.51:6380 myself,master - 0 0 0 connected 0-5461
736fb8deea230949fa2c386f4171b31764d635f0 10.0.0.52:6380 master - 0 1590474729241 5 connected 5462-10922

#创建复制关系
[root@db02 redis_cluster]# redis-cli -h db01 -p 6381 CLUSTER REPLICATE 736fb8deea230949fa2c386f4171b31764d635f0
OK
[root@db02 redis_cluster]# redis-cli -h db02 -p 6381 CLUSTER REPLICATE da408d4dd1e069de499e1f3170566fc3e00e9afd
OK
[root@db02 redis_cluster]# redis-cli -h db03 -p 6381 CLUSTER REPLICATE fd3a376fa7477bfc837ac9f64edab851f8b717b4
OK

Redis Cluster测试集群

使用常规插入redis数据的方式往集群里写入数据可能会出现提示移动到其他节点进行插入

 [root@db01 ~]# redis-cli -h db01 -p 6380 set k1 v1
(error) MOVED 12706 10.0.0.53:6380

#数据并没有插入
[root@db01 ~]# redis-cli -h db03 -p 6380 get k1    
(nil)

这是因为使用集群后由于数据被分片了,所以并不是说在那台机器上写入数据就会在哪台机器的节点上写入,集群的数据写入和读取就涉及到了另外一个概念,ASK路由

Redis Cluster ASK路由介绍

QQ图片20200526134414.png

在集群模式下,Redis接受任何键相关命令时首先会计算键对应的槽,再根据槽找出所对应的节点,如果节点是自身,则处理键命令.否则回复MOVED重定向错误,通知客户端请求正确的节点,这个过程称为Mover重定向.

#使用命令插入测试数据
for i in $(seq 1 1000);do redis-cli -c -h db01 -p 6380 set k_${i} v_${i} && echo "set k_${i} is ok"; done

写入后我们同样使用-c选项来读取刚才插入的键值

[root@db01 redis_cluster]# redis-cli -h db01 -p 6380 -c
db01:6380> get k_1
"v_1"
db01:6380> get k_2
-> Redirected to slot [8970] located at 10.0.0.52:6380
"v_2"
10.0.0.52:6380>

关于-c参数的解释

  • Enable cluster mode (follow -ASK and -MOVED redirections).
  • 启用集群模式(遵循-ASK和-MOVED重定向)

模拟故障转移

停掉期中一台主机的redis节点,然后通过日志查看一下集群的变化

  • 使用kill -9杀掉db02上的6380节点,一段时间后db01的6381节点会接替原主节点
  • 想让修复后的节点重新上线,可以在想变成主库的从库执行CLUSTER FAILOVER命令

集群配置文件变化

#变化前
[root@db02 redis_6381]# cat nodes_6381.conf 
730741f4b16f8e326472452210c0eaffabc548b2 10.0.0.52:6381 myself,slave da408d4dd1e069de499e1f3170566fc3e00e9afd 0 0 2 connected
a1b16f9cfc6b306a8616e6509c86393c6e296438 10.0.0.51:6381 slave 736fb8deea230949fa2c386f4171b31764d635f0 0 1590474844434 5 connected
da408d4dd1e069de499e1f3170566fc3e00e9afd 10.0.0.53:6380 master - 0 1590474845441 4 connected 10923-16383
736fb8deea230949fa2c386f4171b31764d635f0 10.0.0.52:6380 master - 0 1590474843427 5 connected 5462-10922
940a4e8a8b5670ad9dbe4d6e691f040d4eb94e19 10.0.0.53:6381 slave fd3a376fa7477bfc837ac9f64edab851f8b717b4 0 1590474842421 3 connected
fd3a376fa7477bfc837ac9f64edab851f8b717b4 10.0.0.51:6380 master - 0 1590474846448 0 connected 0-5461
vars currentEpoch 5 lastVoteEpoch 0

#变化后
[root@db02 redis_6381]# cat nodes_6381.conf 
730741f4b16f8e326472452210c0eaffabc548b2 10.0.0.52:6381 myself,slave da408d4dd1e069de499e1f3170566fc3e00e9afd 0 0 2 connected
a1b16f9cfc6b306a8616e6509c86393c6e296438 10.0.0.51:6381 master - 0 1590475863418 6 connected 5462-10922
da408d4dd1e069de499e1f3170566fc3e00e9afd 10.0.0.53:6380 master - 0 1590475868453 4 connected 10923-16383
736fb8deea230949fa2c386f4171b31764d635f0 10.0.0.52:6380 master,fail - 1590475851538 1590475851337 5 disconnected
940a4e8a8b5670ad9dbe4d6e691f040d4eb94e19 10.0.0.53:6381 slave fd3a376fa7477bfc837ac9f64edab851f8b717b4 0 1590475867447 3 connected
fd3a376fa7477bfc837ac9f64edab851f8b717b4 10.0.0.51:6380 master - 0 1590475866439 0 connected 0-5461
vars currentEpoch 6 lastVoteEpoch 0

重新启动节点

#db02上6380节点变为从节点
[root@db02 redis_6381]# cat nodes_6381.conf 
730741f4b16f8e326472452210c0eaffabc548b2 10.0.0.52:6381 myself,slave da408d4dd1e069de499e1f3170566fc3e00e9afd 0 0 2 connected
a1b16f9cfc6b306a8616e6509c86393c6e296438 10.0.0.51:6381 master - 0 1590475949991 6 connected 5462-10922
da408d4dd1e069de499e1f3170566fc3e00e9afd 10.0.0.53:6380 master - 0 1590475955025 4 connected 10923-16383
736fb8deea230949fa2c386f4171b31764d635f0 10.0.0.52:6380 slave a1b16f9cfc6b306a8616e6509c86393c6e296438 0 1590475955729 6 connected
940a4e8a8b5670ad9dbe4d6e691f040d4eb94e19 10.0.0.53:6381 slave fd3a376fa7477bfc837ac9f64edab851f8b717b4 0 1590475953011 3 connected
fd3a376fa7477bfc837ac9f64edab851f8b717b4 10.0.0.51:6380 master - 0 1590475954019 0 connected 0-5461
vars currentEpoch 6 lastVoteEpoch 0

db02上6380节点恢复主节点集群配置文件变化过程

[root@db02 redis_6381]# redis-cli -h db02 -p 6380 CLUSTER FAILOVER
OK
[root@db02 redis_6381]# cat nodes_6381.conf 
730741f4b16f8e326472452210c0eaffabc548b2 10.0.0.52:6381 myself,slave da408d4dd1e069de499e1f3170566fc3e00e9afd 0 0 2 connected
a1b16f9cfc6b306a8616e6509c86393c6e296438 10.0.0.51:6381 master - 0 1590476130216 6 connected
da408d4dd1e069de499e1f3170566fc3e00e9afd 10.0.0.53:6380 master - 0 1590476132229 4 connected 10923-16383
736fb8deea230949fa2c386f4171b31764d635f0 10.0.0.52:6380 master - 0 1590476128202 7 connected 5462-10922
940a4e8a8b5670ad9dbe4d6e691f040d4eb94e19 10.0.0.53:6381 slave fd3a376fa7477bfc837ac9f64edab851f8b717b4 0 1590476129208 3 connected
fd3a376fa7477bfc837ac9f64edab851f8b717b4 10.0.0.51:6380 master - 0 1590476131223 0 connected 0-5461
vars currentEpoch 7 lastVoteEpoch 0
[root@db02 redis_6381]# cat nodes_6381.conf 
730741f4b16f8e326472452210c0eaffabc548b2 10.0.0.52:6381 myself,slave da408d4dd1e069de499e1f3170566fc3e00e9afd 0 0 2 connected
a1b16f9cfc6b306a8616e6509c86393c6e296438 10.0.0.51:6381 slave 736fb8deea230949fa2c386f4171b31764d635f0 0 1590476130216 7 connected
da408d4dd1e069de499e1f3170566fc3e00e9afd 10.0.0.53:6380 master - 0 1590476132229 4 connected 10923-16383
736fb8deea230949fa2c386f4171b31764d635f0 10.0.0.52:6380 master - 0 1590476133236 7 connected 5462-10922
940a4e8a8b5670ad9dbe4d6e691f040d4eb94e19 10.0.0.53:6381 slave fd3a376fa7477bfc837ac9f64edab851f8b717b4 0 1590476134243 3 connected
fd3a376fa7477bfc837ac9f64edab851f8b717b4 10.0.0.51:6380 master - 0 1590476131223 0 connected 0-5461
vars currentEpoch 7 lastVoteEpoch 0

使用工具搭建部署Redis Cluster

手动搭建集群便于理解集群创建的流程和细节,不过手动搭建集群需要很多步骤,当集群节点众多时,必然会加大搭建集群的复杂度和运维成本,因此官方提供了redis-trib.rb的工具方便我们快速搭建集群

  • redis-trib.rb是采用Ruby实现的redis集群管理工具,内部通过Cluster相关命令帮我们简化集群创建,检查,槽迁移和均衡等常见运维操作,使用前要安装 ruby 依赖环境
yum makecache fast
yum install -y rubygems
#因为国外源不可用,替换国内源
gem sources --remove https://rubygems.org/
gem sources -a http://mirrors.aliyun.com/rubygems/
gem update - system
gem install redis -v 3.3.5

清空集群数据,恢复为6个节点

pkill redis
rm -rf /data/redis_cluster/redis_6380/*
rm -rf /data/redis_cluster/redis_6381/*
#重新启动节点
redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf

在安装ruby环境的主机的指定目录下执行该命令

#进入到指定目录下
cd /opt/redis_cluster/redis/src/

# 一共有6个节点 --replicas 1 表示每个节点拥有1个从节点,写在前面3个为主节点,后面3个为从节点
./redis-trib.rb create --replicas 1 10.0.0.51:6380 10.0.0.52:6380 10.0.0.53:6380 10.0.0.51:6381 10.0.0.52:6381 10.0.0.53:6381

#检查集群完整性
./redis-trib.rb check 10.0.0.51:6380

使用工具重新分配槽位

对于添加节点和删除节点都会涉及到槽位重新分配,利用官方提供的工具可以实现移动槽位,也就是可以利用官方工具进行扩容缩容

扩容

  1. 准备新节点
  2. 加入集群
  3. 迁移槽和数据

准备新的节点

#db01
mkdir -p /opt/redis_cluster/redis_{6390,6391}/{conf,logs,pid}
mkdir -p /data/redis_cluster/redis_{6390,6391}
cd /opt/redis_cluster/
cp redis_6380/conf/redis_6380.conf redis_6390/conf/redis_6390.conf
cp redis_6380/conf/redis_6380.conf redis_6391/conf/redis_6391.conf
sed -i 's#6380#6390#g' redis_6390/conf/redis_6390.conf
sed -i 's#6380#6391#g' redis_6391/conf/redis_6391.conf

启动节点并加入集群

#启动节点
redis-server /opt/redis_cluster/redis_6390/conf/redis_6390.conf
redis-server /opt/redis_cluster/redis_6391/conf/redis_6391.conf

#加入集群
redis-cli -c -h db01 -p 6380 cluster meet 10.0.0.51 6390
redis-cli -c -h db01 -p 6380 cluster meet 10.0.0.51 6391

迁移槽位进行扩容

cd /opt/redis_cluster/redis/src/
./redis-trib.rb reshard 10.0.0.51:6380

工具操作

[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
打印出进群每个节点信息后,reshard命令需要确认迁移的槽数量
How many slots do you want to move (from 1 to 16384)? 4096
输入6390的节点ID作为目标节点,也就是要扩容的节点,目标节点只能指定一个
What is the receiving node ID? efb01c1ab1cb563cf1ce3d498b27edb21d8794b6
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
之后输入源节点的ID,这里分别输入每个主节点的6380的ID最后输入done,或者直接输入all
Source node #1:all
...
Do you want to proceed with the proposed reshard plan (yes/no)? yes

查看集群的状态

[root@db01 src]# ./redis-trib.rb rebalance 10.0.0.51:6380
>>> Performing Cluster Check (using node 10.0.0.51:6380)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
#不需要再平衡!所有节点都在2.0%阈值内
*** No rebalancing needed! All nodes are within the 2.0% threshold.

缩容

  1. 首先需要确定下线节点是否有负责的槽,如果是,需要把槽均匀迁移到其他节点,保证节点下线后整个集群槽节点映射的完整性.
  2. 当下线节点不再负责槽或者本身是从节点时,就可以通知集群内其他节点忘记下线节点,当所有的节点忘记该节点后可以正常关闭.

收缩和扩容迁移的方向相反,6390变为源节点,其他节点变为目标节点,源节点把自己负责的4096个槽均匀的迁移到其他节点上,由于redis-trib.rb reshard命令只能有一个目标节点,因此需要执行3次reshard命令,分别迁移1365,1365,1366个槽

cd /opt/redis_cluster/redis/src/
./redis-trib.rb reshard 10.0.0.51:6380

执行过程(重复迁移3次)

[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
打印出进群每个节点信息后,reshard命令需要确认迁移的槽数量
How many slots do you want to move (from 1 to 16384)? 1365
输入6390的节点ID作为目标节点,也就是要扩容的节点,目标节点只能指定一个
What is the receiving node ID? 834c74771fccde49a90d8a6da41bcf47fdaa06f3
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
之后输入源节点的ID,这里分别输入每个主节点的6380的ID最后输入done,或者直接输入all
Source node #1:efb01c1ab1cb563cf1ce3d498b27edb21d8794b6
Source node #2:done
...
Do you want to proceed with the proposed reshard plan (yes/no)? yes

删除节点

#需要节点ip,端口,节点id 否则无法删除节点
cd /opt/redis_cluster/redis/src/
./redis-trib.rb del-node 10.0.0.51:6390 efb01c1ab1cb563cf1ce3d498b27edb21d8794b6
./redis-trib.rb del-node 10.0.0.51:6391 51f291f3972d0f2c354ce4ec7f9dc3a8f775e3d0

Redis集群常用命令

集群(cluster)

- CLUSTER INFO 打印集群的信息 - CLUSTER NODES 列出集群当前已知的所有节点(node),以及这些节点的相关信息

节点(node)

- CLUSTER MEET 将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子 - CLUSTER FORGET 从集群中移除 node_id 指定的节点 - CLUSTER REPLICATE 将当前节点设置为 node_id 指定的节点的从节点 - CLUSTER SAVECONFIG 将节点的配置文件保存到硬盘里面

槽(slot)

  • CLUSTER ADDSLOTS [slot ...] : 将一个或多个槽(slot)指派(assign)给当前节点
  • CLUSTER DELSLOTS [slot ...] : 移除一个或多个槽对当前节点的指派
  • CLUSTER FLUSHSLOTS : 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点
  • CLUSTER SETSLOT NODE : 将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派
  • CLUSTER SETSLOT MIGRATING : 将本节点的槽 slot 迁移到 node_id 指定的节点中
  • CLUSTER SETSLOT IMPORTING : 从 node_id 指定的节点中导入槽 slot 到本节点
  • CLUSTER SETSLOT STABLE : 取消对槽 slot 的导入(import)或者迁移(migrate)

键 (key)

  • CLUSTER KEYSLOT : 计算键 key 应该被放置在哪个槽上
  • CLUSTER COUNTKEYSINSLOT : 返回槽 slot 目前包含的键值对数量
  • CLUSTER GETKEYSINSLOT : 返回 count 个 slot 槽中的键

Redis运维工具

运维脚本

需要特定目录,使用时需要注意配置文件和数据目录的位置是否正确

#!/bin/bash

USAG(){
    echo "sh $0 {start|stop|restart|login|ps|tail} PORT"
}
if [ "$#" = 1 ]
then
    REDIS_PORT='6379'
elif 
    [ "$#" = 2 -a -z "$(echo "$2"|sed 's#[0-9]##g')" ]
then
    REDIS_PORT="$2"
else
    USAG
    exit 0
fi

REDIS_IP=$(hostname -I|awk '{print $1}')
PATH_DIR=/opt/redis_cluster/redis_${REDIS_PORT}/
PATH_CONF=/opt/redis_cluster/redis_${REDIS_PORT}/conf/redis_${REDIS_PORT}.conf
PATH_LOG=/opt/redis_cluster/redis_${REDIS_PORT}/logs/redis_${REDIS_PORT}.log

CMD_START(){
    redis-server ${PATH_CONF}
}

CMD_SHUTDOWN(){
    redis-cli -c -h ${REDIS_IP} -p ${REDIS_PORT} shutdown
}

CMD_LOGIN(){
    redis-cli -c -h ${REDIS_IP} -p ${REDIS_PORT}
}

CMD_PS(){
    ps -ef|grep redis
}

CMD_TAIL(){
    tail -f ${PATH_LOG}
}

case $1 in
    start)
        CMD_START
        CMD_PS
        ;;
    stop)
        CMD_SHUTDOWN
        CMD_PS
        ;;
    restart)
        CMD_START
        CMD_SHUTDOWN
        CMD_PS
        ;;
    login)
        CMD_LOGIN
        ;;
    ps)
        CMD_PS
        ;;
    tail)
        CMD_TAIL
        ;;
    *)
        USAG
esac

数据导入导出工具

切换到redis集群的时候肯定会面临数据导入的问题,所以这里推荐使用redis-migrate-tool工具来导入单节点数据到集群里

安装工具

cd /opt/redis_cluster/
git clone https://github.com/vipshop/redis-migrate-tool.git
cd redis-migrate-tool/
autoreconf -fvi
./configure
make && make install 

创建配置文件

cat > redis_6379_to_6380.conf << EOF
[source]
type: single
servers:
- 10.0.0.51:6379

[target]
type: redis cluster
servers:
- 10.0.0.51:6380 

[common]
listen: 0.0.0.0:8888
source_safe: true
EOF

测试导入

#生成测试数据
redis-server /opt/redis_cluster/redis_6379/conf/redis_6379.conf
for i in $(seq 1 1000);do redis-cli -c -h db01 -p 6379 set k_${i} v_${i} && echo "set k_${i} is ok";done

#执行导入命令
redis-migrate-tool -c redis_6379_to_6380.conf

#数据校验
redis-migrate-tool -c redis_6379_to_6380.conf -C redis_check

分析键值大小

redis的内存使用太大键值太多,不知道哪些键值占用的容量比较大,而且在线分析会影响性能

安装工具

yum install -y python-pip gcc python-devel
cd /opt/
git clone https://github.com/sripathikrishnan/redis-rdb-tools
cd /opt/redis-rdb-tools
python setup.py install

使用方法

#分析数据
cd /data/redis_cluster/redis_6380/
rdb -c memory redis_6380.rdb -f redis_6380.rdb.csv

#排序导出
awk -F ',' '{print $4,$2,$3,$1}' redis_6380.rdb.csv |sort  > 6380.txt

监控过期键

因为开发重复提交,导致电商网站优惠卷过期时间失效,参考拼多多100元无门槛优惠券

  • 问题分析: 如果一个键已经设置了过期时间,这时候在set这个键,过期时间就会取消

解决思路: 如何在不影响机器性能的前提下批量获取需要监控键过期时间

  • Keys *查出来匹配的键名.然后循环读取ttl时间
  • scan *范围查询键名.然后循环读取ttl时间
  • Keys 重操作,会影响服务器性能,除非是不提供服务的从节点
  • Scan 负担小,但是需要去多次才能取完,需要写脚本
#!/bin/bash
key_num=0
> key_name.log
for line in $(cat key_list.txt)
do
    while true
    do
        scan_num=$(redis-cli -h 10.0.0.51 -p 6380 SCAN ${key_num} match ${line}\* count 1000|awk 'NR==1{print $0}')
        key_name=$(redis-cli -h 10.0.0.51 -p 6380 SCAN ${key_num} match ${line}\* count 1000|awk 'NR>1{print $0}')
        echo ${key_name}|xargs -n 1 >> key_name.log
        ((key_num=scan_num))
        if [ ${key_num} == 0 ]
           then
           break
        fi
    done
done

故障案例

redis动态调整内存故障

如果redis占满内存,会发生三种情况之一.惰性删除,即删除时间最长的键;随机删除;什么都不做;默认是什么都不做

  • 动态内存调整只能调整的比实际占用的大,不能调整的比实际占用的小.不然就会出现以上情况
  • 动态调整的参数不会写入到配置文件里,配置文件里也看不到最大内存使用限制,即使重启,动态配置也会生效
  • 只能通过config get maxamemory和config set maxmemory 0来恢复配置
  • 需要了解的内容:redis的几种内存回收机制
#查看最大内存
config get maxmemory

#设置最大内存为26843545600
config set maxmemory 26843545600

#设置内存无限制
config set maxmemory 0