Redis主从+哨兵+集群

第五章 Redis主从复制

5.1 主从复制介绍

在分布式系统中为了解决单点问题,通常会把数据复制多个副本到其他机器,满足故障恢复和负载均衡等要求。
Redis也是如此,提供了复制功能。
复制功能是高可用Redis的基础,后面的哨兵和集群都是在复制的基础上实现高可用的.

5.2 redis复制功能介绍(重点了解)

  1. Redis 使用异步复制。从 Redis2.8开始,从服务器会以每秒一次的频率向主服务器报告复制流(replication stream)的处理进度。
  2. 一个主服务器可以有多个从服务器。
  3. 不仅主服务器可以有从服务器,从服务器也可以有自己的从服务器,多个从服务器之间可以构成一个图状结构。
  4. 复制功能不会阻塞主服务器:即使有一个或多个从服务器正在进行初次同步, 主服务器也可以继续处理命令请求。
  5. 复制功能也不会阻塞从服务器:只要在 redis.conf 文件中进行了相应的设置, 即使从服务器正在进行初次同步, 服务器也可以使用旧版本的数据集来处理命令查询。
  6. 在从服务器删除旧版本数据集并载入新版本数据集的那段时间内,连接请求会被阻塞。
  7. 还可以配置从服务器,让它在与主服务器之间的连接断开时,向客户端发送一个错误。
  8. 复制功能可以单纯地用于数据冗余(data redundancy),也可以通过让多个从服务器处理只读命令请求来提升扩展性(scalability): 比如说,繁重的SORT命令可以交给附属节点去运行。
  9. 可以通过复制功能来让主服务器免于执行持久化操作:只要关闭主服务器的持久化功能,然后由从服务器去执行持久化操作即可。

5.3 主从复制原理

image.png
  1. 从节点发送同步请求(SYNC命令)到主节点
  2. 主节点接收到从节点的请求(SYNC命令)之后,做了如下操作
  • 立即执行bgsave将当前内存里的数据持久化到磁盘上
  • 持久化完成之后,将rdb文件发送给从节点
  1. 从节点从主节点接收到rdb文件之后,做了如下操作
  • 清空自己的数据 //非常危险,从库插入的数据,主从复制时会清空从库。如果搞反主从关系,会直接删除主库的数据。
  • 载入从主节点接收的rdb文件到自己的内存里
  1. 从节点和主节点实时复制

注:从 Redis2.8开始,Redis使用PSYNC命令代替SYNC命令。PSYNC实现了部分重同步(partial resync)特性:
在主从服务器断线并且重新连接的时候,只要条件允许,PSYNC可以让主服务器只向从服务器同步断线期间缺失的数据,而不用重新向从服务器同步整个数据库。

5.4 打开主服务器持久化

image.png
  1. 当配置Redis复制功能时,强烈建议打开主服务器的持久化功能。 否则的话,由于延迟等问题,部署的服务应该要避免自动拉起。
  2. 为了帮助理解主服务器关闭持久化时自动拉起的危险性,参考一下以下会导致主从服务器数据全部丢失的例子:
    1)假设节点A为主服务器,并且关闭了持久化。并且节点B和节点C从节点A复制数据
    2)节点A崩溃,然后由自动拉起服务重启了节点A. 由于节点A的持久化被关闭了,所以重启之后没有任何数据
    3)节点B和节点C将从节点A复制数据,但是A的数据是空的,于是就把自身保存的数据副本删除。

结论:

  • 在关闭主服务器上的持久化,并同时开启自动拉起进程的情况下,即便使用Sentinel来实现Redis的高可用性,也是非常危险的。因为主服务器可能拉起得非常快,以至于Sentinel在配置的心跳时间间隔内没有检测到主服务器已被重启,然后还是会执行上面的数据丢失的流程。
  • 无论何时,数据安全都是极其重要的,所以应该禁止主服务器关闭持久化的同时自动拉起。

