关于redis:删库到跑路还得看这篇Redis数据库持久化与企业容灾备份恢复实战指南

50次阅读

共计 29926 个字符,预计需要花费 75 分钟才能阅读完成。

本章目录

0x00 数据长久化

  • 1.RDB 形式
  • 2.AOF 形式
  • 如何抉择 RDB OR AOF?

0x01 备份容灾
一、备份

  • 1. 手动备份 redis 数据库
  • 2. 迁徙 Redis 指定 db- 数据库
  • 3.Redis 集群数据备份与迁徙

二、复原

  • 1. 零碎 Redis 用户被删除后配置数据恢复流程
  • 2.Kubernetes 中单实例异样数据迁徙复原实际
  • 3. 当 Redis 集群中呈现从节点 slave,fail,noaddr 问题进行解决复原流程。

前置常识学习补充
Redis 数据库根底入门介绍与装置 – https://blog.weiyigeek.top/20…

Redis 数据库根底数据类型介绍与应用 – https://blog.weiyigeek.top/20…

Redis 根底运维之原理介绍和主从配置 – https://blog.weiyigeek.top/20…

Redis 根底运维之哨兵和集群装置配置 – https://blog.weiyigeek.top/20…

Redis 根底运维之在 K8S 中的装置与配置 – https://blog.weiyigeek.top/20…

Redis 数据库性能测试及优化配置 – https://blog.weiyigeek.top/20…

Redis 数据库客户端操作实际及入坑出坑 – https://blog.weiyigeek.top/20…


0x00 数据长久化

形容: Redis 是将数据存储在内存之中所以其读写效率十分高,然而往往事物都不是那么美妙,当因为某些不可抗力导致机器宕机、redis 服务进行此时您在内存中的数据将齐全失落;

所以为了使 Redis 在异样重启后仍能保证数据不失落, 咱们就须要对其进行设置长久化存储,使其将内存的数据通过某种形式存入磁盘中,当 Redis 服务端重启后便会从该磁盘中进行读取数据进而复原 Redis 中的数据, 所以 Redis 数据长久化是容灾复原必备条件;

Redis 反对两种长久化形式:

  • (1) RDB 长久化(默认反对): 该机制是指在指定的工夫距离内将内存中数据集写入到磁盘;
  • (2) AOF 长久化: 该机制将以日志的模式记录服务器所解决的每一个写操作,同时在 Redis 服务器启动之初会读取该文件来从新构建数据库,以保障启动后数据库中的数据残缺;
  • (3) 无长久化: 将 Redis 作为一个长期缓存,并将数据寄存到 memcached 之中;

Tips: 为保证数据安全性,咱们能够设置 Redis 同时应用 RDB 和 AOF 长久化形式,来保障重启后 Redis 服务器中的数据残缺;

1.RDB 形式

形容: Redis 将某一时刻的快照(备份的数据库数据)保留成一种称为 RDB 格局的文件中,这种格局是通过压缩的二进制文件,数据库的保留和复原文件如下图所示。

<br/>

保留 RDB 数据的两种形式:

  • 1、save 命令:save 命令会阻塞 redis 服务器的过程,直到 RDB 文件创建完,在该期间 redis 不能解决任何的命令申请,这就是 save 命令最大的缺点。
  • 2、bgsave 命令: 与 save 命令不同的是 bgsave 在生成 RDB 文件时,会派生出一个子过程,子过程负责创立 RDB 文件,在此期间,主过程和子过程是同时存在的,因而不会阻塞 redis 服务器过程。(举荐形式)

阐明: 可用 lastsave 命令 查看生成 RDB 文件是否胜利

<br/>

劣势

  • 1) 采纳子线程创立 RDB 文件(dump.rdb),不会对 redis 服务器性能造成大的影响(性能最大化);
  • 2) 快照生成的 RDB 文件是一种压缩的二进制文件,能够不便的在网络中传输和保留。通过 RDB 文件能够不便的将 redis 数据恢复到某一历史时刻,能够进步数据安全性,防止宕机等意外对数据的影响。
  • 3) 适宜大规模的数据恢复, RDB 的启动复原效率高。
  • 4) 如果业务对数据完整性和一致性要求不高,RDB 是很好的抉择。

<br/>

劣势

  • 1) 在 redis 文件在工夫点 A 生成,之后产生了新数据,还未达到另一次生成 RDB 文件的条件,redis 服务器解体了,那么在工夫点 A 之后的数据会失落掉,数据一致性不是完满的好,如果能够承受这部分失落的数据,能够用生成 RDB 的形式;
  • 2) 快照长久化办法通过调用 fork()办法创立子线程。当 redis 内存的数据量比拟大时,创立子线程和生成 RDB 文件会占用大量的系统资源和解决工夫,对 redis 解决失常的客户端申请造成较大影响。
  • 3) 数据的完整性和一致性不高,因为 RDB 可能在最初一次备份时宕机了。
  • 4) 备份时占用内存,因为 Redis 在备份时会独立创立一个子过程,将数据写入到一个临时文件(此时内存中的数据是原来的两倍哦),最初再将临时文件替换之前的备份文件。所以 Redis 的长久化和数据的复原要抉择在夜深人静的时候执行是比拟正当的。

<br/>

Q: 通过 RDB 文件复原数据?

答: 将 dump.rdb 文件拷贝到 redis 的装置目录的 bin 目录下,重启 redis 服务即可。在理论开发中,个别会思考到物理机硬盘损坏状况,抉择备份 dump.rdb。

<br/>

配置阐明:

# Redis 配置文件
cat > redis.conf <<'EOF'
# 明码认证
requirepass WeiyiGeek.top

# 长久化文件保留门路目录
dir /data

# RDB 外围规定之触发保留条件
阐明:save < 指定工夫距离 > < 执行指定次数更新操作 >,满足条件就将内存中的数据同步到硬盘中。官网出厂配置默认是 900 秒内有 1 个更改,300 秒内有 10 个更改以及 60 秒内有 10000 个更改,则将内存中的数据快照写入磁盘。save 900 1    # 900 秒(15 分钟)至多有 1 条 key 变动,其余同理
save 300 10
save 60 10000 #每 60 形容至多有 1000 个 key 发生变化时候则 dump 内存快照

# RDB 生成的文件名称
dbfilename dump.rdb
# 是否压缩(ZF 压缩形式),会占用局部 cpu 资源,默认 yes(倡议开启)
rdbcompression yes
# rdb 文件校验
rdbchecksum yes

# 备份过程出错时,主过程进行承受写入操作,默认 yes
stop-writes-on-bgsave-error yes

# RDB 主动触发策略是否启用,默认为 yes
rdb-save-incremental-fsync yes
EOF

<br/>

理论案例:

# 1. 如下面配置所示,按配置状况触发
# 比方在 Redis 服务终止的时候执行

# 2. 手动保留数据连贯 redis 后应用命令 save、bgsave 触发
127.0.0.1:6379> SAVE    #save 会阻塞 redis 服务器直到实现长久化
OK
127.0.0.1:6379> BGSAVE  #bgsave 不会阻塞 redis 服务器(它会 fork 一个子过程,由子过程进行长久化。)
OK
127.0.0.1:6379> quit


