本文取3.0版本分析(各個版本差異很大,4.0以上才有aof和rdb混合模式)
觸發時機
? ? ? ? 1、bgrewriteaofCommand函數觸發,即在Redis server服務上運行bgrewriteaof命令。
????????1-1、當前已經有 AOF 重寫的子進程正在執行,重復執行bgrewriteaof命令,是不會執行bgrewriteaof命令。
? ? ? ? 1-2、執行rewriteAppendOnlyFileBackground函數。
? ? ? ? 2、rewriteAppendOnlyFileBackground函數觸發:
????????2-1、當前沒有aof子進程和rdb子進程,但是存在著等待執行任務調度的aof命令,只有到了執行任務調度aof命令的情況下,才會觸發aof重寫。
? ? ? ? 2-2、當前沒有aof子進程和rdb子進程,但是設置了aof閾值的情況,如果當前aof文件超過了預留的閾值,則會觸發aof重寫。
? ? ? ? 3、開啟Redis server aof配置功能
????????3-1、當用戶在運行時使用config命令,從 appendonly no 切換到 appendonly yes 時執行。
? ? ? ? 3-2、執行rewriteAppendOnlyFileBackground函數。
? ? ? ? 4、主從復制函數readSyncBulkPayload,startAppendOnly函數
? ? ? ? 4-1、主從復制開啟aof配置功能下,如果有rdb子進程,那么等待rdb子進程處理完后,再通過任務調度執行aof持久化,如果有aof進程,強制kill掉正在執行的aof子進程,重新生成aof持久化文件。
生成aof文件過程
挺復雜的,后面繼續研究
/* This is how rewriting of the append only file in background works:* * 以下是后臺重寫 AOF 文件(BGREWRITEAOF)的工作步驟:** 1) The user calls BGREWRITEAOF* 用戶調用 BGREWRITEAOF** 2) Redis calls this function, that forks():* Redis 調用這個函數,它執行 fork() :** 2a) the child rewrite the append only file in a temp file.* 子進程在臨時文件中對 AOF 文件進行重寫** 2b) the parent accumulates differences in server.aof_rewrite_buf.* 父進程將新輸入的寫命令追加到 server.aof_rewrite_buf 中** 3) When the child finished '2a' exists.* 當步驟 2a 執行完之后,子進程結束** 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!** 父進程會捕捉子進程的退出信號,* 如果子進程的退出狀態是 OK 的話,* 那么父進程將新輸入命令的緩存追加到臨時文件,* 然后使用 rename(2) 對臨時文件改名,用它代替舊的 AOF 文件,* 至此,后臺 AOF 重寫完成。*/
int rewriteAppendOnlyFileBackground(void) {pid_t childpid;long long start;// 已經有進程在進行 AOF 重寫了if (server.aof_child_pid != -1) return REDIS_ERR;// 記錄 fork 開始前的時間,計算 fork 耗時用start = ustime();if ((childpid = fork()) == 0) {char tmpfile[256];/* Child */// 關閉網絡連接 fdcloseListeningSockets(0);// 為進程設置名字,方便記認redisSetProcTitle("redis-aof-rewrite");// 創建臨時文件,并進行 AOF 重寫snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) getpid());if (rewriteAppendOnlyFile(tmpfile) == REDIS_OK) {size_t private_dirty = zmalloc_get_private_dirty();if (private_dirty) {redisLog(REDIS_NOTICE,"AOF rewrite: %zu MB of memory used by copy-on-write",private_dirty/(1024*1024));}// 發送重寫成功信號exitFromChild(0);} else {// 發送重寫失敗信號exitFromChild(1);}} else {/* Parent */// 記錄執行 fork 所消耗的時間server.stat_fork_time = ustime()-start;if (childpid == -1) {redisLog(REDIS_WARNING,"Can't rewrite append only file in background: fork: %s",strerror(errno));return REDIS_ERR;}redisLog(REDIS_NOTICE,"Background append only file rewriting started by pid %d",childpid);// 記錄 AOF 重寫的信息server.aof_rewrite_scheduled = 0;server.aof_rewrite_time_start = time(NULL);server.aof_child_pid = childpid;// 關閉字典自動 rehashupdateDictResizePolicy();/* We set appendseldb to -1 in order to force the next call to the* feedAppendOnlyFile() to issue a SELECT command, so the differences* accumulated by the parent into server.aof_rewrite_buf will start* with a SELECT statement and it will be safe to merge. ** 將 aof_selected_db 設為 -1 ,* 強制讓 feedAppendOnlyFile() 下次執行時引發一個 SELECT 命令,* 從而確保之后新添加的命令會設置到正確的數據庫中*/server.aof_selected_db = -1;replicationScriptCacheFlush();return REDIS_OK;}return REDIS_OK; /* unreached */
}