• <fieldset id="8imwq"><menu id="8imwq"></menu></fieldset>
  • <bdo id="8imwq"><input id="8imwq"></input></bdo>
    最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
    問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
    當前位置: 首頁 - 科技 - 知識百科 - 正文

    硬盤寫滿后redis的處理機制

    來源:懂視網 責編:小采 時間:2020-11-09 14:20:50
    文檔

    硬盤寫滿后redis的處理機制

    硬盤寫滿后redis的處理機制:前些天一臺redis機器硬盤寫滿了,主要是由于程序bug導致備份量激增,而恰好監控程序的通知機制也罷工了,于是第一次體驗到了redis的罷工(只讀不寫)。 現在我們來看下在磁盤寫滿后redis的處理機制: save流程:serverCron-rdbSaveBackgroun
    推薦度:
    導讀硬盤寫滿后redis的處理機制:前些天一臺redis機器硬盤寫滿了,主要是由于程序bug導致備份量激增,而恰好監控程序的通知機制也罷工了,于是第一次體驗到了redis的罷工(只讀不寫)。 現在我們來看下在磁盤寫滿后redis的處理機制: save流程:serverCron-rdbSaveBackgroun

    前些天一臺redis機器硬盤寫滿了,主要是由于程序bug導致備份量激增,而恰好監控程序的通知機制也罷工了,于是第一次體驗到了redis的罷工(只讀不寫)。 現在我們來看下在磁盤寫滿后redis的處理機制: save流程:serverCron-rdbSaveBackground-rdbSave save后

    前些天一臺redis機器硬盤寫滿了,主要是由于程序bug導致備份量激增,而恰好監控程序的通知機制也罷工了,于是第一次體驗到了redis的罷工(只讀不寫)。

    現在我們來看下在磁盤寫滿后redis的處理機制:

    save流程:serverCron->rdbSaveBackground->rdbSave
    save后流程:serverCron->backgroundSaveDoneHandler
    上述流程產生的結果就是server.lastbgsave_status = REDIS_ERR,

    受其影響,processCommand和luaRedisGenericCommand中判斷如果是寫操作,則直接返回REDIS_OK,而沒有實際寫入

    1.rdbSave所有的寫出錯都會返回REDIS_ERR

    int rdbSave(char *filename) {
     dictIterator *di = NULL;
     dictEntry *de;
     char tmpfile[256];
     char magic[10];
     int j;
     long long now = mstime();
     FILE *fp;
     rio rdb;
     uint64_t cksum;
    
     snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
     fp = fopen(tmpfile,"w");
     if (!fp) {
     redisLog(REDIS_WARNING, "Failed opening .rdb for saving: %s",
     strerror(errno));
     return REDIS_ERR;
     }
    
     rioInitWithFile(&rdb,fp);
     if (server.rdb_checksum)
     rdb.update_cksum = rioGenericUpdateChecksum;
     snprintf(magic,sizeof(magic),"REDIS%04d",REDIS_RDB_VERSION);
     if (rdbWriteRaw(&rdb,magic,9) == -1) goto werr;
    
     for (j = 0; j < server.dbnum; j++) {
     redisDb *db = server.db+j;
     dict *d = db->dict;
     if (dictSize(d) == 0) continue;
     di = dictGetSafeIterator(d);
     if (!di) {
     fclose(fp);
     return REDIS_ERR;
     }
    
     /* Write the SELECT DB opcode */
     if (rdbSaveType(&rdb,REDIS_RDB_OPCODE_SELECTDB) == -1) goto werr;
     if (rdbSaveLen(&rdb,j) == -1) goto werr;
    
     /* Iterate this DB writing every entry */
     while((de = dictNext(di)) != NULL) {
     sds keystr = dictGetKey(de);
     robj key, *o = dictGetVal(de);
     long long expire;
    
     initStaticStringObject(key,keystr);
     expire = getExpire(db,&key);
     if (rdbSaveKeyValuePair(&rdb,&key,o,expire,now) == -1) goto werr;
     }
     dictReleaseIterator(di);
     }
     di = NULL; /* So that we don't release it again on error. */
    
     /* EOF opcode */
     if (rdbSaveType(&rdb,REDIS_RDB_OPCODE_EOF) == -1) goto werr;
    
     /* CRC64 checksum. It will be zero if checksum computation is disabled, the
     * loading code skips the check in this case. */
     cksum = rdb.cksum;
     memrev64ifbe(&cksum);
     if (rioWrite(&rdb,&cksum,8) == 0) goto werr;
    
     /* Make sure data will not remain on the OS's output buffers */
     if (fflush(fp) == EOF) goto werr;
     if (fsync(fileno(fp)) == -1) goto werr;
     if (fclose(fp) == EOF) goto werr;
    
     /* Use RENAME to make sure the DB file is changed atomically only
     * if the generate DB file is ok. */
     if (rename(tmpfile,filename) == -1) {
     redisLog(REDIS_WARNING,"Error moving temp DB file on the final destination: %s", strerror(errno));
     unlink(tmpfile);
     return REDIS_ERR;
     }
     redisLog(REDIS_NOTICE,"DB saved on disk");
     server.dirty = 0;
     server.lastsave = time(NULL);
     server.lastbgsave_status = REDIS_OK;
     return REDIS_OK;
    
    werr:
     fclose(fp);
     unlink(tmpfile);
     redisLog(REDIS_WARNING,"Write error saving DB on disk: %s", strerror(errno));
     if (di) dictReleaseIterator(di);
     return REDIS_ERR;
    }

    2.rdbSaveBackground中,如果子進程調用rdbsave返回REDIS_ERR,那么子進程exit(1)

    int rdbSaveBackground(char *filename) {
     pid_t childpid;
     long long start;
    
     if (server.rdb_child_pid != -1) return REDIS_ERR;
    
     server.dirty_before_bgsave = server.dirty;
     server.lastbgsave_try = time(NULL);
    
     start = ustime();
     if ((childpid = fork()) == 0) {
     int retval;
    
     /* Child */
     closeListeningSockets(0);
     redisSetProcTitle("redis-rdb-bgsave");
     retval = rdbSave(filename);
     if (retval == REDIS_OK) {
     size_t private_dirty = zmalloc_get_private_dirty();
    
     if (private_dirty) {
     redisLog(REDIS_NOTICE,
     "RDB: %zu MB of memory used by copy-on-write",
     private_dirty/(1024*1024));
     }
     }
     exitFromChild((retval == REDIS_OK) ? 0 : 1); //進程退出時返回0/1
     } else {
     /* Parent */
     server.stat_fork_time = ustime()-start;
     if (childpid == -1) {
     server.lastbgsave_status = REDIS_ERR;
     redisLog(REDIS_WARNING,"Can't save in background: fork: %s",
     strerror(errno));
     return REDIS_ERR;
     }
     redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid);
     server.rdb_save_time_start = time(NULL);
     server.rdb_child_pid = childpid;
     updateDictResizePolicy();
     return REDIS_OK;
     }
     return REDIS_OK; /* unreached */
    }
    3.bgsave完成后,serverCron中得到bgsave子進程的返回碼進行后續處理
     /* Check if a background saving or AOF rewrite in progress terminated. */
     if (server.rdb_child_pid != -1 || server.aof_child_pid != -1) {
     int statloc;
     pid_t pid;
    
     if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) {
     int exitcode = WEXITSTATUS(statloc);
     int bysignal = 0;
    
     if (WIFSIGNALED(statloc)) bysignal = WTERMSIG(statloc);
    
     if (pid == server.rdb_child_pid) {
     backgroundSaveDoneHandler(exitcode,bysignal); //根據bgsave子進程的exitcode以及是否由信號結束的標簽進行后續處理
     } else if (pid == server.aof_child_pid) {
     backgroundRewriteDoneHandler(exitcode,bysignal);
     } else {
     redisLog(REDIS_WARNING,
     "Warning, detected child with unmatched pid: %ld",
     (long)pid);
     }
     updateDictResizePolicy();
     }
     }
    4.如果子進程非信號結束,并且exitcode非0,那么設置bgsave狀態為REDIS_ERR
    void backgroundSaveDoneHandler(int exitcode, int bysignal) {
     if (!bysignal && exitcode == 0) {
     redisLog(REDIS_NOTICE,
     "Background saving terminated with success");
     server.dirty = server.dirty - server.dirty_before_bgsave;
     server.lastsave = time(NULL);
     server.lastbgsave_status = REDIS_OK;
     } else if (!bysignal && exitcode != 0) {
     redisLog(REDIS_WARNING, "Background saving error");
     server.lastbgsave_status = REDIS_ERR; //狀態轉換
     } else {
     mstime_t latency;
    
     redisLog(REDIS_WARNING,
     "Background saving terminated by signal %d", bysignal);
     latencyStartMonitor(latency);
     rdbRemoveTempFile(server.rdb_child_pid);
     latencyEndMonitor(latency);
     latencyAddSampleIfNeeded("rdb-unlink-temp-file",latency);
     /* SIGUSR1 is whitelisted, so we have a way to kill a child without
     * tirggering an error conditon. */
     if (bysignal != SIGUSR1)
     server.lastbgsave_status = REDIS_ERR;
     }
     server.rdb_child_pid = -1;
     server.rdb_save_time_last = time(NULL)-server.rdb_save_time_start;
     server.rdb_save_time_start = -1;
     /* Possibly there are slaves waiting for a BGSAVE in order to be served
     * (the first stage of SYNC is a bulk transfer of dump.rdb) */
     updateSlavesWaitingBgsave((!bysignal && exitcode == 0) ? REDIS_OK : REDIS_ERR);
    }
    5.processCommand中判定cmd是寫操作的話,直接返回REDIS_OK
     /* Don't accept write commands if there are problems persisting on disk
     * and if this is a master instance. */
     if (((server.stop_writes_on_bgsave_err &&
     server.saveparamslen > 0 &&
     server.lastbgsave_status == REDIS_ERR) ||
     server.aof_last_write_status == REDIS_ERR) &&
     server.masterhost == NULL &&
     (c->cmd->flags & REDIS_CMD_WRITE ||
     c->cmd->proc == pingCommand))
     {
     flagTransaction(c);
     if (server.aof_last_write_status == REDIS_OK)
     addReply(c, shared.bgsaveerr);
     else
     addReplySds(c,
     sdscatprintf(sdsempty(),
     "-MISCONF Errors writing to the AOF file: %s\r\n",
     strerror(server.aof_last_write_errno)));
     return REDIS_OK;
     }
    6.luaRedisGenericCommand中判定cmd是寫操作的話,屏蔽
     /* Write commands are forbidden against read-only slaves, or if a
     * command marked as non-deterministic was already called in the context
     * of this script. */
     if (cmd->flags & REDIS_CMD_WRITE) {
     if (server.lua_random_dirty) {
     luaPushError(lua,
     "Write commands not allowed after non deterministic commands");
     goto cleanup;
     } else if (server.masterhost && server.repl_slave_ro &&
     !server.loading &&
     !(server.lua_caller->flags & REDIS_MASTER))
     {
     luaPushError(lua, shared.roslaveerr->ptr);
     goto cleanup;
     } else if (server.stop_writes_on_bgsave_err &&
     server.saveparamslen > 0 &&
     server.lastbgsave_status == REDIS_ERR)
     {
     luaPushError(lua, shared.bgsaveerr->ptr);
     goto cleanup;
     }
     }
    
    cleanup:
     /* Clean up. Command code may have changed argv/argc so we use the
     * argv/argc of the client instead of the local variables. */
     for (j = 0; j < c->argc; j++) {
     robj *o = c->argv[j];
    
     /* Try to cache the object in the cached_objects array.
     * The object must be small, SDS-encoded, and with refcount = 1
     * (we must be the only owner) for us to cache it. */
     if (j < LUA_CMD_OBJCACHE_SIZE &&
     o->refcount == 1 &&
     o->encoding == REDIS_ENCODING_RAW &&
     sdslen(o->ptr) <= LUA_CMD_OBJCACHE_MAX_LEN)
     {
     struct sdshdr *sh = (void*)(((char*)(o->ptr))-(sizeof(struct sdshdr)));
    
     if (cached_objects[j]) decrRefCount(cached_objects[j]);
     cached_objects[j] = o;
     cached_objects_len[j] = sh->free + sh->len;
     } else {
     decrRefCount(o);
     }
     }
    
     if (c->argv != argv) {
     zfree(c->argv);
     argv = NULL;
     }
    
     if (raise_error) {
     /* If we are here we should have an error in the stack, in the
     * form of a table with an "err" field. Extract the string to
     * return the plain error. */
     lua_pushstring(lua,"err");
     lua_gettable(lua,-2);
     return lua_error(lua);
     }
     return 1; 

    聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

    硬盤寫滿后redis的處理機制

    硬盤寫滿后redis的處理機制:前些天一臺redis機器硬盤寫滿了,主要是由于程序bug導致備份量激增,而恰好監控程序的通知機制也罷工了,于是第一次體驗到了redis的罷工(只讀不寫)。 現在我們來看下在磁盤寫滿后redis的處理機制: save流程:serverCron-rdbSaveBackgroun
    推薦度:
    標簽: 硬盤 處理 解決
    • 熱門焦點

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 全国精品一区二区在线观看| 久久久精品人妻无码专区不卡| 国产精品成人观看视频| 亚洲一区二区三区在线观看精品中文 | 94久久国产乱子伦精品免费| 久久精品国产亚洲av麻豆小说| 四虎影院国产精品| 狠狠精品干练久久久无码中文字幕 | 免费短视频软件精品一区二区| 国产精品手机在线| 热RE99久久精品国产66热| 无码国内精品人妻少妇蜜桃视频| 久久99精品久久久久久9蜜桃| 一区二区三区精品| 国产成人精品免费视频动漫 | 精品人妻无码专区中文字幕 | 国内精品久久久久久久涩爱 | 亚洲欧美日韩精品久久亚洲区| 久久久久国产精品嫩草影院| 隔壁老王国产在线精品| 欧美国产日本精品一区二区三区| 8AV国产精品爽爽ⅴa在线观看| 国内精品久久久久影院日本| 欧美精品v欧洲精品| 亚洲精品国产精品乱码在线观看| 亚洲А∨精品天堂在线| 欧美精品福利在线视频 | 久久这里只有精品久久| 久久96国产精品久久久| 久久精品国内一区二区三区| 精品一区二区三区四区| 久久久精品午夜免费不卡| 欧美高清在线精品一区| 亚洲视频精品在线| 日韩一级精品视频在线观看| 国产精品嫩草视频永久网址| 久久精品草草草| 日韩精品www| 国产午夜精品理论片| 国内精品国产成人国产三级| 日韩精品成人a在线观看|