# 3.redis aof 长久化文件完整性检查与异样修改
/usr/local/redis/bin/redis-check-aof --fix  appendonly.aof
  # The AOF appears to start with an RDB preamble.
  # Checking the RDB preamble to start:
  # [offset 0] Checking RDB file --fix
  # [offset 27] AUX FIELD redis-ver = '5.0.10'
  # [offset 41] AUX FIELD redis-bits = '64'
  # [offset 53] AUX FIELD ctime = '1631088747'
  # [offset 68] AUX FIELD used-mem = '31554944'
  # [offset 84] AUX FIELD aof-preamble = '1'
  # [offset 86] Selecting DB ID 0
  # [offset 13350761] Checksum OK
  # [offset 13350761] \o/ RDB looks OK! \o/
  # [info] 157070 keys read
  # [info] 0 expires
  # [info] 0 already expired
  # RDB preamble is OK, proceeding with AOF tail...
  # 0x         27b66b0: Expected prefix '*', got: 'R'
  # AOF analyzed: size=116993914, ok_up_to=41641648, ok_up_to_line=1816854, diff=75352266
  # This will shrink the AOF from 116993914 bytes, with 75352266 bytes, to 41641648 bytes
  # Continue? [y/N]: y
  # Successfully truncated AOF


# 4. 再利用 rdb 数据文件进行复原数据
root@dfbf8c0c0625:/data# ls
dump.rdb
# 将容器中的 dump.rdb 拷贝一份到宿主机中的 `/var/lib/redis/` 中,并须要在 redis.conf 中配置 `dir "/var/lib/redis/"`;
docker cp dfbf8c0c0625:/data/dump.rdb /var/lib/redis/dump.rdb

RDB 文件复原数据流程

1、先备份一份 dump.rdb 为 dump_bak.rdb(模仿线上)2、flushall 清空数据(模仿数据失落, 须要留神 flushall 也会触发 rbd 长久化)3、将 dump_bak.rdb 替换为 dump.rdb
4、重启 redis 服务,复原数据

2.AOF 形式

形容: AOF 是 redis 对将所有的写命令保留到一个 aof 文件中,依据这些写命令实现数据的长久化和数据恢复。

<br/>

AOF 文件生成机制

答: 生成过程包含三个步骤, 即 命令追加、文件写入、文件同步
redis 关上 AOF 长久化性能之后,redis 在执行完一个写命令后,把执行的命令首先追加到 redis 外部的 aof_buf 缓冲区膜开端,此时缓冲区的记录还没有写到 appendonly.aof 文件中。而后,缓冲区的写命令会被写入到 AOF 文件,这一过程是文件写入过程。对于操作系统来说,调用 write 函数并不会立即将数据写入到硬盘,为了将数据真正写入硬盘,还须要调用 fsync 函数,调用 fsync 函数即是文件同步的过程,只有通过了文件的同步过程,写命令才真正的被保留到了 AOF 文件中。选项 appendfsync 就是配置同步的频率的。

<br/>

AOF 文件重写

  • 1、redis 一直的将写命令保留到 AOF 文件中,导致 AOF 文件越来越大,当 AOF 文件体积过大时,数据恢复的工夫也是十分长的,因而,redis 提供了重写或者说压缩 AOF 文件的性能。
    比方 对 key1 初始值是 0,调用 incr 命,100 次,key1 的值变为 100,那么其实间接一句 set key1 100 就能够顶之前的 100 局调用,AOF 重写性能就是干这个事件的。重写时,能够调用 BGREWRITEAOF 命令重写 AOF 文件,与新建子线程 bgsave 命令的工作原理类似。也能够通过配置文件配置什么条件下对 AOF 文件重写。
  • 2、重写的原理:Redis 会 fork 出一条新过程,读取内存中的数据,并从新写到一个临时文件中。并没有读取旧文件(太大了)。最初替换旧的 aof 文件
  • 3、重写触发机制: 当 AOF 文件大小是上次 rewrite 后大小的一倍且文件大于 64M 时触发,这里的“一倍”和“64M”能够通过配置文件批改

<br/>

劣势

  • 1) 该机制能够带来更高的数据安全性,即数据长久化; 惯例三种同步策略即每秒同步 ( 异步实现效率高 )、每批改同步( 同步插入批改删除操作效率最低 ) 和不同步;
  • 2) 因为该机制对日志文件的写入操作采纳的是 append 模式,即便过程中呈现宕机也不会毁坏日志文件中曾经存在的内容, 如果数据不残缺在 Redis 下次启动之前, 通过 redis-check-aof 解决数据一致性问题;
  • 3) 如果日志文件体积过大能够启动 rewrite 机制,即 redis 以 append 模式一直的将批改数据写到老的磁盘文件中,同时创立新文件记录期间有哪些批改命令执行,此项极大的保证数据的安全性;
  • 4) AOF 文件可读性强, 其蕴含一个格局清晰、易于了解的日志文件用于记录所有的批改操作(可通过此文件实现数据的重构
  • 5) 数据的完整性和一致性更高

<br/>

劣势

  • 1) AOF 文件比 RDB 文件较大, 对于雷同数量的数据集而言;
  • 2) redis 负载较高时,RDB 文件比 AOF 文件具备更好的性能;
  • 3) RDB 应用快照的形式长久化整个 redis 数据,而 aof 只是追加写命令,因而从实践上来说,RDB 比 AOF 形式更加强壮,另外,官网文档也指出,在某些状况下,AOF 确实也存在一些 bug,比方应用阻塞命令时,这些 bug 的场景 RDB 是不存在的。
  • 4) 因为 AOF 记录的内容多,文件会越来越大,数据恢复也会越来越慢。
  • 5) 依据同步策略的不同,AOF 在运行效率上往往会慢于 RDB, 总的来说每秒同步策略的效率还是比拟高的

<br/>

Q: 如何触发 AOF 快照?

答: 依据配置文件触发,能够是每次执行触发,能够是每秒触发,能够不同步。

<br/>

Q: 如何依据 AOF 文件复原数据?

答: 失常状况下,将 appendonly.aof 文件拷贝到 redis 的装置目录的 bin 目录下,重启 redis 服务即可。但在理论开发中,可能因为某些起因导致 appendonly.aof 文件格式异样,从而导致数据还原失败,能够通过命令 redis-check-aof --fix appendonly.aof 进行修复。

<br/>

配置阐明:

cat > redis.conf <<'EOF'
# 长久化数据存储
dir "/data"

# 是否开启 AOF 默认为否
appendonly yes

# AOF 文件名字及门路,若 RDB 门路已设置这里可不设置
appendfilename "appendonly.aof"

# AOF 的 3 种模式,no(应用零碎缓存解决,快)、always(记录全副操作,慢但比拟平安)、everysec(每秒同步,折中计划,默认应用)appendfsync everysec

# 重写期间是否同步数据,默认为 no
no-appendfsync-on-rewrite no

# 配置重写触发机制: 确保 AOF 日志文件不会过大,放弃跟 redis 内存数据量统一。# 配置阐明: 当 AOF 文件大小是上次 rewrite 后大小的一倍且文件大于 64M 时触发(依据理论环境进行配置)
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 256mb

# AOF 重写策略是否启用,默认为 yes
aof-rewrite-incremental-fsync yes

