redis持久化机制、主从哨兵架构原理
创始人
2025-06-01 05:26:49

文章目录

  • 持久化机制与主从架构
    • RDB
    • AOF
    • 混合模式
    • 数据备份与恢复
    • 主从架构
    • redis管道
    • 哨兵架构
    • SpringBoot项目配置哨兵

持久化机制与主从架构

redis有三种持久化机制:RDB、AOF、混合模式

RDB

是redis默认的持久化机制

# 比如redis.conf文件中默认就会开启以下配置,意思是60秒内如果 有1万个key改变就会触发RDB持久化
save 900 1
save 300 10
save 60 10000

持久化的文件的文件名与文件存储路径的配置在redis.conf文件中是下面的配置

dbfilename dump.rdb
dir ./

RDB持久化的方式有两种:

  • save

    这条命令在执行时是单线程的,在备份生成rdb文件时会阻塞用户的操作

  • bgsave

    rdb持久化底层默认使用的是bgsave

    就重新fork一个线程来进行数据备份,不会阻塞用户的操作。在备份过程中如果用户进行了更新操作,这块数据就会被复制一份,生成该数据的副本。然后,bgsave 子进程会把这个副本数据写入 RDB 文件,而在这个过程中,主线程仍然可以直接修改原来的数据。

RDB的优点就是文件体积小、重启恢复数据快

缺点是可能会丢失一段时间的数据,因为我们不可能每秒钟去生成一个rdb文件



AOF

如果要开启AOF持久化我们需要在redis.conf文件中放开下面这一行的配置改为yes

appendonly yes

生成的aof文件名与文件生成目录的配置如下

appendfilename "appendonly.aof"
dir ./

dir这个配置项即指定rdb文件的目录也指定aof文件的目录

AOF文件的触发策略

# appendfsync always
appendfsync everysec
# appendfsync no
  • always:每一次更新都会把命令持久化到aof文件中
  • everysec:默认项,每秒钟持久化一次
  • no:不主动进行持久化,让操作系统在需要的时候刷新数据

aof文件存储内容的格式如下所示

# 执行的原命令
set name hs# aof文件持久化内容
*3
$3
set
$4
name
$2
hs其中*3表示这个命令有三个参数:set key  value
$3表示下来来这个参数的长度为3,比如set就是3位   name是4位   hs为2位

AOF文件的优点是数据安全性更高,不会丢失很多数据

缺点是文件更大、数据恢复时间慢

AOF文件重写

aof触发文件重写的配置项的

# 其中100是百分比,达到64m就会触发一次文件重写,aof文件自上一次重写后文件大小增长了100%则再次触发重写
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

底层其实就是相当于执行一次bgrewriteaof命令

比如我现在执行很多次自增操作

127.0.0.1:6379> set number 1
OK
127.0.0.1:6379> incr number
(integer) 2
127.0.0.1:6379> incr number
(integer) 3
127.0.0.1:6379> incr number
(integer) 4
127.0.0.1:6379> incr number
(integer) 5

而aof文件中的内容如下所示

[root@VM-8-7-centos redis-5.0.3]# cat appendonly.aof 
*3
$3
set
$6
number
$1
1
*2
$4
incr
$6
number
*2
$4
incr
$6
number
*2
$4
incr
$6
number
*2
$4
incr
$6
number

此时我手动执行bgrewriteaof命令

127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started

现在aof文件中的内容如下所示

[root@VM-8-7-centos redis-5.0.3]# cat appendonly.aof 
*3
$3
set
$6
number
$1
5

aof文件的重写其实就是结合当前内存中的数据生成命令,然后保存在appendonly.aof文件中

如果rdb和aof两种持久化都开启后,redis服务重启时会优先使用aof文件来进行数据恢复,因为这种方式数据安全性更高。



混合模式

redis4.0版本开始有混合模式,它其实本质还是aof这种方式。如果要使用混合模式,前提是aof的配置项需要开启。

