1. Redis持久化机制介绍
Redis(Remote Dictionary Server)是一种高性能的键值对存储数据库,其优点包括高性能、支持多种数据结构、持久化、主从复制等。而其中持久化机制,也就是将Redis内存中的数据保存到磁盘中,是Redis中非常重要的一个特性。Redis提供了两种持久化方式:RDB快照和AOF日志。
1.1 RDB快照
RDB快照是Redis的一种数据持久化方式,它会在指定时间间隔内来保存Redis数据。当Redis服务器需要持久化数据时,它会fork出一个子进程来进行RDB快照,将整个内存中的数据保存到一个文件中。由于fork出一个子进程,所以在进行快照的过程中,Redis主进程是不会受到影响的,不会发生阻塞。虽然生成快照会占用一定的内存来暂存当前的数据,但是对于Redis来说,生成RDB文件的方式可以保证数据的完整性,也保证了文件的可压缩性
下面是一个RDB快照的配置示例:
save 900 1
save 300 10
save 60 10000
以上配置表示,当Redis内存中的数据在900秒内有至少1个键被修改、在300秒内有至少10个键被修改或者在60秒内有至少10000个键被修改,则Redis会触发持久化快照。由于RDB快照的特点,很适合用在备份和恢复的场景中,也比AOF的可靠性高,但是因为是定期持久化,所以可能会丢失最近修改的数据。
1.2 AOF日志
AOF持久化是将Redis的所有操作以日志的方式记录下来,只要该日志文件足够记录一段时间的Redis操作,就能完整地还原出Redis的数据。AOF日志文件以文本的方式保存,每条Redis命令都会以文本的方式追加到日志的最后,一旦Redis重新启动,就可以通过重新执行这些命令来还原数据。AOF持久化可以通过配置不同的刷盘策略来保障数据的安全性和稳定性。
下面是一个AOF日志的配置示例:
appendonly yes
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
以上配置表示,开启AOF功能,每秒钟将AOF缓冲区中的数据刷写到磁盘上,当AOF文件大小超过原来文件的100%时,Redis会自动触发AOF重写操作,重写后的文件的文件大小至少为64mb。
2. Redis持久化实现
Redis持久化的实现基于5个关键函数:
rdbSave、rdbLoad:RDB快照的实现
aofWrite、flushAppendOnlyFile:AOF持久化的实现
startAppendOnly:开启AOF文件的记录
2.1 RDB快照实现
RDB快照的实现是通过rdbSave和rdbLoad两个函数来实现的。前者将Redis的内存数据转换成RDB文件,后者则将RDB文件加载到内存中。
下面是rdbSave函数的部分代码:
if ((fp = fopen(filename,"w")) == NULL) return REDIS_ERR;
payload = SDL_malloc(sz);
if (payload == NULL) {
fclose(fp);
return REDIS_ERR;
}
if (rdbSaveAux(fp) == -1) {
fclose(fp);
SDL_free(payload);
return REDIS_ERR;
}
上面代码中,首先会打开一个文件句柄,然后分配好了一个payload缓存区用来存放要写入文件中的数据。接着调用rdbSaveAux函数进行RDB数据的写入。rdbSaveAux函数是一个递归函数,在写入数据的过程中,会从Redis的数据库中不断地读取数据,然后写入文件中,直到所有数据都写入完毕。
下面是rdbLoad函数的部分代码:
if ((fp = fopen(filename,"r")) == NULL) return REDIS_ERR;
...
while(rdbLoadLen(&fp,NULL) != -1) {
if ((sds = rdbLoadStringObject(&fp)) == NULL) goto err;
...
ret = rdbLoadObject(type,fp);
sdsfree(sds);
if (ret == -1) {
goto err;
}
}
...
上述代码中,我们需要先打开RDB文件,然后开始迭代读取文件中的RDB数据。每次循环调用rdbLoadLen函数读取数据长度,再进行分支判断。如果读取的长度为-1,则代表就读到了文件的结尾。否则调用rdbLoadStringObject函数获取数据到缓冲的字符串中。最后调用rdbLoadObject函数,将缓冲中的数据转换成Redis可以识别的对象,并缓存到数据库中。
2.2 AOF持久化实现
AOF持久化的实现是通过aofWrite和flushAppendOnlyFile两个函数来实现的。aofWrite函数用来追加写入新的Redis操作到AOF文件中,而flushAppendOnlyFile函数则用来将AOF缓冲区中的数据刷写到磁盘上。
下面是aofWrite函数的部分代码:
if (server.aof_state == AOF_ON) {
off = ftello(server.aof_fp);
if (fwrite(payload,sz,1,server.aof_fp) == 0) goto werr;
server.aof_current_size += sz;
if (g_pserver->aof_rewrite_scheduled
== 0 && server.aof_current_size > server.aof_rewrite_min_size) {
g_pserver->aof_rewrite_scheduled = 1;
bgrewriteaofIfNeeded();
}
}
上述代码中,判断AOF是否处于开启状态。如果开启,则将AOF缓冲区中的数据写入文件中。如果文件写入失败,则直接跳转到错误处理。此外,每次写入操作完成后,将当前保存的长度保存到server.aof_current_size中,并判断是否需要进行AOF重写。
下面是flushAppendOnlyFile函数的部分代码:
...
if (fflush(fp)) goto writeerr;
if (aof_fsync(fileno(fp)) == -1) goto writeerr;
server.aof_last_fsync = server.unixtime;
...
上述代码中,我们首先将AOF缓冲区中的数据刷入到文件中,并通过调用aof_fsync函数将文件刷写到磁盘上。同时也更新了last_fsync字段,标记了最后一次刷盘的时间。
3. 总结
Redis的持久化机制是非常重要的特性之一,因为它可以保障Redis的数据不会因为异常情况而意外丢失。Redis目前提供了两种持久化方式:RDB和AOF。其中,RDB快照比较适用于实时数据备份和重建;AOF日志则比适合应用在数据安全等较为苛刻的场景。
在实现上,Redis是通过rdbSave、rdbLoad、aofWrite和flushAppendOnlyFile等函数来实现持久化机制。掌握这些关键函数的原理,也有助于我们深入理解Redis的持久化机制实现。