# 加载 AOF 时如果报错则会持续但写入 log,如果为 no 则不会持续
aof-load-truncated yes

# Redis5.0 有的性能 AOF 重写及复原能够应用 RDB 文件及 AOF 文件,速度更快,默认 yes
aof-use-rdb-preamble yes
EOF

Q: 如何通过 AOF 文件复原数据流程?

1、执行 flushall,模仿数据失落
2、重启 redis 服务,复原数据
3、批改 appendonly.aof,模仿文件异样
4、重启 Redis 服务失败,这同时也阐明了 RDB 和 AOF 能够同时存在,且优先加载 AOF 文件。5、应用 redis-check-aof 校验 appendonly.aof 文件。#  针对 Redis aof 长久化文件进行完整性检测并进行修复
/usr/local/redis/bin/redis-check-aof --fix appendonly.aof
  # The AOF appears to start with an RDB preamble.
  # Checking the RDB preamble to start:
  # [offset 0] Checking RDB file appendonly.aof
  # [offset 27] AUX FIELD redis-ver = '5.0.10'
  # [offset 41] AUX FIELD redis-bits = '64'
  # [offset 53] AUX FIELD ctime = '1631088747'
  # [offset 68] AUX FIELD used-mem = '31554944'
  # [offset 84] AUX FIELD aof-preamble = '1'
  # [offset 86] Selecting DB ID 0
  # [offset 13350761] Checksum OK
  # [offset 13350761] \o/ RDB looks OK! \o/
  # [info] 157070 keys read
  # [info] 0 expires
  # [info] 0 already expired
  # RDB preamble is OK, proceeding with AOF tail...
  # 0x         27b66b0: Expected prefix '*', got: 'R'
  # AOF analyzed: size=116993914, ok_up_to=41641648, ok_up_to_line=1816854, diff=75352266
  # AOF is not valid. Use the option to try fixing it.

6、重启 Redis 服务后失常。# 利用源实例生成的 aof 文件数据进行复原到其它主机中。redis-cli -h 17.20.0.2 -a password --pipe < applendonly.aof

留神: 当你应用 flushall 清空数据的时候,重启 redis 服务发现数据没复原,是因为 FLUSHALL 命令也被写入 AOF 文件中,会导致数据恢复失败,所只须要删除 aof 文件中的 flushall 就行了

Tips : 在数据库复原时把 aof(append only file) 从中对 redis 数据库操作的命令,增删改操作的命令,执行了一遍即可。

理论案例:
形容: 用于异步执行一个 AOF(AppendOnly File) 文件重写操作, 重写会创立一个以后 AOF 文件的体积优化版本,因为 AOF 为记录每次的操作会导致理论记录繁杂、使得文件过大,所以须要做重写操作。

重写形式分为以下两种:

# (1) AOF 主动重写: 按配置文件条件主动触发重写
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 256mb

# (2) AOF 手动重写: 应用 redis-cli 连贯到 server 端执行 bgrewriteaof 进行手动重写。# 留神: 从 Redis 2.4 开始,AOF 重写由 Redis 自行触发,BGREWRITEAOF 仅仅用于手动触发重写操作。127.0.0.1:6379> BGREWRITEAOF 
# 即便 Bgrewriteaof 执行失败,也不会有任何数据失落,因为旧的 AOF 文件在 Bgrewriteaof 胜利之前不会被批改。Background append only file rewriting started

如何抉择 RDB OR AOF?

形容: 在理论生产环境中不要仅应用 RDB(加载快、不保障数据完整性)或仅应用 AOF(加载慢、数据完整性保障),所以举荐综合应用 AOF 和 RDB 两种长久化机制进行数据备份。

  • AOF 机制保证数据不失落,并且文件有肯定的可读性即能够选择性复原一部分数据,所以作为数据恢复的第一抉择;
  • RDB 机制在 AOF 文件都失落或损坏不可用的时候,能够利用其冷备文件来进行疾速的数据恢复;

<br/>

AOF 和 RDB 同时工作特点:

  • 当 rdb 进行 snapshotting 时, redis 便不会再执行 AOF rewrite, 反之则一样。
  • 当 rdb 进行 snapshotting 时, 其它用户也在执行 BGREWRITEAOF 命令, 后果是只有等 RDB 快照生成之后,才会执行 AOF rewrite;
  • 当同时领有 rdb 快照文件和 AOF 日志文件时, Redis 重启时会优先应用 AOF 日志进行复原,。
  • 数据恢复齐全依赖于磁盘长久化,如果 rdb 和 aof 上都没有数据,数据就无奈复原了。

<br/>

Tips : 重点再记录、为保证数据容灾倡议启用 rdb 与 aof 长久化机制,前者保障数据备份而后者保证数据的完整性。
Tips : 重点再记录、当在服务器中同时启用 rdb 与 aof 长久化机制时,在 redis 服务启动时优先加载 AOF 文件(其数据的完整性)。

<br/>

合并两个不同实例的数据
形容: 咱们能够利用如下形式进行集群多个主节点长久化数据的合并。

(1) AOF 备份合并: 咱们说过它实际上是一些列 Redis 的命令文本。
例如,假如有两台 Redis(6379, 6479),它们的 AOF 文件名别离为(6379.aof, 6479.aof),当初要将 6379 的数据合并到 6479.aof

# 首先
cp 6379.aof 6379.aof.bak, cp 6479.aof 6479.aof.bak

# 合并
cat 6379.aof 6479.aof > new.aof

# 查看 & 修复
/usr/local/redis/bin/redis-check-aof --fix appendonly.aof

(2) RDB 备份合并: 留神以下办法可能因为服务端版本不同而有些许差别。
RDB 格局如下:头 5 个字节是字符 REDIS, 之后 4 个字节代表版本号,阿里的版本别离是 00 00 00 06, 之后 2 个字节 FE 00,FE 是标识 00 是数据库,还好咱们只有一个库, 最初的结尾 9 个字节 , FF 加上 8 个字节的 CRC64 校验码(切实没空弄,起初偷了一个懒)

# 1. 线上服务应用的阿里云的集群版本 redis 服务,数据量 1 千万,rdb 文件 4GB,8 个 rdb 文件,每个 500MB。#文件 1 大小 566346503,截取尾部的 9 个字节
dd bs=1 if=src_1.rdb of=1.rdb count=566346494
#文件 2 大小 570214520,跳过头部的 11 个字节,再截取尾部的 9 个字节
dd bs=1 if=src_2.rdb of=2.rdb skip=11 count=570214500
...
#文件 8 大小 569253061,跳过头部的 11 个字节,再截取尾部的 8 个字节,保留 FF。dd bs=1 if=src_8.rdb of=8.rdb skip=11 count=569253042

# 2. 合并文件(失去备份文件 dump.rdb)
cat 1.rdb > dump.rdb
cat 2.rdb >> dump.rdb
...
cat 8.rdb >> dump.rdb

# 3. 查看备份文件(应该会提醒没有 crc 校验)
redis-check-rdb dump.rdb 

# 4. 批改配置文件, 因为数据库备份文件外面不蕴含 crc64 的校验码,配置文件中敞开选项。rdbchecksum no

