Offer to come, dig friends take it! I am participating in the 2022 Spring Recruit Punch card activity. Click here for details.

The principle of

Redis provides RDB persistence, which can save Redis database state in memory to disk to avoid accidental data loss.

Trigger time: Manual or automatic.

Configuration is read

The RDB configuration in redis. Conf is as follows:

To enable this function, you need to set the parameter rdbcompression (enabled by default) in the configuration file. Dbfilename Specifies the RDB filename. This parameter is enabled by default to ensure data consistency. By default dump. RDB save <seconds> <changes> specifies the RDB trigger mechanism, indicating that the seconds change changes is triggeredCopy the code

Brew installation RDB file location for MAC system:

RDB file viewing

od -c dump.rdb

➜ redis od -c dump. RDB 0000000 R E D I S 00 9 372 \t R E D I S 0000020 - v E R 005 6  - b i t s 300 @ 372 005 c t i m e 313 0000060 313 x ' b 372 \b u s e d - m e m 302 300 0000100 B 020 \0 372 \f a o f - p r e a m b l 0000120 e 300 \0 376 \0 373 001 \0 370 " \0 003 m s g 300 0000140 001 377 9 3 235 231 R 251 \ N 0000152Copy the code

Manual trigger

Redis can perform SAVE and BGSAVE to manually trigger RDB persistence.

  • The SAVE command blocks the Redis server process until the RDB file is common.
  • BGSAVE does not block the server process, but creates a child process that creates the RDB file.

The RDB file is created by the rdb.c/rdbSave function.

/* Save the DB on disk. Return C_ERR on error, C_OK on success. */
int rdbSave(char *filename, rdbSaveInfo *rsi) {
    char tmpfile[256];
    char cwd[MAXPATHLEN]; /* Current working dir path for error messages. */
    FILE *fp = NULL;
    rio rdb;
    int error = 0;

    snprintf(tmpfile,256."temp-%d.rdb", (int) getpid());
    fp = fopen(tmpfile,"w");
    if(! fp) {char *cwdp = getcwd(cwd,MAXPATHLEN);
        serverLog(LL_WARNING,
            "Failed opening the RDB file %s (in server root dir %s) "
            "for saving: %s",
            filename,
            cwdp ? cwdp : "unknown",
            strerror(errno));
        return C_ERR;
    }

    rioInitWithFile(&rdb,fp);
    startSaving(RDBFLAGS_NONE);

    if (server.rdb_save_incremental_fsync)
        rioSetAutoSync(&rdb,REDIS_AUTOSYNC_BYTES);

    if (rdbSaveRio(&rdb,&error,RDBFLAGS_NONE,rsi) == C_ERR) {
        errno = error;
        goto werr;
    }

    /* Make sure data will not remain on the OS's output buffers */
    if (fflush(fp)) goto werr;
    if (fsync(fileno(fp))) goto werr;
    if (fclose(fp)) { fp = NULL; goto werr; }
    fp = NULL;
    
    /* Use RENAME to make sure the DB file is changed atomically only * if the generate DB file is ok. */
    if (rename(tmpfile,filename) == - 1) {
        char *cwdp = getcwd(cwd,MAXPATHLEN);
        serverLog(LL_WARNING,
            "Error moving temp DB file %s on the final "
            "destination %s (in server root dir %s): %s",
            tmpfile,
            filename,
            cwdp ? cwdp : "unknown",
            strerror(errno));
        unlink(tmpfile);
        stopSaving(0);
        return C_ERR;
    }

    serverLog(LL_NOTICE,"DB saved on disk");
    server.dirty = 0;
    server.lastsave = time(NULL);
    server.lastbgsave_status = C_OK;
    stopSaving(1);
    return C_OK;

// Error handling
werr:
    serverLog(LL_WARNING,"Write error saving DB on disk: %s", strerror(errno));
    if (fp) fclose(fp);
    unlink(tmpfile);
    stopSaving(0);
    return C_ERR;
}
Copy the code

Automatic trigger

Redis allows users to set the server configuration save option (in redis.conf) to have the server automatically execute BGSAVE commands at intervals.

The default configuration is as follows:

save 900 1
save 300 10
save 60 10000
Copy the code

The BGSAVE command is executed if any of the following three conditions are met:

  • The server made at least one change to the database within 900 seconds.
  • The server made at least 10 changes to the database within 300 seconds.
  • The server made at least 10,000 changes to the database within 60 seconds.

The saveParams property of the redisServer structure of the server state is set in the server according to the save conditions set by the Save option

struct redisServer {

	// Record the storage conditions
    struct saveparam *saveparams;   /* Save points array for RDB */
}

/ / saveparam definition
struct saveparam {
    time_t seconds;
    int changes;
};
Copy the code

conclusion

1. Redis provides manual and automatic ways to persist data, which is a compromise between performance and reliability.

In addition to the saveParams array, the server state also maintains a dirty counter and a lastSave property:

  • The dirty counter records how many changes (writes, deletes, updates, etc.) the server has made to the database state (all databases on the server) since the last SAVE or BGSAVE command was successfully executed.
  • The lastSave attribute is a UNIX timestamp that records the last time the server successfully executed the SAVE or BGSAVE command.
struct redisServer {

    // Modify the counter
    long long dirty;                /* Changes to DB from the last save */
    
    // Last saved time
    time_t lastsave;                /* Unix time of last successful save */
}
Copy the code

The Redis server periodic operation function serverCron is executed every 100 milliseconds by default. This function is used to maintain the running server. One of its jobs is to check whether the save conditions set by the save option have been met. The BGSAVE command is executed.

RDB structure

Legend:

  1. The fields in the pink box are fixed strings
  2. The fields in the green box are integers
  3. The purple box shows the expanded data
  4. The value type in the yellow box is an enumerated constant
  5. The blue box shows the actual stored key-value pair data