5.5 Redis是怎么保证数据安全的呢?

  1. 从Redis 2.8开始,为了保证数据的安全性,可以通过配置,让主服务器只在有至少N个当前已连接从服务器的情况下,才执行写命令。
  2. 不过,因为 Redis 使用异步复制,所以主服务器发送的写数据并不一定会被从服务器接收到,因此, 数据丢失的可能性仍然是存在的。
  3. 通过以下两个参数保证数据的安全:
# 执行写操作所需的至少从服务器数量
min-slaves-to-write <number of slaves>
#指定网络延迟的最大值
min-slaves-max-lag <number of seconds>

5.6 开启主从复制的三种方式

  1. 在配置文件中加入slaveof 10.0.0.51 6379 随redis启动生效.
  2. 在redis-server启动命令后加入—slaveof 10.0.0.51 6379生效.
  3. 登录从库直接使用命令:slaveof 10.0.0.51 6379生效.
# 从库配置文件
cat /etc/redis/6379/redis.conf
port 6379
daemonize yes
pidfile /etc/redis/6379/redis.pid
loglevel notice
logfile /etc/redis/6379/redis.log
dbfilename dump.rdb
dir /etc/redis/6379
bind 127.0.0.1 10.0.0.51
protected-mode no

# 查看主从信息
Info replication

# 断开复制
slave of no one

# 切换主从
slaveof {newMasterIp} {newMasterPort}

注意:

  • 从节点只读不可写
  • 从节点不会自动故障转移,它会一直同步主
  • 从节点断开复制后不会抛弃原有数据,只是无法再获取主节点上的数据变化.
  • 切换主后会清空之前所有的数据,线上操作一定要小心.
  • 安全的操作:无论是主节点还是从节点主从复制时,先备份一下数据

第六章 哨兵 Sentinel

6.1 哨兵介绍

Redis-Sentinel是Redis官方推荐的高可用性解决方案,当用Redis做Master-slave的高可用方案时,假如master宕机了,Redis本身都没有实现自动进行主备切换,而Redis-sentinel本身也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自动切换。

6.2 sentinel的功能

  1. 监控(Monitoring):
    Sentinel会不断地检查你的主服务器和从服务器是否运作正常。
  2. 提醒(Notification):
    当被监控的某个Redis服务器出现问题时,Sentinel可以通过API向管理员或者其他应用程序发送通知。
  3. 自动故障迁移(Automatic failover):
    当一个主服务器不能正常工作时,Sentinel会开始一次自动故障迁移操作,它会将失效主服务器的其中一个从服务器升级为新的主服务器,并让失效主服务器的其他从服务器改为复制新的主服务器;当客户端试图连接失效的主服务器时,集群也会向客户端返回新主服务器的地址,使得集群可以使用新主服务器代替失效服务器。

6.3 故障转移failover

一次故障转移操作由以下步骤组成:

  1. 发现主服务器已经进入客观下线状态。
  2. 基于Raft leader election协议 ,进行投票选举
  3. 如果当选失败,那么在设定的故障迁移超时时间的两倍之后,重新尝试当选。如果当选成功,那么执行以下步骤。
  4. 选出一个从服务器,并将它升级为主服务器。
  5. 向被选中的从服务器发送 SLAVEOF NO ONE 命令,让它转变为主服务器。
  6. 通过发布与订阅功能,将更新后的配置传播给所有其他Sentinel,其他Sentinel对它们自己的配置进行更新。
  7. 向已下线主服务器的从服务器发送SLAVEOF命令,让它们去复制新的主服务器。
  8. 当所有从服务器都已经开始复制新的主服务器时, leader Sentinel 终止这次故障迁移操作。

6.4 安装部署命令

前提:哨兵是基于主从复制,所有节点都启动redis,并且已部署好主从复制关系

注意!哨兵的配置文件会自动更改,不要手动修改!

