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; } } |