开启混合模式的配置项,redis5.0的版本默认开启

aof-use-rdb-preamble yes

混合模式结合了rdb和aof两种文件的优点,在触发aof文件重写时,此时会把当前内存中的数据生成二进制文件的格式存储在appendonly.aof文件中,之后还是以之前aof文件存储的格式存储

如下所示,前面一部分是二进制内容,后面一部分还是之前那的aof文件追加格式。

[root@VM-8-7-centos redis-5.0.3]# cat appendonly.aof 
REDIS0009	redis-ver5.0.3
redis-bits󿿀򳨭eR¨used-memÀ 
𮤭preamble󿾁þ㭡mehsnumberȫ)!*2
$6
SELECT
$1
0
*3
$3
set
$5
name1
$7
hushang

其实当我们使用混合模式这种方式后,就可以不需要再单独触发rdb文件备份了,可以将redis.conf文件中的save配置项都注释掉



数据备份与恢复

我们可以利用crontab定时任务备份aof或rdb文件

在数据恢复时只是将备份的文件放到指定目录下(dir配置项目录),然后重启redis-server即可完成数据恢复



主从架构

搭建主从架构

拿一台服务器上运行多个redis-service实例来举例

首先复制一份redis.conf文件,修改下面这几个不能重复的配置项

port 6380
pidfile /var/run/redis_6380.pid  # 把pid进程号写入pidfile配置的文件
logfile "6380.log"
dir /usr/local/redis-5.0.3/data/6380  # 指定数据存放目录

主从架构重点是配置下面的几行配置

replicaof 192.168.0.60 6379   # 从本机6379的redis实例复制数据,Redis 5.0之前使用slaveof
replica-read-only yes  # 配置从节点只读# 如果master配置的密码,那么我们在从机上也要指定密码
masterauth 

启动两个服务后,在redis-cli中可以通过info replication命令来查看主从架构是否搭建成功

全量主从复制原理

  1. 主从两个节点建立socket长连接
  2. 从节点向主节点发送psync命令进行数据同步
  3. 主节点会生成最新的rdb文件,并且还会有一个repl buffer缓冲区
  4. 把rdb文件同步给从节点
  5. 从节点清空老数据并加载rdb文件内容
  6. 如果在数据同步过程中,master节点有新的更新操作,这个更新操作会缓存在repl buffer中,从节点加载完rdb文件后再将repl buffer中的数据发送给从节点
  7. 从节点再执行buffer中的命令
  8. 之后主节点执行更新操作都会通过socket长连接同步给从节点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4bLJFred-1679406986106)(picture/Redis/102424)]

部分数据主从复制

如果某个时间点从节点宕机了,过一段时间后有重启了,那么这个时候我想要只是把宕机这段时间的数据进行增量复制,而不进行全量复制。过程如下

  1. master节点会缓冲一部分最近执行的命令在repl backlog buffer缓冲中
  2. 从节点重新和master建立连接后,从节点会向master发送一个psync(offset)命令,会携带从节点宕机时从主节点复制数据的偏移量
  3. master拿到这个offset后去repl backlog buffer中找判断是否能找到
  4. 如果找到了那么就从这个偏移量开始,将之后的命令同步给从节点
  5. 如果找不到则进行全量备份

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FV7gHdCA-1679406986107)(picture/Redis/102426)]

主从复制风暴

如果一个master节点下有很多的slave节点,为了缓解主从复制风暴(多个从节点同时复制主节点导致主节点压力过大),可以做如下架构,让部分从节点与从节点(与主节点同步)同步数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vphSbDHu-1679406986107)(picture/Redis/102435)]



redis管道

redis客户端可以一次性发送多条命令给redis-service去执行,目的是减少网络传输开销。但管道不能保证多条命令的原子性,如果其中有一条命令执行失败了是不会影响到其他命令的执行,以下是一个jedis使用管道的实例

