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 数据备份策略
- 写crontab定时调度脚本,每小时都copy一份rdb或aof的备份到一个目录中去,仅仅保留最近48小时的备份 【短期备份】
- 每天都保留一份当日的数据备份到一个目录中去,可以保留最近1个月的备份 【长期备份】
- 每次copy备份的时候,都把太旧的备份给删了
- 每天晚上将当前机器上的备份复制一份到其他机器上,以防机器损坏 【多机备份】
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的从节点
工作原理
有一下两种方式
- 全量复制
- 部分复制
全量复制
流程:
- slave 建立socket,发送 PSYNC 命令给 master 请求复制数据
- master 接收到 PSYNC 命令,bgsave生成RDB快照,并继续接收客户端请求 RESP 存入 内存 中 【RDB+Buffer】
- master send rdb数据
- slave 清空旧数据,加载master的 rdb 数据
- master send buffer
- slave 执行buffer内的命令,数据写入内存
- 通过socket长连接,保持==主从数据一致性==
注意:
如果master收到多个slave并发请求,只会进行一次持久化,并将rdb 发送给多个并发连接的slave
部分复制
当master和slave断开重连后,支持部分数据复制的命令PSYNC去同步master的数据。【断点续传】
流程:
- master 在内存创建一个缓存队列,缓存最近的数据 【repl backlog buffer】
- master 和所有的 slave 维护复制的数据下标 offset 和 master的进程id
- 断开重连,slave 会请求 master 继续进行未完成的复制
- 如果master的进程id变化,或者 offset不在master缓存队列里,会执行一次全量复制
主从复制风暴
定义:
如果有很多从节点,多个从节点同时复制主节点导致主节点压力过大,可以做如下架构优化
哨兵高可用架构
定义:
sentinel哨兵是特殊的redis服务,主要用来 监控redis实例节点
客户端通过连接sentinel集群,来连接redis集群,因为sentinel集群中的节点始终指向redis集群中的master节点,当master节点宕机后,sentinel会选举一个新的master节点
流程:
- 客户端第一次访问集群,是访问sentinel
- sentinel 指向redis集群中的 主节点
- 客户端后续访问直接访问master主节点
- 如果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协商选出sentinel的leader进行故障转移工作 【sentinel leader】
- 每个发现 master 服务器下线的 sentinel 都可以要求 其他的sentinel选自己为leader 【选举先到先得】
- sentinel 每次选举都会自增配置纪元【选举周期】,每个周期指挥选择一个leader
- 如果超过一半的票数选取某个sentinel,之后该sentinel作为leader进行故障转移工作,从存活的slave中选出master 【与集群中选取master类似,sentinel投票】
可以只有一个sentinel,不过为了高可用,一般至少配置三个
管道和Lua脚本
管道
定义:
客户端可以一次性发送多个请求而不等待服务器的响应,等所有命令发送完后再一次性读取响应,降低网络传输开销
管道执行多条命令是通过pipeline方式打包命令发送,redis处理完所有命令前先缓存所有命令的处理结果,但不保证全都成功执行。
Lua脚本
- 减少网络开销 —— 多次网络请求,合并为一次
- 原子操作 —— 中途不被其他命令插入
- 替代redis的事务功能 —— 支持报错回滚操作
注意,不要在Lua脚本中出现死循环或者耗时的运算,否则redis会阻塞,单线程执行脚本,管道不会阻塞redis
RedisTemplate中的方法
String类型结构 | |
---|---|
Redis | RedisTemplate rt |
set key value | rt.opsForValue().set(“key”,“value”) |
get key | rt.opsForValue().get(“key”) |
del key | rt.delete(“key”) |
strlen key | rt.opsForValue().size(“key”) |
getset key value | rt.opsForValue().getAndSet(“key”,“value”) |
getrange key start end | rt.opsForValue().get(“key”,start,end) |
append key value | rt.opsForValue().append(“key”,“value”) |
Hash结构 | |
hmset key field1 value1 field2 value2… | rt.opsForHash().putAll(“key”,map) //map是一个集合对象 |
hset key field value | rt.opsForHash().put(“key”,“field”,“value”) |
hexists key field | rt.opsForHash().hasKey(“key”,“field”) |
hgetall key | rt.opsForHash().entries(“key”) //返回Map对象 |
hvals key | rt.opsForHash().values(“key”) //返回List对象 |
hkeys key | rt.opsForHash().keys(“key”) //返回List对象 |
hmget key field1 field2… | rt.opsForHash().multiGet(“key”,keyList) |
hsetnx key field value | rt.opsForHash().putIfAbsent(“key”,“field”,“value” |
hdel key field1 field2 | rt.opsForHash().delete(“key”,“field1”,“field2”) |
hget key field | rt.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 index | rt.opsForList().index(“list”, index) |
llen key | rt.opsForList().size(“key”) |
lpop key | rt.opsForList().leftPop(“key”) |
rpop key | rt.opsForList().rightPop(“key”) |
lpushx list node | rt.opsForList().leftPushIfPresent(“list”,“node”) |
rpushx list node | rt.opsForList().rightPushIfPresent(“list”,“node”) |
lrange list start end | rt.opsForList().range(“list”,start,end) |
lrem list count value | rt.opsForList().remove(“list”,count,“value”) |
lset key index value | rt.opsForList().set(“list”,index,“value”) |
Set结构 | |
sadd key member1 member2… | rt.boundSetOps(“key”).add(“member1”,“member2”,…) |
rt.opsForSet().add(“key”, set) //set是一个集合对象 | |
scard key | rt.opsForSet().size(“key”) |
sidff key1 key2 | rt.opsForSet().difference(“key1”,“key2”) //返回一个集合对象 |
sinter key1 key2 | rt.opsForSet().intersect(“key1”,“key2”)//同上 |
sunion key1 key2 | rt.opsForSet().union(“key1”,“key2”)//同上 |
sdiffstore des key1 key2 | rt.opsForSet().differenceAndStore(“key1”,“key2”,“des”) |
sinter des key1 key2 | rt.opsForSet().intersectAndStore(“key1”,“key2”,“des”) |
sunionstore des key1 key2 | rt.opsForSet().unionAndStore(“key1”,“key2”,“des”) |
sismember key member | rt.opsForSet().isMember(“key”,“member”) |
smembers key | rt.opsForSet().members(“key”) |
spop key | rt.opsForSet().pop(“key”) |
srandmember key count | rt.opsForSet().randomMember(“key”,count) |
srem key member1 member2… | rt.opsForSet().remove(“key”,“member1”,“member2”,…) |
这篇关于Redis 持久化主从哨兵 (二)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-08阿里云Redis项目实战入门教程
- 2024-11-08阿里云Redis资料:新手入门与初级使用指南
- 2024-11-08阿里云Redis教程:新手入门及实用指南
- 2024-11-07阿里云Redis学习入门:新手必读指南
- 2024-11-07阿里云Redis学习入门:从零开始的操作指南
- 2024-11-07阿里云Redis学习:初学者指南
- 2024-11-06阿里云Redis入门教程:轻松搭建与使用指南
- 2024-11-02Redis项目实战:新手入门教程
- 2024-10-22Redis入门教程:轻松掌握数据存储与操作
- 2024-10-22Redis缓存入门教程:快速掌握Redis缓存基础知识