Tips : 数据恢复到此结束,此办法只适宜用于长期复原和导出数据,数据完整性不敢保障。

参考地址: https://github.com/sripathikr…

其它工具:

  • https://github.com/leonchen83… | 一个能够解析, 过滤, 宰割, 合并 rdb 离线内存剖析的工具. 也能够在两个 redis 之前同步数据并容许用户自定义同步服务来把 redis 数据同步到其余中央.

0x01 备份容灾

一、备份

1. 手动备份 redis 数据库

#!/bin/bash
# 形式 1. 通过 redis-cli 内置命令将内存中的数据存储到 rdb 文件中
echo "auth 123456\nping\nsave\n" | redis-cli -h 127.0.0.1 -p 6379
echo "auth 123456\nping\nbgsave\n" | redis-cli -h 127.0.0.1 -p 6379

# 形式 2. 将近程主机 Redis-Server 中存储的数据保留到本地 /tmp/backup/ 目录中。redis-cli -h 127.0.0.1 -p 6379 --rdb /tmp/backup/app-6379.rdb

# 形式 3. 定时执行拷贝 rdb 与 aof 文件进行备份。# 例如: 每天 0 点执行一次 0 0 * * * sh /tmp/redisBackup.sh
current_date=$(date +%Y%m%d-%H%M%S)
BACKUPDIR="/backup/redis"
RDBFILE="/data/dump.rdb"
AOFFILE="/data/appendonly.aof"
# del_date=$(date -d -1day +%Y%m%d)
if [! -d ${BACKUPDIR} ];then
  mkdir -vp ${BACKUPDIR}
fi

if [! -f ${RDBFILE} ];then
  cp -a ${RDBFILE} ${BACKUPDIR}/${current_date}-dump.rdb
fi

if [! -f ${AOFFILE} ];then
  cp -a ${AOFFILE} ${BACKUPDIR}/${current_date}-appendonly.aof
fi

# 删除七天前的备份
find ${BACKUPDIR} -type f -mtime +7 >> delete.log
find ${BACKUPDIR} -type f -mtime +7 -exec rm -rf {} \;

2. 迁徙 Redis 指定 db- 数据库

形式 1. 同主机 db 迁徙到另外一个 dbn 中

$ redis-cli -h localhost -a weiyigeek.top -n 0 keys "*" | while read key
do
  redis-cli -h localhost -a weiyigeek.top -n 0 --raw dump $key | perl -pe 'chomp if eof' | redis-cli -h localhost -a weiyigeek.top -n 12 -x restore $key 0
done 

<br/>

形式 2. 跨主机迁徙 db

# redis 把 db2 的数据迁徙到 db14 里 (留神: 某些格局的数据不能齐全已此种形式进行迁徙)
# 需要剖析:
'''1、建设两个 redis 连贯
   2、获取所有的 keys()3、获取 keys 的类型:string hash'''

import redis
src_redis = redis.Redis(host='211.149.218.16',
                password='123456',
                port=6379,
                db=2)
target_redis = redis.Redis(host='211.149.218.16',
                password='123456',
                port=6379,
                db=14)
                
for key in src_redis.keys(): # redis 获取的数据都是 bytes 类型的,所以 key 的类型是 bytes 类型
    if src_redis.type(key) == b'string':# 也能够用 decode() 把 key 转换成 string,这样等号左边就不须要加 b
        v = src_redis.get(key)  #先获取原来的数据
        target_redis.set(key,v) #set 到新的数据库里
    else:
        all_hash_data = src_redis.hgetall(key) # 获取 hash 类型外面所有的数据,获取进去的数据是字典格局的  然而有 b,须要转换
        for k,v in all_hash_data.items():# 因为获取到字典格局的 hash 类型的原数据有 b,所以须要用 for 循环来进行转换后从新赋值给新的数据库
            target_redis.hset(key,k,v) # key 是里面的,k 是外面的 key,v 是 k 对应的 value

3.Redis 集群数据备份与迁徙

形容: 当咱们须要备份或迁徙 Redis 集群时能够采纳以下计划。

# (1) 备份集群数据到本地目录中(已 rdb 格式文件存储)。redis-cli -a weiyigeek --cluster backup 172.16.243.97:6379 .
  # >>> Node 172.16.243.97:6379 -> Saving RDB...
  # SYNC sent to master, writing 178 bytes to './redis-node-172.16.243.97-6379-d97cb5b15b7130ca0bd5322758e0c2dce061fd7b.rdb'
  # Transfer finished with success.
  # >>> Node 172.16.183.95:6379 -> Saving RDB...
  # SYNC sent to master, writing 178 bytes to './redis-node-172.16.183.95-6379-94b8d3748dc47053454e657da8d6bb90e0081f2c.rdb'
  # Transfer finished with success.
  # >>> Node 172.16.24.214:6379 -> Saving RDB...
  # SYNC sent to master, writing 178 bytes to './redis-node-172.16.24.214-6379-2674f21a88a9573f51ec46f9dc248ad4a5c5974d.rdb'
  # Transfer finished with success.

# (2) 把 192.168.1.187:6379 上的数据导入到 192.168.75.187:6379 这个节点所在的集群,如有明码将询问
redis-cli -a weiyigeek --cluster import 192.168.75.187:6379 --cluster-from 192.168.1.187:6379 --cluster-from-askpass --cluster-copy

# (3) 迁徙后利用 dbsize 命令查看数据是否正确

