Redis 持久化主从哨兵 (二)

2022/3/3 2:15:23

本文主要是介绍Redis 持久化主从哨兵 (二),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Redis笔记

  • Redis 简介(一)
  • Redis 持久化主从哨兵 (二)

持久化

Redis 本身支持持久化,有三种方式

  • RDB快照
  • AOF
  • 混合持久化

RDB快照

定义:

在 **默认情况下,**redis将内存数据库快照保存在名字为 dump.rdb 文件中 【将内存拍照,压缩成二进制存储dump.rdb】

开启:

# 通过配置文件中
## 在time时间内,数据库有count个key被改动,触发一次save,生成dump.rdb文件
save time count

## 配置数据文件路径,这里的dir放备份文件RDB和AOF
dir [path]

## 配置备份文件名称
dbfilename dump-6379.rdb

配置完成后,通过命令可以主动生成 RDB 快照

  • save —— 阻塞执行,同步redis数据
  • bgsave —— 后台执行,生成子进程同步数据

怎么恢复?

redis在重启的时候会自动恢复数据

优点

  • 磁盘空间占用少,速度快 【二进制压缩】
  • 但是有可能会丢失大量数据

AOF

定义:

append-only file,AOF持久化将修改的每一条指令记录到文件appendonly.aof 【先写入os cache,每隔一段时间fsync到磁盘】

开启:

# 在配置文件中
## appendonly值修改为yes 开启AOF功能
appendonly yes

## 备份文件名称
appendfilename appendonly.aof


## 模式选择 内存刷入磁盘的时间 [总是,每秒,不刷入]
appendfsync [always , everysec , no]

配置完成后,AOF功能会开启

重写指令:

bgrewriteaof重写AOF中的垃圾命令,【没必要的自增命令等】 减少磁盘空间占用

# aof文件至少要达到64M才会自动重写,文件太小恢复速度本来就快,重写的意义不大
auto‐aof‐rewrite‐min‐size 64mb 


# aof文件自上一次重写后文件大小增长了100%则再次触发重写
auto‐aof‐rewrite‐percentage 100

Redis混合持久化 ※

原因:

  • 由于RDB会丢失大量文件
  • 由于AOF重放性能会比RDB低

所以可以采用混合持久化,它是AOF的升级版

  • 基于bgrewriteaof命令生成rdb内存快照
  • 生成快照过程 RESP 命令记录此时的命令

开启

# 配置
## 开启混合持久化
aof‐use‐rdb‐preamble yes

配置完成后

**AOF在重写时,**不再是简单的将 内存数据 转换为RESP命令写入 AOF 文件,

  • 而是将重写 这一刻之前的内存做RDB快照处理
  • 并将RDB快照文件内容和 增量的AOF修改内存数据命令放在一起
  • 替换原来的AOF文件

混合持久化文件模型

Redis 数据备份策略

  1. 写crontab定时调度脚本,每小时都copy一份rdb或aof的备份到一个目录中去,仅仅保留最近48小时的备份 【短期备份】
  2. 每天都保留一份当日的数据备份到一个目录中去,可以保留最近1个月的备份 【长期备份】
  3. 每次copy备份的时候,都把太旧的备份给删了
  4. 每天晚上将当前机器上的备份复制一份到其他机器上,以防机器损坏 【多机备份】

Redis主从架构

配置

# 架构搭建,配置从节点步骤
# 1、复制一份redis.conf文件

# 2、将相关配置修改为如下值:
port 6380
pidfile /var/run/redis_6380.pid # 把pid进程号写入pidfile配置的文件
logfile /usr/local/redis/log/6380.log
dir /usr/local/redis/data/6380 # 指定数据存放目录
# 需要注释掉bind
# bind 127.0.0.1(bind绑定的是自己机器网卡的ip,如果有多块网卡可以配多个ip,代表允许客户端通过机器的哪些网卡ip去访问,内网一般可以不配置bind,注释掉即可)

# 3、配置主从复制
replicaof 192.168.0.60 6379 # 从本机6379的redis实例复制数据,Redis 5.0之前使用slaveof
replica‐read‐only yes # 配置从节点只读

