redis.conf之save配置項解讀
配置示例:
save 900 1 save 300 10 save 60 3600 |
配置解讀:
1) “save 900 1”表示如果900秒內至少1個key發生變化(新增、修改和刪除),則重寫rdb檔案;
2) “save 300 10”表示如果每300秒內至少10個key發生變化(新增、修改和刪除),則重寫rdb檔案;
3) “save 60 3600”表示如果每60秒內至少10000個key發生變化(新增、修改和刪除),則重寫rdb檔案。
作用:
控制什麼時候生成rdb檔案(快照,也可叫Checkpoint,即檢查點)。
程式啟動的時候,會將每一行save讀進到型別為struct saveparam的陣列中。這個沒有排序,依在redis.conf中的先後順序。在檢查時,只要滿足就不會再檢查下一條規則。
配置策略:
如果同時開啟了aof,則可考慮將save的引數調大一點,以減少寫rdb帶來的壓力。實際上如果開啟了aof,redis在啟動時只會讀取aof檔案,而不會讀取rdb檔案:
// Function called at startup to load RDB or AOF file in memory. void loadDataFromDisk(void) { if (server.aof_state == AOF_ON) { // 允許空的aof檔案, // 如果讀取aof檔案出錯,則呼叫exit(1)直接退出程式 if (loadAppendOnlyFile(server.aof_filename) == C_OK) serverLog(LL_NOTICE,"DB loaded from append only file: %.3f seconds",(float)(ustime()-start)/1000000); } else { if (rdbLoad(server.rdb_filename,&rsi) == C_OK) { } }
// #define AOF_OFF 0 /* AOF is off */ // #define AOF_ON 1 /* AOF is on */ void loadServerConfigFromString(char *config) { 。。。。。。 } else if (!strcasecmp(argv[0],"appendonly") && argc == 2) { int yes; if ((yes = yesnotoi(argv[1])) == -1) { err = "argument must be 'yes' or 'no'"; goto loaderr; } server.aof_state = yes ? AOF_ON : AOF_OFF; } 。。。。。。 }
int yesnotoi(char *s) { if (!strcasecmp(s,"yes")) return 1; else if (!strcasecmp(s,"no")) return 0; else return -1; } |
呼叫順序:
main()/server.c ->
aeMain()/ae.c -> while (!stop) { aeProcessEvents()/ae.c } ->
serverCron()/server.c -> rdbSaveBackground()/server.c
注:
aeProcessEvents可看作是個epoll_wait呼叫,在Linux上實際正是epoll_wait呼叫,而在Solaris上則是port_getn呼叫。
相關原始碼:
int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { 。。。。。。 // Check if a background saving or AOF rewrite in progress terminated. // 如果已有rdb和aof程式,檢查程式是否已退出。 // 如果已退出,則會善後處理,否則什麼也不做,等待下一次迴圈時再次檢查 if (server.rdb_child_pid != -1 || server.aof_child_pid != -1 || ldbPendingChildren()) { int statloc; pid_t pid; if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) { int exitcode = WEXITSTATUS(statloc); 。。。。。。 } } else { // If there is not a background saving/rewrite // in progress check if we have to save/rewrite now. // 按在redis.conf中定義的順序依次遍歷每一行配置項 // 最終是否進行寫rdb操作(即生成快照檔案),不僅由redis.conf // 中的配置項決定,還要看上一次操作的結果和狀態。 for (j = 0; j < server.saveparamslen; j++) { struct saveparam *sp = server.saveparams+j; // Save if we reached the given amount of changes, // the given amount of seconds, and if the latest bgsave was // successful or if, in case of an error, at least // CONFIG_BGSAVE_RETRY_DELAY seconds already elapsed. // CONFIG_BGSAVE_RETRY_DELAY(5): Wait a few secs before trying again. if (server.dirty >= sp->changes && server.unixtime-server.lastsave > sp->seconds && (server.unixtime-server.lastbgsave_try>CONFIG_BGSAVE_RETRY_DELAY || server.lastbgsave_status == C_OK)) { serverLog(LL_NOTICE,"%d changes in %d seconds. Saving...", sp->changes, (int)sp->seconds); rdbSaveInfo rsi, *rsiptr; rsiptr = rdbPopulateSaveInfo(&rsi); rdbSaveBackground(server.rdb_filename,rsiptr); break; // 遇到一條滿足的即結束處理,因為已沒有必要判斷是否滿足下一條配置規則 } } } 。。。。。。 }
// rdb.c int rdbSaveBackground(char *filename, rdbSaveInfo *rsi) { 。。。。。。 server.lastbgsave_try = time(NULL); 。。。。。。 // 建立寫rdb的子程式 if ((childpid = fork()) == 0) { redisSetProcTitle("redis-rdb-bgsave"); retval = rdbSave(filename,rsi); } 。。。。。。 }
/* Save the DB on disk. Return C_ERR on error, C_OK on success. */ // rdb.c // rdbSave呼叫rdbSaveRio將資料寫入到rdb檔案中 int rdbSave(char *filename, rdbSaveInfo *rsi) { 。。。。。。 // 寫rdb檔案 if (rdbSaveRio(&rdb,&error,RDB_SAVE_NONE,rsi) == C_ERR) { errno = error; goto werr; } 。。。。。。 serverLog(LL_NOTICE,"DB saved on disk"); server.dirty = 0; server.lastsave = time(NULL); server.lastbgsave_status = C_OK; return C_OK; }
/* Produces a dump of the database in RDB format sending it to the specified * Redis I/O channel. On success C_OK is returned, otherwise C_ERR * is returned and part of the output, or all the output, can be * missing because of I/O errors. * * When the function returns C_ERR and if 'error' is not NULL, the * integer pointed by 'error' is set to the value of errno just after the I/O * error. */ int rdbSaveRio(rio *rdb, int *error, int flags, rdbSaveInfo *rsi) { for (j = 0; j < server.dbnum; j++) { 。。。。。。 // Iterate this DB writing every entry while((de = dictNext(di)) != NULL) { 。。。。。。 // 將一對對KV寫入到rdb檔案 if (rdbSaveKeyValuePair(rdb,&key,o,expire) == -1) goto werr; 。。。。。。 } } 。。。。。。 werr: if (error) *error = errno; if (di) dictReleaseIterator(di); return C_ERR; }
// 以SADD命令為例,所有寫操作,均會修改dirty 的值 void saddCommand(client *c) { 。。。。。。 for (j = 2; j < c->argc; j++) { if (setTypeAdd(set,c->argv[j]->ptr)) added++; } 。。。。。。 server.dirty += added; addReplyLongLong(c,added); } |
相關文章
- redis.conf 常用配置Redis
- Centos-redis配置redis.conf內容CentOSRedis
- Redis——Redis.conf檔案簡單詳解Redis
- Unable to save settings: Failed to save settings. Please restart PyCharm解決AIRESTPyCharm
- webpack(2)——配置項詳解Web
- Python - poetry(3)配置項詳解Python
- Python Fabric ssh 配置解讀Python
- npm install -save 和 -save-devNPMdev
- Mysql配置檔案my.ini配置項詳解MySql
- ASP.NET Core - 配置系統之配置讀取ASP.NET
- Android 高階UI9 Canvas save和restore例項解析AndroidUICanvasREST
- npm –save-dev –save 的區別NPMdev
- ThreadLocal之深度解讀thread
- Flutter之Navigator解讀Flutter
- Webpack解讀之loaderWeb
- 微服務配置中心完全解讀微服務
- Spring Security(三)--核心配置解讀Spring
- Django筆記十八之save函式的繼承操作和指定欄位更新等例項方法Django筆記函式繼承
- canvas save()Canvas
- Save Water
- Vue 原始碼解讀(6)—— 例項方法Vue原始碼
- React之配置元件的props(兩個例項)React元件
- 補習系列(10)-springboot 之配置讀取Spring Boot
- .NET Core 6.0之讀取配置檔案
- DeepSort之原始碼解讀原始碼
- mysql 5.7配置項最詳細的解釋MySql
- npm 引數使用注意事項 :npm install babel-polyfill --save-gNPMBabel
- save download pdf
- React原始碼解讀之setStateReact原始碼
- React原始碼解讀之componentMountReact原始碼
- 解決service iptables save出錯please try to use systemctl
- Mysql:mysql多例項建立、配置檔案講解【四】MySql
- canvas save()和restore()CanvasREST
- docker tag save loadDocker
- save() create()區別
- .NET Core基礎篇之:配置檔案讀取
- mongodb配置檔案常用配置項MongoDB
- Nuxt常用配置項UX