# db01节点
mkdir -p /data/redis_cluster/redis_26379
mkdir -p /opt/redis_cluster/redis_26379/{conf,pid,logs}
cat >/opt/redis_26379/conf/redis_26379.conf << EOF
bind $(ifconfig eth0|awk 'NR==2{print $2}')
port 26379
daemonize yes
logfile /opt/redis_26379/logs/redis_26379.log
dir /data/redis_26379
sentinel monitor myredis 10.0.0.51 6379 2     //51是主节点,2表示至少有两个成员活着才能选举新的主节点,myredis是组名
sentinel down-after-milliseconds myredis 3000  //超过3000毫秒(3秒)连不上,才会认为主节点挂掉
sentinel parallel-syncs myredis 1     //同时向主节点发起复制的从库的个数,设置为一个,主节点压力小
sentinel failover-timeout myredis 18000   //故障转移超时时间,超过时间表示转移失败,重新执行
EOF

# 将配置文件传给db02、db03
rsync -avz /opt/* db02:/opt/
rsync -avz /opt/* db03:/opt/

# db02
mkdir -p /data/redis_cluster/redis_26379
cd /opt/redis_cluster/redis
make install
sed -i 's#bind 10.0.0.51#bind 10.0.0.52#g' /opt/redis_cluster/redis_6379/conf/redis_6379.conf
sed -i 's#bind 10.0.0.51#bind 10.0.0.52#g' /opt/redis_cluster/redis_26379/conf/redis_26379.conf

# db03
mkdir -p /data/redis_cluster/redis_26379
cd /opt/redis_cluster/redis
make install
sed -i 's#bind 10.0.0.51#bind 10.0.0.53#g' /opt/redis_cluster/redis_6379/conf/redis_6379.conf
sed -i 's#bind 10.0.0.51#bind 10.0.0.53#g' /opt/redis_cluster/redis_26379/conf/redis_26379.conf

db02/db03配置主从关系

redis-server /opt/redis_cluster/redis_6379/conf/redis_6379.conf
redis-cli slaveof 10.0.0.51 6379
ps -ef|grep redis

所有节点都启动哨兵

redis-sentinel /opt/redis_cluster/redis_26379/conf/redis_26379.conf

验证进程

[root@redis ~]# ps -ef|grep redis
root       8108      1  0 12:18 ?        00:00:16 redis-server 127.0.0.1:6379
root       8422      1  0 14:27 ?        00:00:00 redis-sentinel 10.0.0.51:26379 [sentinel]     #表示哨兵启动
root       8426   8395  0 14:29 pts/0    00:00:00 grep --color=auto redis

验证主节点是否一致

redis-cli -h 10.0.0.51 -p 26379 Sentinel get-master-addr-by-name myredis  //连接53的哨兵告诉我集群的主节点
redis-cli -h 10.0.0.52 -p 26379 Sentinel get-master-addr-by-name myredis  
redis-cli -h 10.0.0.53 -p 26379 Sentinel get-master-addr-by-name myredis

6.5 模拟故障转移

  • 关闭主节点服务上的所有redis进程 pkill redis
  • 观察其他2个节点会不会发生选举
  • 查看配置文件里会不会自动更新
  • 查看新的主节点能不能写入
  • 查看从节点能否正常同步

模拟故障修复上线

# 启动原主节点  51节点
[root@redis ~]# redis-server /opt/redis_6379/conf/redis_6379.conf
# 启动原主节点哨兵   51节点
[root@redis ~]# redis-sentinel /opt/redis_26379/conf/redis_26379.conf

修改各节点权重命令

# 查询权重命令
CONFIG GET slave-priority

# 设置权重命令
CONFIG SET slave-priority 0

# 命令行提升权重不好使,如果要切换53为主节点,将51和52权重改为0
redis-cli -h 10.0.0.51 -p 6379 CONFIG SET slave-priority 0    
redis-cli -h 10.0.0.52 -p 6379 CONFIG SET slave-priority 0

# 集群重新选举
sentinel failover myredis

# 命令行重新选举
redis-cli -h 10.0.0.53 -p 26379 sentinel failover myredis     
#注意任意一台有哨兵的机器即可执行切换,但是要登录哨兵执行,端口号为26379

# 验证选举结果:
redis-cli -h 10.0.0.53 -p 26379 Sentinel get-master-addr-by-name myredis

# 更改权重后,要改回51和52权重,下次会公平选举
CONFIG SET slave-priority 100

哨兵管理命令(不常用)

# 连接sentinel管理端口
[root@db01 26380]# redis-cli -p 26380

# 检测状态,返回PONG
127.0.0.1:26380> PING
PONG

# 列出所有被监视的主服务器
127.0.0.1:26380> SENTINEL masters

# 列出所有被监视的从服务器
127.0.0.1:26380> SENTINEL slaves mymaster

# 返回给定名字的主服务器的IP地址和端口号
127.0.0.1:26380> SENTINEL get-master-addr-by-name mymaster
1) "127.0.0.1"
2) "6380"

# 重置所有名字和给定模式
127.0.0.1:26380> SENTINEL reset mymaster

# 当主服务器失效时,在不询问其他Sentinel意见的情况下,强制开始一次自动故障迁移。
127.0.0.1:26380> SENTINEL failover mymaster

第七章 Cluster分布式集群

7.1 redis集群介绍

  1. Redis集群是一个可以在多个Redis节点之间进行数据共享的设施(installation)。
  2. Redis集群不支持那些需要同时处理多个键的Redis命令,因为执行这些命令需要在多个Redis节点之间移动数据,并且在高负载的情况下,这些命令将降低Redis集群的性能,并导致不可预测的行为。
  3. Redis集群通过分区(partition)来提供一定程度的可用性(availability):即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求。
  4. Redis集群有将数据自动切分(split)到多个节点的能力。

7.2 集群与主从对比

  • 主从缺点:资源利用率低,有内存、并发、流量的瓶颈
  • 集群优点:负载均衡,内存取并集,高并发

7.3 集群特点

1、高性能
1)在多分片节点中,将16384个槽位,均匀分布到多个分片节点中,分片规则:哈希分片
2)存数据时,将key做crc16(key),然后和16384进行取模,得出槽位值(0-16384之间)
3)根据计算得出的槽位值,找到相对应的分片节点的主节点,存储到相应槽位上
4)如果客户端当时连接的节点不是将来要存储的分片节点,分片集群会将客户端连接切换至真正存储节点进行数据存储

2、高可用
在搭建集群时,会为每一个分片的主节点,对应一个从节点,实现slaveof功能,同时当主节点down,实现类似于sentinel的自动failover的功能。

7.4 Redis Cluster故障转移

  1. 在集群里面,节点会对其他节点进行下线检测。
  2. 当一个主节点下线时,集群里面的其他主节点负责对下线主节点进行故障移。
  3. 换句话说,集群的节点集成了下线检测和故障转移等类似 Sentinel 的功能。
  4. 因为 Sentinel 是一个独立运行的监控程序,而集群的下线检测和故障转移等功能是集成在节点里面的,它们的运行模式非常地不同,所以尽管这两者的功能很相似,但集群的实现没有重用 Sentinel 的代码。

7.5 Redis集群手动安装部署

  • 集群拓扑,主从节点错开放在不同服务器
    节点IP 10.0.0.51、10.0.0.52、10.0.0.53
    主节点端口 6380
    从节点端口 6381

db01创建命令

db01创建命令
pkill redis
mkdir -p /opt/redis_{6380,6381}/{conf,logs,pid}
mkdir -p /data/redis_{6380,6381}
cat >/opt/redis_6380/conf/redis_6380.conf<<EOF
bind 10.0.0.51
port 6380
daemonize yes
pidfile "/opt/redis_6380/pid/redis_6380.pid"
logfile "/opt/redis_6380/logs/redis_6380.log"
dbfilename "redis_6380.rdb"
dir "/data/redis_6380/"
cluster-enabled yes                             //开启集群模式
cluster-config-file nodes_6380.conf     //集群配置文件
cluster-node-timeout 15000               //当发生故障,15000毫秒后发生选举
EOF
cd /opt/
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 
rsync -avz /opt/redis_638* 10.0.0.52:/opt/
rsync -avz /opt/redis_638* 10.0.0.53:/opt/
redis-server /opt/redis_6380/conf/redis_6380.conf
redis-server /opt/redis_6381/conf/redis_6381.conf
ps -ef|grep redis

db02操作命令

pkill redis
find /opt/redis_638* -type f -name "*.conf"|xargs sed -i "/bind/s#51#52#g"
mkdir –p /data/redis_{6380,6381}
redis-server /opt/redis_6380/conf/redis_6380.conf
redis-server /opt/redis_6381/conf/redis_6381.conf
ps -ef|grep redis

db03操作命令

pkill redis
find /opt/redis_638* -type f -name "*.conf"|xargs sed -i "/bind/s#51#53#g"
mkdir –p /data/redis_{6380,6381}
redis-server /opt/redis_6380/conf/redis_6380.conf
redis-server /opt/redis_6381/conf/redis_6381.conf
ps -ef|grep redis

查看集群状态信息

redis-cli -h 10.0.0.51 -p 6380
CLUSTER nodes      //查看集群成员信息
CLUSTER info         //查看集群状态

7.6 发现节点

目前集群内的节点,还没有互相发现搭建redis集群我们第一步要做的就是让集群内的节点互相发现。
注意:Redis自动维护集群配置文件,不需要手动修改,防止节点重启时产生错乱

redis-cli -h 10.0.0.51-p 6380 CLUSTER MEET 10.0.0.51 6381
redis-cli -h 10.0.0.51 -p 6380 CLUSTER MEET 10.0.0.52 6380
redis-cli -h 10.0.0.51 -p 6380 CLUSTER MEET 10.0.0.52 6381
redis-cli -h 10.0.0.51 -p 6380 CLUSTER MEET 10.0.0.53 6380
redis-cli -h 10.0.0.51 -p 6380 CLUSTER MEET 10.0.0.53 6381
redis-cli -h 10.0.0.51 -p 6380 CLUSTER NODES
d03cb38d612802aead8f727b1726a3359c241818 10.0.0.51:6380 myself,master - 0 0 4 connected
67c8128df00b2fa304a41bafbadac25a654f196d 10.0.0.51:6381 master - 0 1562059947079 1 connected
a23ec7d444791a0b258ac454ef15cb4d6ab5abd2 10.0.0.53:6381 master - 0 1562059948087 5 connected
e57807d4d35daaaca05f4a9705e844eab15c7ce8 10.0.0.52:6381 master - 0 1562059949098 0 connected
aa9da67a594dfb357195f12ca4c44001804ee470 10.0.0.53:6380 master - 0 1562059945063 3 connected
5cb6895305520e6a0aa4198a6ea5f2c087530b41 10.0.0.52:6380 master - 0 1562059950108 2 connected

节点都发现完毕后我们再次查看集群配置文件,可以看到,发现到的节点的ID自动写入到了集群的配置文件里

7.7 槽的介绍

1、无论有几个集群,一共有16384个槽位,必须所有的槽位都分配完成,集群才能正常使用。
2、每个节点上的槽位顺序无所谓,重点是槽位的个数,每个槽位获取数据的概率都是一样的。
3、hash算法足够随机,足够平均。
4、集群配置文件不要手动修改

7.8 槽位的分配

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

分配槽位,必须在命令行执行

redis-cli -h 10.0.0.51 -p 6380 CLUSTER ADDSLOTS {0..5460}    //添加槽位
redis-cli -h 10.0.0.52 -p 6380 CLUSTER ADDSLOTS {5461..10922}   //10921不行就换10922
redis-cli -h 10.0.0.53 -p 6380 CLUSTER ADDSLOTS {10923..16383}
redis-cli -h db01 -p 6380 CLUSTER info     //查看集群状态

# 删除槽位
redis-cli -h 10.0.0.53 -p 6380 CLUSTER DELSLOTS 5460

7.9 手动部署复制关系

建议画一个做一个复制

CLUSTER NODES   //查询得到主库ID号
redis-cli -h 10.0.0.51 -p 6381 CLUSTER REPLICATE 主库ID号    //登录从库复制
redis-cli -h 10.0.0.52 -p 6381 CLUSTER REPLICATE 65baaa3b071f906c14da10452c349b0871317210
redis-cli -h 10.0.0.53 -p 6381 CLUSTER REPLICATE a1d47ccb19411eaf12d5af4b22cafbbefc8e2486

7.10 测试集群

  1. 尝试插入一条数据发现报错
redis-cli -h10.0.0.51 -p 6380
10.0.0.55:6380> set k1 v1
(error) MOVED 12706 10.0.0.53:6380         //不使用-c参数,提示需要手动到53节点登录操作
  1. 问题原因
    因为集群模式有ASK路由规则,加入-c参数后,会自动跳转到目标节点处理,并且最后由目标节点返回信息

  2. 解决方法:
    1、使用-c参数后,使用集群模式,自动跳转对应节点插入。
    redis-cli -c -h10.0.0.55 -p 6380

    2、使用脚本redis_shell.sh 登录,包含-c参数,自动跳转插入

  3. 再开一个会话,插入数据状态进行测试

for i in {1..5000};do redis-cli -c -h 10.0.0.51 -p 6380 set k_${i} v_${i} && echo "set k_${i} is ok";done
DBSIZE      //查看Key的数量
keys *        //查看key 是否随机   sort -n   排序
  1. 切换主从
    CLUSTER FAILOVER //切换主从,在从库执行,前提:确定主从库数据一致
    注意:生产场景,主从复制或者是主从切换要消耗非常大的资源,建议操作完一步,再执行下一步,否则会卡死

7.11 使用工具搭建部署Redis Cluster

  • 脚本位置:/opt/redis/src/redis-trib.rb
1) 安装依赖-只要在db01上操作
yum makecache fast
yum install rubygems -y
gem sources --remove https://rubygems.org/
gem sources -a http://mirrors.aliyun.com/rubygems/
gem update –system
gem install redis -v 3.3.5

2) 还原环境-所有节点都执行!!!
pkill redis
rm -rf /data/redis_6380/*
rm -rf /data/redis_6381/*
# 清空数据目录,集群各节点就会互相无法识别,因为识别信息再数据目录

3) 启动集群节点-所有节点都执行
redis-server /opt/redis_6380/conf/redis_6380.conf
redis-server /opt/redis_6381/conf/redis_6381.conf
ps -ef|grep redis

4) 使用工具搭建部署Redis
cd /opt/redis/src/
./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
# 主节点写在前,从节点写在后

5) 检查集群完整性
./redis-trib.rb check 10.0.0.51:6380
[OK] All nodes agree about slots configuration.    //正常
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.     //正常

6) 查看集群信息
[root@redis /opt/redis/src]# ./redis-trib.rb info 10.0.0.51:6380
10.0.0.51:6380 (1abba272...) -> 0 keys | 5461 slots | 1 slaves.      //多少个key,多少个槽,多少个slave
10.0.0.52:6380 (fe3ea1a8...) -> 0 keys | 5461 slots | 1 slaves.
10.0.0.53:6380 (7f86d32b...) -> 0 keys | 5462 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.

7) 检查集群负载是否合规
[root@redis /opt/redis/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.
*** No rebalancing needed! All nodes are within the 2.0% threshold.    //不需要平衡负载,所有的节点都在2%误差以内

添加删除节点

1、添加节点,在主节点上执行,将db02上的redis添加到7000端口所在主节点
[root@db01 ~]# redis-trib.rb add-node 172.16.1.52:7006 172.16.1.51:7000

# 添加完节点后,查看master状态,可以看到7006节点上并没有槽位
[root@db01 ~]# redis-cli -p 7000 cluster nodes |grep master
c74da3c4b8250425fa3626fd486364371188b1ee 127.0.0.1:7002 master - 0 1554637395372 3 connected 10923-16383
c1838701432c77418850dcab8fbc6edd8c15c697 172.16.1.51:7000 myself,master - 0 0 1 connected 0-5460
f4e3ce12a9aa1fe741634e74b88bb8b70b414f51 172.16.1.52:7006 master - 0 1554637395476 0 connected
80d141fdf0af0a90c98ab911812e810ac073940f 127.0.0.1:7001 master - 0 1554637394866 2 connected 5461-1092

2、删除节点:
redis-trib.rb del-node 10.0.0.51:6381 f4e3ce12a9aa1fe741634e74b88bb8b70b414f51
清除所有节点:CLUSTER RESET

redis运维脚本

[root@db01 ~]# cat redis_shell.sh 
#!/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

第八章 使用工具扩容节点

  1. 创建新节点-db05操作
mkdir -p /opt/redis_{6390,6391}/{conf,logs,pid}
mkdir -p /data/redis_{6390,6391}
cd /opt/
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_6390/conf/redis_6390.conf
redis-server /opt/redis_6391/conf/redis_6391.conf
ps -ef|grep redis
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
redis-cli -c -h db01 -p 6380 cluster nodes
  1. 使用工具扩容步骤
  • cd /opt/redis/src/
    ./redis-trib.rb reshard 10.0.0.51:6380

  • 第一次交互:每个节点保留多少个槽位
    How many slots do you want to move (from 1 to 16384)? 4096

  • 第二次交互:接收节点的ID是什么
    What is the receiving node ID? //6390的ID

  • 第三次交互:哪个节点需要导出
    Source node #1: all

  • 第四次交互:确认是否执行分配
    Do you want to proceed with the proposed reshard plan (yes/no)? yes

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

  2. 检查集群负载是否合规
    ./redis-trib.rb rebalance 10.0.0.51:6380

  3. 调整复制顺序
    redis-cli -h 10.0.0.53 -p 6381 CLUSTER REPLICATE ID
    redis-cli -h 10.0.0.51 -p 6391 CLUSTER REPLICATE ID

  4. 测试读写;另开一个会话,做扩容数据迁移,写和读不会中断,证明数据迁移不会影响正常读写

* 测试写入脚本
[root@db01 ~]# cat for.sh 
#!/bin/bash
for i in $(seq 1 5000)
do
    redis-cli -c -h db05 -p 6380 set k_${i} v_${i} && echo "set k_${i} is ok"
done

* 测试读脚本
[root@db03 ~]# cat du.sh 
#!/bin/bash 
for i in $(seq 1 5000)
do
    redis-cli -c -h db01 -p 6380 get k_${i}
    sleep 0.1 
done

第九章 使用工具收缩节点

  1. 使用工具收缩节点
    cd /opt/redis/src/
    ./redis-trib.rb reshard 10.0.0.51:6380

  2. 第一次交互: 要迁移多少个
    How many slots do you want to move (from 1 to 16384)? 1365

  3. 第二次交互: 输入第一个需要接收节点的ID //三个原节点
    What is the receiving node ID? db01的6380的ID

  4. 第三次交互: 输入需要导出的节点的ID
    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.
    Source node #1: db05的6390的ID
    Source node #2: done

  5. 第四次交互: 确认
    Do you want to proceed with the proposed reshard plan (yes/no)? yes

  6. 继续重复的操作,直到6390所有的槽位都分配给了其他主节点

  7. 确认集群状态是否正常,确认6390槽位是否都迁移走了

  8. 忘记以及下线节点
    ./redis-trib.rb del-node 10.0.0.55:6390 baf9585a780d9f6e731972613a94b6f3e6d3fb5e //删除节点
    ./redis-trib.rb del-node 10.0.0.55:6391 e54a79cca258eb76fb74fc12dafab5ebac26ed90

Redis集群常用命令

集群(cluster)
CLUSTER INFO 打印集群的信息
CLUSTER NODES 列出集群当前已知的所有节点(node),以及这些节点的相关信息。 
节点(node)
CLUSTER MEET <ip> <port> 将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。
CLUSTER FORGET <node_id> 从集群中移除 node_id 指定的节点。
CLUSTER REPLICATE <node_id> 将当前节点设置为 node_id 指定的节点的从节点。
CLUSTER SAVECONFIG 将节点的配置文件保存到硬盘里面。 
槽(slot)
CLUSTER ADDSLOTS <slot> [slot ...] 将一个或多个槽(slot)指派(assign)给当前节点。
CLUSTER DELSLOTS <slot> [slot ...] 移除一个或多个槽对当前节点的指派。
CLUSTER FLUSHSLOTS 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
CLUSTER SETSLOT <slot> NODE <node_id> 将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。
CLUSTER SETSLOT <slot> MIGRATING <node_id> 将本节点的槽 slot 迁移到 node_id 指定的节点中。
CLUSTER SETSLOT <slot> IMPORTING <node_id> 从 node_id 指定的节点中导入槽 slot 到本节点。
CLUSTER SETSLOT <slot> STABLE 取消对槽 slot 的导入(import)或者迁移(migrate)。 
键 (key)
CLUSTER KEYSLOT <key> 计算键 key 应该被放置在哪个槽上。
CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的键值对数量。CLUSTER GETKEYSINSLOT <slot> <count> 返回 count 个 slot 槽中的键。

第十章 Redis运维工具

10.1 数据导入导出工具

刚切换到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 

# 创建配置文件
[root@db01 ~]# cat redis_6379_to_6380.conf    
[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

# 生成测试数据
[root@db01 ~]# cat input_key.sh 
#!/bin/bash
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

# 执行导入命令
[root@db01 ~]# redis-migrate-tool -c redis_6379_to_6380.conf 

# 数据校验
[root@db01 ~]# redis-migrate-tool -c redis_6379_to_6380.conf -C redis_check

10.2 分析键值大小

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

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

2.生成测试数据:
redis-cli -h db01 -p 6379 set txt $(cat txt.txt)

3.执行bgsave生成rdb文件
redis-cli -h db01 -p 6379 BGSAVE

4.使用工具分析:
cd /data/redis_6379/
rdb -c memory redis_6379.rdb -f redis_6379.rdb.csv

5.过滤分析
awk -F"," '{print $4,$3}' redis_6379.rdb.csv |sort -r

6.将结果整理汇报给领导,询问开发这个key是否可以删除

10.3 监控过期键

需求背景,因为开发重复提交,导致电商网站优惠卷过期时间失效
问题分析:如果一个键已经设置了过期时间,这时候在set这个键,过期时间就会取消

  • 解决思路:如何在不影响机器性能的前提下批量获取需要监控键过期时间
    1.Keys * 查出来匹配的键名。然后循环读取ttl时间
    2.scan * 范围查询键名。然后循环读取ttl时间
    Keys 重操作,会影响服务器性能,除非是不提供服务的从节点
    Scan 负担小,但是需要去多次才能取完,需要写脚本

脚本内容

cat 01get_key.sh 
#!/bin/bash
key_num=0
> key_name.log
for line in $(cat key_list.txt)
do
    while true
    do
        scan_num=$(redis-cli -h 192.168.47.75 -p 6380 SCAN ${key_num} match ${line}\* count 1000|awk 'NR==1{print $0}')
        key_name=$(redis-cli -h 192.168.47.75 -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集群故障修复案例

背景:槽位迁移过程中中断了
现象:使用check命令和reshard命令不好使了,使用集群节点命令查看发现槽位状态不对

解决办法:
一、尝试使用fix命令

cd /opt/redis/src/
./redis-trib.rb fix 10.0.0.55:6380     //集群任意一个节点执行

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

# 检查集群负载是否合规
./redis-trib.rb rebalance 10.0.0.55:6380

二、如果fix命令解决不了,手动解决

  1. 找到有问题的槽
    例:登录10.0.0.55:6390>CLUSTER nodes
    发现存在6442槽在55节点
    登录10.0.0.52:6380>CLUSTER nodes
    发现6442槽位存在52节点,在不同节点发现相同槽位,信息不一致

  2. 删除有问题的槽,会丢失这个槽的数据
    登录10.0.0.55:6390>CLUSTER DELSLOTS 6442
    登录10.0.0.52:6380>CLUSTER DELSLOTS 6442

  3. 重新添加新槽位
    10.0.0.55:6390>CLUSTER ADDSLOTS 6442
    CLUSTER nodes
    在不同节点登录发现6442槽位在同一节点

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容