# 4、启动从节点
redis‐server redis.conf

# 5、连接从节点
redis‐cli ‐p 6380

# 6、测试在6379实例上写数据,6380实例是否能及时同步新修改数据

# 7、可以自己再配置一个6381的从节点

工作原理

有一下两种方式

  • 全量复制
  • 部分复制

全量复制

流程:

  1. slave 建立socket,发送 PSYNC 命令给 master 请求复制数据
  2. master 接收到 PSYNC 命令,bgsave生成RDB快照,并继续接收客户端请求 RESP 存入 内存 中 【RDB+Buffer
  3. master send rdb数据
  4. slave 清空旧数据,加载masterrdb 数据
  5. master send buffer
  6. slave 执行buffer内的命令,数据写入内存
  7. 通过socket长连接,保持==主从数据一致性==

全量复制原理

注意:

如果master收到多个slave并发请求,只会进行一次持久化,并将rdb 发送给多个并发连接的slave

部分复制

当master和slave断开重连后,支持部分数据复制的命令PSYNC去同步master的数据。【断点续传

流程:

  1. master 在内存创建一个缓存队列,缓存最近的数据 【repl backlog buffer
  2. master 和所有的 slave 维护复制的数据下标 offsetmaster的进程id
  3. 断开重连,slave 会请求 master 继续进行未完成的复制
  4. 如果master的进程id变化,或者 offset不在master缓存队列里,会执行一次全量复制

部分复制原理

主从复制风暴

定义:

如果有很多从节点,多个从节点同时复制主节点导致主节点压力过大,可以做如下架构优化

主从复制风暴优化

哨兵高可用架构

定义:

sentinel哨兵是特殊的redis服务,主要用来 监控redis实例节点

客户端通过连接sentinel集群,来连接redis集群,因为sentinel集群中的节点始终指向redis集群中的master节点,当master节点宕机后,sentinel会选举一个新的master节点

流程:

  1. 客户端第一次访问集群,是访问sentinel
  2. sentinel 指向redis集群中的 主节点
  3. 客户端后续访问直接访问master主节点
  4. 如果redis主节点发生变化,sentinel会感知到并推送给客户端client实现订阅功能

架构图

配置

# 1、复制一份sentinel.conf文件
cp sentinel.conf sentinel‐26379.conf

# 2、将相关配置修改为如下值:
port 26379
daemonize yes
pidfile "/var/run/redis‐sentinel‐26379.pid"
logfile "26379.log"
dir "/usr/local/redis‐5.0.3/data"
# sentinel monitor <master‐redis‐name> <master‐redis‐ip> <master‐redis‐port> <quorum>
# quorum是一个数字,指明当有多少个sentinel认为一个master失效时(值一般为:sentinel总数/2 +1),master才算真正失效 【半数以上选举】
sentinel monitor mymaster 47.107.82.29 6379 2 # mymaster这个名字随便取,客户端访问时会用到,关闭防火墙

# 3、启动sentinel哨兵实例
src/redis‐sentinel sentinel‐26379.conf

# 4、查看sentinel的info信息
src/redis‐cli ‐p 26379
127.0.0.1:26379>info

# 可以看到Sentinel的info里已经识别出了redis的主从

# 5、可以自己再配置两个sentinel,端口26380和26381,注意上述配置文件里的对应数字都要修改

选举

master宕机后,slave要通过选举才能成为新的master

哨兵leader选举流程

当一个master服务器被某个sentinel定为下线后

  • sentinel 会与其他 sentinel协商选出sentinelleader进行故障转移工作 【sentinel leader
  • 每个发现 master 服务器下线的 sentinel 都可以要求 其他的sentinel选自己为leader选举先到先得
  • sentinel 每次选举都会自增配置纪元【选举周期】,每个周期指挥选择一个leader
  • 如果超过一半的票数选取某个sentinel,之后该sentinel作为leader进行故障转移工作,从存活的slave中选出master 【与集群中选取master类似,sentinel投票

可以只有一个sentinel,不过为了高可用,一般至少配置三个

管道和Lua脚本