Tips: 第三方 redis 集群数据迁徙工具我的项目参考(https://github.com/alibaba/Re…)

二、复原

1. 零碎 Redis 用户被删除后配置数据恢复流程

形容: 在零碎删除了配置文件后以及用户账号后复原办法流程,理论环境中倡议利用 rdb 文件进行重新部署。

  • Step1.Redis 账户数据恢复首先确定零碎中是否还有 redis 用户。(如果拷贝过去的零碎也装置了 redis,那么必定是会有 redis 账户)
  • Step2. 如果发现有 redis 用户以下步骤能够跳过,否则进行手动增加。

    echo "redis:x:996:994:Redis Database Server:/var/lib/redis:/sbin/nologin" >> /etc/passwd
    echo "redis:!!:17416::::::" >> /etc/shadow
    echo "redis:x:994:" >> /etc/group
    echo "redis:!::" >> /etc/gshadow
  • Step3.Redis 配置文件复原, Redis 的配置文件复原绝对简略一些,官网提供了 CONFIG REWRITE 命令重写 redis.conf 配置文件。

    redis-cli
    > CONFIG REWRITE
    OK
  • Step4. 批改配置文件权限

    touch /etc/redis.conf
    chown redis:redis /etc/redis.conf

2.Kubernetes 中单实例异样数据迁徙复原实际

计划 1. 利用其余 kubernetes 集群进行恢复原 k8s 集群的 redis 数据。

#!/bin/bash
# author: WeiyiGeek
# usage: ./K8SRedisRecovery.sh [aof|rdb] redis 原长久化目录
BACKUP_TYPE=$1
BACKUP_DIR=$2
DATA_DIR="$(pwd)/data"
echo "开始工夫: $(date +%s)"

# 1. 判断备份文件以及长久化文件是否存在
if [! -d ${BACKUP_DIR} ];then echo -e "[Error] - Not Found ${BACKUP_DIR} Dirctory!"; return -1; fi
if [! -d ${DATA_DIR} ];then mkdir -vp ${DATA_DIR};else rm -rf "${DATA_DIR}/*"; fi

# 2.redis 配置与 k8s 部署复原 redis 清单
# tee redis.conf <<'EOF'
# bind 0.0.0.0
# port 6379
# daemonize no
# supervised no
# protected-mode no
# requirepass "weiyigeek"
# dir "/data"
# pidfile "/var/run/redis.pid"
# logfile "/var/log/redis.log"
# loglevel verbose
# maxclients 10000
# timeout 300
# tcp-keepalive 60
# maxmemory-policy volatile-lru
# slowlog-max-len 128
# lua-time-limit 5000
# save 300 10
# save 60 10000
# dbfilename "dump.rdb"
# rdbcompression yes
# rdb-save-incremental-fsync yes
# # appendonly yes
# appendfilename "appendonly.aof"
# appendfsync everysec
# # rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
# rename-command FLUSHDB WeiyiGeekFLUSHDB
# rename-command FLUSHALL WeiyiGeekFLUSHALL
# rename-command EVAL WeiyiGeekEVAL
# rename-command DEBUG WeiyiGeekDEBUG
# rename-command SHUTDOWN WeiyiGeekSHUTDOWN
# EOF

tee redisrecovery.yaml <<'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
  name: redis-recovery
  namespace: database
data:
  redis.conf: |+
    bind 0.0.0.0
    port 6379
    daemonize no
    supervised no
    protected-mode no
    requirepass "weiyigeek"
    dir "/data"
    pidfile "/var/run/redis.pid"
    logfile "/var/log/redis.log"
    loglevel verbose
    maxclients 10000
    timeout 300
    tcp-keepalive 60
    maxmemory-policy volatile-lru
    slowlog-max-len 128
    lua-time-limit 5000
    save 300 10
    save 60 10000
    dbfilename "dump.rdb"
    rdbcompression yes
    rdb-save-incremental-fsync yes
    # appendonly yes
    appendfilename "appendonly.aof"
    appendfsync everysec
    # rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
    rename-command FLUSHDB WeiyiGeekFLUSHDB
    rename-command FLUSHALL WeiyiGeekFLUSHALL
    rename-command EVAL WeiyiGeekEVAL
    rename-command DEBUG WeiyiGeekDEBUG
    rename-command SHUTDOWN WeiyiGeekSHUTDOWN
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-recovery
  namespace: database
spec:
  serviceName: redisrecovery
  replicas: 1
  selector:
    matchLabels:
      app: redis-recovery
  template:
    metadata:
      labels:
        app: redis-recovery
    spec:
      containers:
      - name: redis
        image: redis:6.2.5-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 6379
          name: server
        command: ["redis-server", "/conf/redis.conf"]
        volumeMounts:
        # 从 configmap 获取的配置文件,挂载到指定文件中
        - name: conf
          mountPath: /conf/redis.conf
          subPath: redis.conf
        - name: data
          mountPath: /data
        # 时区设置
        - name: timezone
          mountPath: /etc/localtime
      volumes:
      - name: conf
        # 配置文件采纳 configMap
        configMap:
          name: redis-recovery
          defaultMode: 0755
        # redisc 长久化目录采纳 hostPath 卷
      - name: data
        hostPath:
          type: DirectoryOrCreate
          path: {PersistentDir}
        # 时区定义
      - name: timezone
        hostPath:
          path: /usr/share/zoneinfo/Asia/Shanghai
---
apiVersion: v1
kind: Service
metadata:
  name: redisrecovery
  namespace: database
spec:
  type: ClusterIP
  ports:
  - port: 6379
    targetPort: 6379
    name: server
  selector:
    app: redis-recovery
EOF

# 3. 删除原有的复原 Pod
kubectl delete -f redisrecovery.yaml
# kubectl delete configmap -n database redis-recovery

# 4. 判断 redis 备份格局
if ["${BACKUP_TYPE}" == "aof" ];then
  sed -i "s|# appendonly yes|appendonly yes|g" redisrecovery.yaml
  cp -a ${BACKUP_DIR}/appendonly.aof ${DATA_DIR}
else
  cp -a ${BACKUP_DIR}/dump.rdb ${DATA_DIR}
fi

# 5. 更新 redis 备份复原 k8s 资源清单中的长久化目录
sed -i "s#{PersistentDir}#${DATA_DIR}#g" redisrecovery.yaml

# 6. 创立 configmap 和部署 redis 备份复原利用
# kubectl create configmap -n database redis-recovery --from-file=$(pwd)/redis.conf
kubectl create --save-config -f redisrecovery.yaml

# 7. 验证 Pod 状态是否失常
flag=$(kubectl get pod -n database -o wide -l app=redis-recovery | grep -c "Running")
echo -e "\e[31m[Error]: Pod Status is not Running! \e[0m"
while [${flag} -ne 1 ];do
sleep 0.5
flag=$(kubectl get pod -n database -o wide -l app=redis-recovery | grep -c "Running")
done

# 8. 验证数据是否复原
# apt install -y redis-tools
echo "[OK] redis-recovery Status is Running"
echo -e "AUTH weiyigeek\nping\ninfo" | redis-cli -h redisrecovery.database.svc.cluster.local | grep -A 16 "# Keyspace"
while [$? -ne 0];do
echo -e "AUTH weiyigeek\nping\ninfo" | redis-cli -h redisrecovery.database.svc.cluster.local | grep -A 16 "# Keyspace"
done
echo "数据恢复实现......"
echo "实现工夫: $(date +%s)"

命令执行示例:

# (1) 利用 AOF 文件进行复原百万数据
/nfsdisk-31/datastore/redis/demo2# time ./K8sredisRecovery.sh aof /nfsdisk-31/data/database-data-redis-cm-0-pvc-00ee48e8-b1ca-4640-96c5-16f7265a2c61
  # # Keyspace
  # db0:keys=1000000,expires=0,avg_ttl=0
  # 数据恢复实现......
  # 实现工夫: 1631067931

  # real    0m12.039s
  # user    0m0.647s
  # sys     0m0.199s

/nfsdisk-31/datastore/redis/demo2/data# ls -alh
  # -rw-r--r-- 1 root root  41M Sep  7 22:14 appendonly.aof
  # -rw-r--r-- 1 root root  41M Sep  8  2021 dump.rdb

# (2) 利用 rdb 文件进行复原 百万数据
root@WeiyiGeek-107:/nfsdisk-31/datastore/redis/demo2# time ./K8sredisRecovery.sh rdb /nfsdisk-31/data/database-data-redis-cm-0-pvc-00ee48e8-b1ca-4640-96c5-16f7265a2c61
  # # Keyspace
  # db0:keys=993345,expires=0,avg_ttl=0
  # 数据恢复实现......
  # 实现工夫: 1631069375

  # real    0m11.106s
  # user    0m0.606s
  # sys     0m0.192s

/nfsdisk-31/datastore/redis/demo2# ls -lah data/
  # -rw-r--r-- 1 root root  41M Sep  8  2021 dump.rdb
  # root@WeiyiGeek-107:/nfsdisk-31/datastore/redis/demo2#

Tips : 从上述复原后果能够看出以 aof 形式复原的数据比 rdb 复原的数据残缺,但所加载的工夫会随着数据增大会使得 AOF 形式耗时比 rdb 耗时更多。

计划 2. 利用宿主机装置编译 redis 源码,进行恢复原 k8s 集群的 redis 数据

#!/bin/bash
# author: WeiyiGeek
# usage: ./RedisRecovery.sh [aof|rdb] redis 原长久化目录
# 验证环境: Ubuntu 20.04.1 LTS
# 脚本阐明: 将 Redis 数据恢复到物理中

if [$# -eq 0];then
  echo -e "\e[31m[*] $0 [aof|rdb] redis 原长久化目录 \e[0m"
  exit
fi

BACKUP_TYPE=$1
BACKUP_DIR=$2
DATA_DIR="$(pwd)/data"
REDIS_DIR="/usr/local/redis"

echo "开始工夫: $(date +%s)"

if [! -d ${BACKUP_DIR} ];then echo -e "[Error] - Not Found ${BACKUP_DIR} Dirctory!"; return -1; fi
if [! -d ${DATA_DIR} ];then mkdir -vp ${DATA_DIR};else rm -rf "${DATA_DIR}/*"; fi

## 1. 根底环境筹备
# - 设置内存调配策略
sudo sysctl -w vm.overcommit_memory=1
# - 尽量应用物理内存 (速度快) 针对内核版本大于 >=3.x
sudo sysctl -w vm.swapniess=1
# - SYN 队列长度设置,此参数能够包容更多期待连贯的网络。sudo sysctl -w net.ipv4.tcp_max_syn_backlog=4096
# - 禁用 THP 个性缩小内存耗费
echo never > /sys/kernel/mm/transparent_hugepage/enabled
# redis 客户端: apt remove redis-tools


## 2.REDIS 源码包
if [! -f /usr/local/redis/redis.conf];then
REDIS_VERSION="redis-6.2.5"
REDIS_URL_TAR="https://download.redis.io/releases/${REDIS_VERSION}.tar.gz"
REDIS_TAR="${REDIS_VERSION}.tar.gz"

# redis 编译环境以及编译 redis 装置在指定目录
apt install -y gcc make gcc+ pkg-config
wget ${REDIS_URL_TAR} -O /tmp/${REDIS_TAR}
tar -zxf /tmp/${REDIS_TAR} -C /usr/local/
mv /usr/local/${REDIS_VERSION} ${REDIS_DIR}
cd ${REDIS_DIR} && make distclean
make PREFIX=${REDIS_DIR} install
cp -a ${REDIS_DIR}/redis.conf /etc/redis.conf
for i in $(ls -F ${REDIS_DIR}/bin | grep "*"| sed 's#*##g');do
  sudo chmod +700 ${REDIS_DIR}/bin/${i}
  sudo ln -s ${REDIS_DIR}/bin/${i} /usr/local/bin/${i}
done
fi

# 物理机运行能够将 daemonize 设置为后盾运行。tee ${REDIS_DIR}/redis.conf <<'EOF'
bind 0.0.0.0
port 6379
daemonize yes
supervised no
protected-mode no
requirepass "weiyigeek"
dir "/data"
pidfile "/var/run/redis.pid"
logfile "/var/log/redis.log"
# loglevel verbose
maxclients 10000
timeout 300
tcp-keepalive 60
maxmemory-policy volatile-lru
slowlog-max-len 128
lua-time-limit 5000
save 900 1
save 300 100
save 60 10000
dbfilename "dump.rdb"
rdbcompression yes
rdb-save-incremental-fsync yes
# appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
rename-command FLUSHDB WeiyiGeekFLUSHDB
rename-command FLUSHALL WeiyiGeekFLUSHALL
rename-command EVAL WeiyiGeekEVAL
rename-command DEBUG WeiyiGeekDEBUG
rename-command SHUTDOWN WeiyiGeekSHUTDOWN
EOF

# 3. 判断要应用的备份格局
if ["${BACKUP_TYPE}" == "aof" ];then
  sed -i "s|# appendonly yes|appendonly yes|g" ${REDIS_DIR}/redis.conf
  cp -a ${BACKUP_DIR}/appendonly.aof ${DATA_DIR}
else
  cp -a ${BACKUP_DIR}/dump.rdb ${DATA_DIR}
fi

sed -i "s#/data#${DATA_DIR}#g" ${REDIS_DIR}/redis.conf

# 4. 启动 redis 服务复原数据
${REDIS_DIR}/bin/redis-server ${REDIS_DIR}/redis.conf 
ps -aux | grep redis-server
echo -e "AUTH weiyigeek\nping\ninfo" | redis-cli -h 127.0.0.1 | grep -A 16 "# Keyspace"
while [$? -ne 0];do
echo -e "AUTH weiyigeek\nping\ninfo" | redis-cli -h 127.0.0.1 | grep -A 16 "# Keyspace"
done
echo "数据恢复实现......"
echo "实现工夫: $(date +%s)"

<br/>

计划 3. 利用 Kubernetes 部署的 Redis 集群,进行恢复原 k8s 集群的 redis 数据

#!/bin/bash
# author: WeiyiGeek
# K8s 中 redis 集群数据恢复
# useage: K8SRedisClusterRecovery.sh [single|cluster] PODMATCH K8SVOLUMNDIR 

if [$# -eq 0];then
  echo -e "\e[31m[*] $0 [single|cluster] PODMATCH K8SVOLUMNDIR \e[0m"
  echo -e "\e[31m[*] PODMATCH : redis-cluster {异样集群 statefulset 资源对象名称} \e[0m"
  echo -e "\e[31m[*] K8SVOLUMNDIR : /nfsdisk-31/data  {K8S 长久化跟目录} \e[0m"
  exit
fi


RECTARGET="${1}"
PODMATCH="${2}"
K8SVOLUMNDIR="${3}"
AUTH="weiyigeek"
PWD=$(pwd)
AOFNAME="appendonly.aof"
DATADIR="${PWD}/database"
K8SSVCNAME="database.svc.cluster.local"


# 1. 原 `Redis` 集群 nodes 信息一览, 获取 aof 文件门路。grep "myself,master" ${K8SVOLUMNDIR}/*${PODMATCH}-[0-9]-*/nodes.conf | head -n 3 > /tmp/nodes.log
cat /tmp/nodes.log
node1=$(grep "0-5460" /tmp/nodes.log | cut -d ":" -f 1)
aofpath1=${node1%/*}
node2=$(grep "5461-10922" /tmp/nodes.log | cut -d ":" -f 1)
aofpath2=${node2%/*}
node3=$(grep "10923-16383" /tmp/nodes.log | cut -d ":" -f 1)
aofpath3=${node3%/*}


# 2. 验证 aof 文件是否存在并拷贝到以后门路下, 合并 AOF 文件到当前目录的 data 下。if [! -f ${aofpath1}/${AOFNAME} -o ! -f ${aofpath2}/${AOFNAME} -o ! -f ${aofpath3}/${AOFNAME} ];then echo -e "\e[31m[-] ${AOFNAME} file not found \e[0m";exit;fi
cp ${aofpath1}/${AOFNAME} ./1.${AOFNAME}
cp ${aofpath2}/${AOFNAME} ./2.${AOFNAME}
cp ${aofpath3}/${AOFNAME} ./3.${AOFNAME}
if [! -d ${DATADIR} ];then mkdir -v ${DATADIR};fi
cat *.aof > ${DATADIR}/${AOFNAME}
# 校验合并的原集群 aof 文件并尝试进行修复
echo "y" | /usr/local/redis/bin/redis-check-aof --fix ${DATADIR}/${AOFNAME}
ls -alh ${DATADIR}

# 3. 验证原集群相干文件是否有误(如有误须要人工进行相应解决)
echo -e "\e[32m[*] 请验证原 Redis 集群 Nodes 信息是否无误? 请输出[Y|N] \e[0m"
read flag
if ["${flag}" == "N" -o "${flag}" == "n" ];then echo -e "\e[31m[-] FAILED: 须要人工进行干涉解决. \e[0m";exit;fi


# 4. 判断复原到单实例还是 cluster 集群中。if ["${RECTARGET}" == "single" ];then
  echo -e "\e[32m[*] 正在进行异样的 K8S 集群 -> 单实例数据恢复! \e[0m"
  ./K8SRedisRecovery.sh aof ${DATADIR}
  return 0
else
  echo -e "\e[32m[*] 正在进行异样的 K8S 集群 -> 集群数据恢复! \e[0m"
fi

# 5.redis 集群资源清单(留神: 此处默认是采纳 nfs 类型的动静卷)tee Redis-cluster-6.2.5.yaml <<'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
  name: redis-cluster-recovery
  namespace: database
data:
  update-node.sh: |
    #!/bin/sh
    if [! -f /data/nodes.conf];then touch /data/nodes.conf;fi
    REDIS_NODES="/data/nodes.conf"
    sed -i -e "/myself/ s/[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/${POD_IP}/" ${REDIS_NODES}
    exec "$@"
  redis.conf: |+
    port 6379
    protected-mode no
    masterauth {RedisAuthPass}
    requirepass {RedisAuthPass}
    dir /data
    dbfilename dump.rdb
    rdbcompression yes
    no-appendfsync-on-rewrite no
    appendonly yes 
    appendfilename appendonly.aof 
    appendfsync everysec
    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size 128mb
    # 集群模式关上
    cluster-enabled yes 
    cluster-config-file /data/nodes.conf
    cluster-node-timeout 5000
    slave-read-only yes
    # 当负责一个插槽的主库下线且没有相应的从库进行故障复原时集群依然可用
    cluster-require-full-coverage no
    # 只有当一个主节点至多领有其余给定数量个处于失常工作中的从节点的时候,才会调配从节点给集群中孤立的主节点
    cluster-migration-barrier 1
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-cluster-recovery
  namespace: database
spec:
  serviceName: redisclusterrecovery
  replicas: 6
  selector:
    matchLabels:
      app: redis-cluster-recovery
  template:
    metadata:
      labels:
        app: redis-cluster-recovery
    spec:
      containers:
      - name: redis
        image: redis:6.2.5-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 6379
          name: client
        - containerPort: 16379
          name: gossip
        command: ["/conf/update-node.sh", "redis-server", "/conf/redis.conf"]
        env:
        - name: POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        volumeMounts:
        - name: conf
          mountPath: /conf
          readOnly: false
        - name: data
          mountPath: /data
          readOnly: false
        - name: timezone
          mountPath: /etc/localtime
      volumes:
      - name: conf
        configMap:
          name: redis-cluster-recovery
          defaultMode: 0755
      - name: timezone 
        hostPath:
          path: /usr/share/zoneinfo/Asia/Shanghai
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: "managed-nfs-storage"
      resources:
        requests:
          storage: 1Gi
---
# headless Service
apiVersion: v1
kind: Service
metadata:
  name: redisclusterrecovery
  namespace: database
spec:
  clusterIP: "None"
  ports:
  - port: 6379
    targetPort: 6379
    name: client
  - port: 16379
    targetPort: 16379
    name: gossip
  selector:
    app: redis-cluster-recovery
EOF
sed -i "s#{RedisAuthPass}#${AUTH}#g" Redis-cluster-6.2.5.yaml
sed "s#replicas: 6#replicas: 0#g" Redis-cluster-6.2.5.yaml > Redis-cluster-6.2.5-empty.yaml


# 6. 部署复原数据的 redis 集群:判断是否存在旧的资源对象,是则清理相干文件,否则创立集群。sts=$(kubectl get sts -n database  | grep -c "redis-cluster-recovery")
if [${sts} -eq 1 ];then 
  # 将正本数量至为 0
  kubectl apply -f Redis-cluster-6.2.5-empty.yaml; 
  podrun=$(kubectl get pod -n database  | grep -c "redis-cluster-recovery")
  while [${run} -ne 0 ];do podrun=$(kubectl get pod -n database  | grep -c "redis-cluster-recovery");sleep 5;echo -n .; done
  find ${K8SVOLUMNDIR}/database-data-redis-cluster-recovery-* -type f -delete;
  # 清理后将正本数量至为 6
  kubectl apply -f Redis-cluster-6.2.5.yaml
  run=$(kubectl get pod -n database -l app=redis-cluster-recovery | grep -c "Running")
  while [${run} -ne 6 ];do run=$(kubectl get pod -n database -l app=redis-cluster-recovery | grep -c "Running");sleep 2;echo -n .; done
else
  # 新建部署集群资源清单 
  kubectl create --save-config -f Redis-cluster-6.2.5.yaml
  run=$(kubectl get pod -n database -l app=redis-cluster-recovery | grep -c "Running")
  while [${run} -ne 6 ];do run=$(kubectl get pod -n database -l app=redis-cluster-recovery | grep -c "Running");sleep 2;echo -n .; done
fi

echo -e "\e[32m[*] Happy,redis-cluster-recovery Pod is Running....\e[0m"
kubectl get pod -n database -l app=redis-cluster-recovery


# 7.redis 集群疾速创立配置
echo -e "yes" | redis-cli -h redisclusterrecovery.${database.svc.cluster.local} -a weiyigeek --cluster create --cluster-replicas 1 $(kubectl get pods -n database -l app=redis-cluster-recovery -o jsonpath='{range.items[*]}{.status.podIP}:6379'| sed "s# :6379 ##g")
# 将其余两个 Master 卡槽归于一个 Master
redis-cli -h redis-cluster-recovery-0.redisclusterrecovery.${database.svc.cluster.local} --no-auth-warning -a weiyigeek cluster nodes | grep "master" > /tmp/rnodes.log
cat /tmp/rnodes.log
m1=$(grep "0-5460" /tmp/rnodes.log | cut -d " " -f 1)
m2=$(grep "5461-10922" /tmp/rnodes.log | cut -d " " -f 1)
m3=$(grep "10923-16383" /tmp/rnodes.log | cut -d " " -f 1)
redis-cli --no-auth-warning -a weiyigeek --cluster reshard --cluster-from ${m2} --cluster-to ${m1} --cluster-slots 5462 --cluster-yes redis-cluster-recovery-0.redisclusterrecovery.${database.svc.cluster.local}:6379 > /dev/null
redis-cli --no-auth-warning -a weiyigeek --cluster reshard --cluster-from ${m3} --cluster-to ${m1} --cluster-slots 5461 --cluster-yes redis-cluster-recovery-0.redisclusterrecovery.${database.svc.cluster.local}:6379 > /dev/null
redis-cli -h redis-cluster-recovery-0.redisclusterrecovery.database.svc.cluster.local --no-auth-warning -a weiyigeek cluster nodes
echo -e "\e[32m[*] 请验证 Nodes 信息是否无误? 请输出[Y|N] \e[0m"
read flag
if ["${flag}" == "N" -o "${flag}" == "n" ];then echo -e "\e[31m[-] FAILED: 须要人工进行干涉解决. \e[0m";exit;fi


# 8. 将所有 slots 都归于一个 master 节点后咱们须要, 将 redisclusterrecovery 资源对象所治理的 Pod 先敞开。# 将正本数量至为 0
kubectl apply -f Redis-cluster-6.2.5-empty.yaml; 
podrun=$(kubectl get pod -n database  | grep -c "redis-cluster-recovery")
while [${run} -ne 0 ];do podrun=$(kubectl get pod -n database  | grep -c "redis-cluster-recovery");sleep 5;echo -n .; done
# find ${K8SVOLUMNDIR}/database-data-redis-cluster-recovery-* -type f -delete;

# 此处只清空了 redis 长久化数据文件。master=$(find /nfsdisk-31/data/*redis-cluster-recovery-0* -type d)
rm -rf ${master}/*.aof ${master}*/.rdb
cp ${DATADIR}/appendonly.aof {${master}}

# 清理后将正本数量至为 6
kubectl apply -f Redis-cluster-6.2.5.yaml
run=$(kubectl get pod -n database -l app=redis-cluster-recovery | grep -c "Running")
while [${run} -ne 6 ];do run=$(kubectl get pod -n database -l app=redis-cluster-recovery | grep -c "Running");sleep 2;echo -n .; done

echo -e "\e[32m[*] Happy,redis-cluster-recovery Pod is Running....\e[0m"
kubectl get pod -n database -l app=redis-cluster-recovery


# 9. 解决 K8s 重启 redis 集群呈现的 fail 问题,咱们能够将谬误节点剔出集群并从新指定节点信息退出到集群之中
redis-cli -h redis-cluster-recovery-0.redisclusterrecovery.database.svc.cluster.local --no-auth-warning -a weiyigeek cluster nodes | grep "fail" > /tmp/errnodes.log
# 将该从节点剔出集群
for err in $(cat /tmp/errnodes.log | cut -d " " -f 1);do
  redis-cli -h redis-cluster-recovery-0.redisclusterrecovery.database.svc.cluster.local -a weiyigeek cluster forget ${errid}
done
# 从新将该节点退出集群
for ip in $(kubectl get pods -n database -l app=redis-cluster-recovery -o jsonpath='{range.items[*]}{.status.podIP}'| sed "s# :6379 ##g");do
  redis-cli -h  -a weiyigeek cluster meet ${ip} 6379
done

# 10. 集群状态检测以及重新分配 slots 卡槽到 Master 节点
redis-cli -h redisclusterrecovery.database.svc.cluster.local -a weiyigeek --cluster check redis-cluster-recovery-0.redisclusterrecovery.database.svc.cluster.local:6379
redis-cli -h redis-cluster-recovery-0.redisclusterrecovery.database.svc.cluster.local -a weiyigeek --cluster rebalance --cluster-threshold 1 --cluster-use-empty-masters redis-cluster-recovery-1.redisclusterrecovery.database.svc.cluster.local:6379

# 11. 验证调配的 slots 卡槽到各个 Master 节点节点信息。redis-cli -h redisclusterrecovery.database.svc.cluster.local -a weiyigeek --cluster check redis-cluster-recovery-0.redisclusterrecovery.database.svc.cluster.local:6379


# 12. 主 master 节点验证 keyspace 数据
redis-cli -h redis-cluster-recovery-0.redisclusterrecovery.database.svc.cluster.local -c -a weiyigeek info keyspace

# 13. 任何节点拜访复原的数据
redis-cli -h redisclusterrecovery.database.svc.cluster.local -c -a weiyigeek 

<br/>

3. 当 Redis 集群中呈现从节点 slave,fail,noaddr 问题进行解决复原流程。

  • Step 1. 利用 cluster nodes 查看你集群状态,发现其中一个从节点异样(是 Fail 状态)。

    f86464011d9f8ec605857255c0b67cff1e794c19 :0@0 slave,fail,noaddr 2cb35944b4492748a8c739fab63a0e90a56e414a 

<br/>

  • Step 2. 在问题节点上查看节点状态,发现它已脱离集群,且其 ID 都已产生了变动.

    127.0.0.1:6379> cluster nodes
    0cbf44ef3f9c3a8a473bcd303644388782e5ee78 192.168.109.132:6379@16379 myself,master - 0 0 0 connected 0-5461

Tips : 若 id 没发生变化,间接重启下该从节点就能解决。

<br/>

  • Step 3. 但如果 ID 与 Node IP 都发生变化时,此时咱们须要将该从节点剔出集群。

    # 在集群每个失常节点上执行 cluster forget 故障从节点 id
    echo 'cluster forget f86464011d9f8ec605857255c0b67cff1e794c19' | /usr/local/bin/redis-cli -a "weiyigeek"
  • Step 4. 咱们从新将该节点退出集群,此时咱们只须要 在集群内任意节点上执行 cluster meet 命令退出新节点,握手状态会通过信息在集群内流传,这样其余节点会主动发现新节点并发动握手流程。

    # 1. 应用集群强制分割指定节点(握手)
    echo 'cluster meet 192.168.109.132 6379' | /usr/local/bin/redis-cli -p 6379 -a "明码"
    
    # 2. 从节上执行 cluster replicate 主节点 id(配置主从关系)
    echo 'cluster replicate 2cb35944b4492748a8c739fab63a0e90a56e414a' | /usr/local/bin/redis-cli -p 6383 -a "明码"
  • Step 5. 最初检测集群是否恢复正常, 执行如下命令即可。

    echo 'cluster nodes' | /usr/local/bin/redis-cli -p 6384 -a "明码"
    38287a7e715c358b5537a369646e9698a7583459 192.168.109.132:6383@16383 slave 2cb35944b4492748a8c739fab63a0e90a56e414a 0 1615233239757 8 connected
    2cb35944b4492748a8c739fab63a0e90a56e414a 192.168.109.133:6383@16383 master - 0 1615233239000 8 connected 0-5461
    .......

原文地址: https://blog.weiyigeek.top/20…
文章书写不易,如果您感觉这篇文章还不错的,请给这篇专栏【点个赞、投个币、收个藏、关个注,转个发】(世间五大情),这将对我的必定,谢谢!。

本文章起源 我的 Blog 站点 或 WeiyiGeek 公众账号 以及 我的 BiliBili 专栏 (技术交换、友链替换请邮我哟 ), 谢谢反对!(๑′ᴗ‵๑) ❤
欢送各位气味相投的敌人一起学习交换,如文章有误请留下您贵重的常识倡议,通过邮箱【master#weiyigeek.top】分割我哟!

正文完
 0