1. 程式人生 > >Redis的appendfsync參數詳解

Redis的appendfsync參數詳解

edi err handle tab 全局對象 ext 其它 form already

redis.conf中的appendfysnc是對redis性能有重要影響的參數之一。可取三種值:alwayseverysecno

設置為always時,會極大消弱Redis的性能,因為這種模式下每次write後都會調用fsyncLinux為調用fdatasync)。

如果設置為no,則write後不會有fsync調用,由操作系統自動調度刷磁盤,性能是最好的。

everysec為最多每秒調用一次fsync,這種模式性能並不是很糟糕,一般也不會產生毛刺,這歸功於Redis引入了BIO線程,所有fsync操作都異步交給了BIO線程。

另外,Redis在處理一條命令時,並不立即調用write

AOF文件,只是將數據寫入到AOF bufferserver.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;

}

}

Redis的appendfsync參數詳解