管道

定义:

客户端可以一次性发送多个请求而不等待服务器的响应,等所有命令发送完后再一次性读取响应,降低网络传输开销

管道执行多条命令是通过pipeline方式打包命令发送,redis处理完所有命令前先缓存所有命令的处理结果,但不保证全都成功执行。

Lua脚本

  1. 减少网络开销 —— 多次网络请求,合并为一次
  2. 原子操作 —— 中途不被其他命令插入
  3. 替代redis的事务功能 —— 支持报错回滚操作

注意,不要在Lua脚本中出现死循环或者耗时的运算,否则redis会阻塞,单线程执行脚本,管道不会阻塞redis

RedisTemplate中的方法

String类型结构
RedisRedisTemplate rt
set key valuert.opsForValue().set(“key”,“value”)
get keyrt.opsForValue().get(“key”)
del keyrt.delete(“key”)
strlen keyrt.opsForValue().size(“key”)
getset key valuert.opsForValue().getAndSet(“key”,“value”)
getrange key start endrt.opsForValue().get(“key”,start,end)
append key valuert.opsForValue().append(“key”,“value”)
Hash结构
hmset key field1 value1 field2 value2…rt.opsForHash().putAll(“key”,map) //map是一个集合对象
hset key field valuert.opsForHash().put(“key”,“field”,“value”)
hexists key fieldrt.opsForHash().hasKey(“key”,“field”)
hgetall keyrt.opsForHash().entries(“key”) //返回Map对象
hvals keyrt.opsForHash().values(“key”) //返回List对象
hkeys keyrt.opsForHash().keys(“key”) //返回List对象
hmget key field1 field2…rt.opsForHash().multiGet(“key”,keyList)
hsetnx key field valuert.opsForHash().putIfAbsent(“key”,“field”,“value”
hdel key field1 field2rt.opsForHash().delete(“key”,“field1”,“field2”)
hget key fieldrt.opsForHash().get(“key”,“field”)
List结构
lpush list node1 node2 node3…rt.opsForList().leftPush(“list”,“node”)
rt.opsForList().leftPushAll(“list”,list) //list是集合对象
rpush list node1 node2 node3…rt.opsForList().rightPush(“list”,“node”)
rt.opsForList().rightPushAll(“list”,list) //list是集合对象
lindex key indexrt.opsForList().index(“list”, index)
llen keyrt.opsForList().size(“key”)
lpop keyrt.opsForList().leftPop(“key”)
rpop keyrt.opsForList().rightPop(“key”)
lpushx list nodert.opsForList().leftPushIfPresent(“list”,“node”)
rpushx list nodert.opsForList().rightPushIfPresent(“list”,“node”)
lrange list start endrt.opsForList().range(“list”,start,end)
lrem list count valuert.opsForList().remove(“list”,count,“value”)
lset key index valuert.opsForList().set(“list”,index,“value”)
Set结构
sadd key member1 member2…rt.boundSetOps(“key”).add(“member1”,“member2”,…)
rt.opsForSet().add(“key”, set) //set是一个集合对象
scard keyrt.opsForSet().size(“key”)
sidff key1 key2rt.opsForSet().difference(“key1”,“key2”) //返回一个集合对象
sinter key1 key2rt.opsForSet().intersect(“key1”,“key2”)//同上
sunion key1 key2rt.opsForSet().union(“key1”,“key2”)//同上
sdiffstore des key1 key2rt.opsForSet().differenceAndStore(“key1”,“key2”,“des”)
sinter des key1 key2rt.opsForSet().intersectAndStore(“key1”,“key2”,“des”)
sunionstore des key1 key2rt.opsForSet().unionAndStore(“key1”,“key2”,“des”)
sismember key memberrt.opsForSet().isMember(“key”,“member”)
smembers keyrt.opsForSet().members(“key”)
spop keyrt.opsForSet().pop(“key”)
srandmember key countrt.opsForSet().randomMember(“key”,count)
srem key member1 member2…rt.opsForSet().remove(“key”,“member1”,“member2”,…)


这篇关于Redis 持久化主从哨兵 (二)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程