Pipeline pl = jedis.pipelined();
for (int i = 0; i < 10; i++) {pl.incr("pipelineKey");pl.set("zhuge" + i, "zhuge");//模拟管道报错// pl.setbit("zhuge", -1, true);
}
List results = pl.syncAndReturnAll();
System.out.println(results);
 



哨兵架构

相关配置与启动

# 复制一份sentinel.conf文件
cp sentinel.conf sentinel-26379.conf# 将相关配置修改为如下值
port 26379
daemonize yes
pidfile "/var/run/redis-sentinel-26379.pid"
logfile "26379.log"
dir "/usr/local/redis-5.0.3/data"
# sentinel monitor    
# quorum是一个数字,指明当有多少个sentinel认为一个master失效时(值一般为:sentinel总数/2 + 1),master才算真正失效
sentinel monitor mymaster 192.168.0.60 6379 2   # mymaster这个名字随便取,客户端访问时会用到# 启动sentinel哨兵实例
src/redis-sentinel sentinel-26379.conf

我们启动了多个redis服务和redis哨兵后,在哨兵配置文件的最后会自动生成一些数据

sentinel known-replica mymaster 192.168.0.60 6380 #代表redis主节点的从节点信息
sentinel known-replica mymaster 192.168.0.60 6381 #代表redis主节点的从节点信息
sentinel known-sentinel mymaster 192.168.0.60 26380 52d0a5d70c1f90475b4fc03b6ce7c3c56935760f  #代表感知到的其它哨兵节点
sentinel known-sentinel mymaster 192.168.0.60 26381 e9f530d3882f8043f76ebb8e1686438ba8bd5ca6  #代表感知到的其它哨兵节点

当主节点如果宕机后,上面的信息也会更着修改,同时sentinel monitor mymaster 192.168.0.60 6379 2 这个配置项也会跟着修改



SpringBoot项目配置哨兵

引入相关依赖

org.springframework.bootspring-boot-starter-data-redis
org.apache.commonscommons-pool2

基本配置

server:port: 8080spring:redis:database: 0timeout: 3000sentinel:    #哨兵模式master: mymaster #主服务器所在集群名称nodes: 192.168.0.60:26379,192.168.0.60:26380,192.168.0.60:26381lettuce:pool:max-idle: 50min-idle: 10max-active: 100max-wait: 1000

java代码中的具体使用

@Autowired
private StringRedisTemplate stringRedisTemplate;stringRedisTemplate.opsForValue().set("name", "hushang");

RedisTemplate中定义了对5种数据结构操作

redisTemplate.opsForValue();//操作字符串
redisTemplate.opsForHash();//操作hash
redisTemplate.opsForList();//操作list
redisTemplate.opsForSet();//操作set
redisTemplate.opsForZSet();//操作有序set

SpringRedisTemplate介绍

StringRedisTemplate继承自RedisTemplate,也一样拥有上面这些操作。

StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。我们使用redis-cli能直接看到内容

RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。我们使用redis-cli看不到明文内容

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”,…)

相关内容

热门资讯

2025最新消息“牵手益阳棋牌... 2025最新消息“牵手益阳棋牌开挂辅助神器”原来真的有挂2022已更新(哔哩哔哩)是一款可以让一直输...
2025最新消息“畅享徐州麻将... 自定义畅享徐州麻将系统规律,只需要输入自己想要的开挂功能,一键便可以生成出畅享徐州麻将专用辅助器,不...
2025最新消息“欢乐掌心麻将... 您好:欢乐掌心麻将这款游戏可以开挂,确实是有挂的,需要了解添加微信【29290261很多玩家在这款游...
2025最新消息“畅享徐州麻将... 您好:畅享徐州麻将这款游戏可以开挂的,确实是有挂的,很多玩家在这款游戏中打牌都会发现很多用户的牌特别...
2025最新消息“决胜奕福麻将... 2025最新消息“决胜奕福麻将开挂辅助神器”原来真的有挂2022已更新(哔哩哔哩),亲,有的,ai轻...