Redis的appendfsync参数详解

redis.conf中的appendfysnc是对redis性能有重要影响的参数之一。可取三种值:always、everysec和no。

设置为always时,会极大消弱Redis的性能,因为这种模式下每次write后都会调用fsync(Linux为调用fdatasync)。

如果设置为no,则write后不会有fsync调用,由操作系统自动调度刷磁盘,性能是最好的。

everysec为最多每秒调用一次fsync,这种模式性能并不是很糟糕,一般也不会产生毛刺,这归功于Redis引入了BIO线程,所有fsync操作都异步交给了BIO线程。

 

另外,Redis在处理一条命令时,并不立即调用write写AOF文件,只是将数据写入到AOF buffer(server.aof_buf)中。调用write和命令处理是分开的,Redis只在每次进入epoll_wait之前做write操作。

/* Write the append only file buffer on disk.

 *

 * Since we are required to write the AOF before replying to the client,

 * and the only way the client socket can get a write is entering when the

 * the event loop, we accumulate all the AOF writes in a memory

 * buffer and write it on disk using this function just before entering

 * the event loop again.

 *

 * About the 'force' argument:

 *

 * When the fsync policy is set to 'everysec' we may delay the flush if there

 * is still an fsync() going on in the background thread, since for instance

 * on Linux write(2) will be blocked by the background fsync anyway.

 * When this happens we remember that there is some aof buffer to be

 * flushed ASAP, and will try to do that in the serverCron() function.

 *

 * However if force is set to 1 we'll write regardless of the background

 * fsync. */

#define AOF_WRITE_LOG_ERROR_RATE 30 /* Seconds between errors logging. */

void flushAppendOnlyFile(int force) {

    // aofWrite调用write将AOF buffer写入到AOF文件,处理了ENTR,其它没什么

    ssize_t nwritten = aofWrite(server.aof_fd,server.aof_buf,sdslen(server.aof_buf));

    。。。。。。

    /* Handle the AOF write error. */

    if (server.aof_fsync == AOF_FSYNC_ALWAYS) {

        /* We can't recover when the fsync policy is ALWAYS since the

         * reply for the client is already in the output buffers, and we

         * have the contract with the user that on acknowledged write data

         * is synced on disk. */

        serverLog(LL_WARNING,"Can't recover from AOF write error when the AOF fsync policy is 'always'. Exiting...");

        exit(1);

    } else {

        return; /* We'll try again on the next call... */

    } else {

        /* Successful write(2). If AOF was in error state, restore the

         * OK state and log the event. */

    }

    。。。。。。

    /* Perform the fsync if needed. */

    if (server.aof_fsync == AOF_FSYNC_ALWAYS) {

        // redis_fsync是一个宏,Linux实际为fdatasync,其它为fsync

        // 所以最好不要将redis.conf中的appendfsync设置为always,这极影响性能

        redis_fsync(server.aof_fd); /* Let's try to get this data on the disk */

    }

    else if ((server.aof_fsync == AOF_FSYNC_EVERYSEC && server.unixtime > server.aof_last_fsync)) {

        // 如果已在sync状态,则不再重复

        // BIO线程会间隔设置sync_in_progress

        // if (server.aof_fsync == AOF_FSYNC_EVERYSEC)

        //     sync_in_progress = bioPendingJobsOfType(BIO_AOF_FSYNC) != 0;

        if (!sync_in_progress)

            // eversec性能并不那么糟糕,因为它:

            // 后台方式执行fsync

            // Redis并不是严格意义上的单线程,实际上它创建一组BIO线程,专门处理阻塞和慢操作

            // 这些操作就包括FSYNC,另外还有关闭文件和内存的free两个操作。

            // 不像always,EVERYSEC模式并不立即调用fsync,

            // 而是将这个操作丢给了BIO线程异步执行,

            // BIO线程在进程启动时被创建,两者间通过bio_jobs和bio_pending两个

            // 全局对象交互,其中主线程负责写,BIO线程负责消费。

            aof_background_fsync(server.aof_fd);

        server.aof_last_fsync = server.unixtime;

    }

}

 

你可能感兴趣的:(C/C++,redis,Redis)