前言
网络上也有许多介绍redis的AOF机制的文章,但是从宏观上介绍aof的流程,没有具体分析在AOF过程中涉及到的数据结构和控制机制。昨晚特别看了2.8源码,感觉源码中的许多细节是值得细细深究的。特别是list *aof_rewrite_buf_blocks结构。仔细看源码,会发现原来看网络文章多的到的领会是片面的,最好的学习还是得自己动手...
原文链接: http://blog.csdn.net/ordeder/article/details/39271543
作者提及的AOF简化的流程为:
* 1) The user calls BGREWRITEAOF
* 2) Redis calls this function, that forks():
* 2a) the child rewrite the append only file in a temp file.
* 2b) the parent accumulates differences in server.aof_rewrite_buf.
* 3) When the child finished '2a' exists.
* 4) The parent will trap the exit code, if it's OK, will append the
* data accumulated into server.aof_rewrite_buf into the temp file, and
* finally will rename(2) the temp file in the actual file name.
* The the new file is reopened as the new append only file. Profit!
AOF流程
依据源码,AOF总体有一下操作:
主要函数:
//函数1:将command写入aof_buff
void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc);
//函数2:启动子进程,子进程用于刷一遍redis中的数据
int rewriteAppendOnlyFileBackground(void);
//函数3:刷一遍server.db[16],依次将对象写入磁盘临时文件tmpfile
int rewriteAppendOnlyFile(char *filename);
//函数4:将aof_buff内容持久化
void flushAppendOnlyFile(int force);
//函数5:将server.aof_rewrite_buf_blocks中的内容写入tmpfile,并替换aof文件
void backgroundRewriteDoneHandler(exitcode,bysignal);
1 AOF日常命令append:
1.1. Redis执行文件事件:执行用户命令,并将该命令缓存于Server.aof_buf中{函数1}
1.2. Redis执行时间时间的ServerCron:依据参数server.aof_flush_postponed_start,{函数4}
1.2.1. 将redisServer.aof_buf写入文件Server.aof_fd。
1.2.2. 该文件何时fsync到磁盘有三种机制:
AOF_FSYNC_EVERYSEC 每秒调用fsync
AOF_FSYNC_ALWAYS 写文件后立即调用fsync
其他 听系统的
2 AOF日志简化操作:
2.1. Redis执行时间时间的ServerCron:{函数2-3}
2.1.1. 开启后台AOF进程,依据redis内存数据(redis.db[16]),生成可重建数据库的命令集,并写入tmpfile临时文件
2.2. Redis执行文件事件:
执行用户命令时,{函数1}
2.2.1. 将该命令缓存于redisServer.aof_buf;
2.2.2. 同时将该命令缓存于server.aof_rewrite_buf_blocks
2.3. Redis执行时间时间的ServerCron:
2.3.1 {函数4}在aof子进程还未结束期间,步骤 1.2 照常执行,将aof_buf写入aof_fd(该干嘛干嘛)
2.3.2 wait3发现aof子进程结束,那么:{函数5}
2.3.2.1 将server.aof_rewrite_buf_blocks中的内容写入tmpfile中
2.3.2.2 用tmpfile替换原有aof文件,并重置Server.aof_fd
函数和数据间关系如下图所示:

源码
struct redisServer{
...
/* AOF persistence */
int aof_state; /* REDIS_AOF_(ON|OFF|WAIT_REWRITE) */
int aof_fsync; /* Kind of fsync() policy (每个操作|每秒|缓冲区满)*/
char *aof_filename; /* Name of the AOF file */
int aof_no_fsync_on_rewrite; /* Don't fsync if a rewrite is in prog. */
int aof_rewrite_perc; /* Rewrite AOF if % growth is > M and... */
off_t aof_rewrite_min_size; /* the AOF file is at least N bytes. */
off_t aof_rewrite_base_size; /* AOF size on latest startup or rewrite. */
off_t aof_current_size; /* AOF current size. */
int aof_rewrite_scheduled; /* Rewrite once BGSAVE terminates. 是否需要开启后台aof子进程*/
pid_t aof_child_pid; /* PID if rewriting process */
list *aof_rewrite_buf_blocks; /* Hold changes during an AOF rewrite. 在aof bgsave期间redis执行的命令将存储到aof_rewrite_buf_blocks,当然aof_buf还是要照常使用的,二者不冲突*/
sds aof_buf; /* AOF buffer, written before entering the event loop */
int aof_fd; /* File descriptor of currently selected AOF file */
int aof_selected_db; /* Currently selected DB in AOF */
time_t aof_flush_postponed_start; /* UNIX time of postponed AOF flush */
time_t aof_last_fsync; /* UNIX time of last fsync() */
time_t aof_rewrite_time_last; /* Time used by last AOF rewrite run. */
time_t aof_rewrite_time_start; /* Current AOF rewrite start time. */
int aof_lastbgrewrite_statu