内容简介:本来今天想写点别的,但是心想之前一篇既然已经提到持久化这边了,而且也说了之后会讲到,索性,今天就说说这个。所谓持久化,就是将内存中的内容同步到磁盘当中,redis提供了两种持久化机制:aof和rdb。今天的主角是aof。aof持久化将被执行的命令写到AOF的末尾,以此来记录数据发生的变化,它一共有三个配置选项,在redis.conf这个配置文件中,具体如下:
本来今天想写点别的,但是心想之前一篇既然已经提到持久化这边了,而且也说了之后会讲到,索性,今天就说说这个。
所谓持久化,就是将内存中的内容同步到磁盘当中,redis提供了两种持久化机制:aof和rdb。今天的主角是aof。
aof持久化将被执行的命令写到AOF的末尾,以此来记录数据发生的变化,它一共有三个配置选项,在redis.conf这个配置文件中,具体如下:
点击( 此处 )折叠或打开
- #
- # If unsure , use "everysec" .
- # appendfsync always
- appendfsync everysec
- # appendfsync no
其意义也比较明显了,就不再多说了。
redis开启aof的开关代码如下:
点击( 此处 )折叠或打开
- / * Called when the user switches from "appendonly no" to "appendonly yes"
- * at runtime using the CONFIG command . * /
- int startAppendOnly ( void ) {
- char cwd [ MAXPATHLEN ] ; / * Current working dir path for error messages . * /
- int newfd ;
- newfd = open ( server . aof_filename , O_WRONLY | O_APPEND | O_CREAT , 0644 ) ;
- serverAssert ( server . aof_state = = AOF_OFF ) ;
- if ( newfd = = - 1 ) {
- char * cwdp = getcwd ( cwd , MAXPATHLEN ) ;
- serverLog ( LL_WARNING ,
- "Redis needs to enable the AOF but can't open the "
- "append only file %s (in server root dir %s): %s" ,
- server . aof_filename ,
- cwdp ? cwdp : "unknown" ,
- strerror ( errno ) ) ;
- return C_ERR ;
- }
- if ( server . rdb_child_pid ! = - 1 ) {
- server . aof_rewrite_scheduled = 1 ;
- serverLog ( LL_WARNING , "AOF was enabled but there is already a child process saving an RDB file on disk. An AOF background was scheduled to start when possible." ) ;
- } else {
- / * If there is a pending AOF rewrite , we need to switch it off and
- * start a new one : the old one cannot be reused becuase it is not
- * accumulating the AOF buffer . * /
- if ( server . aof_child_pid ! = - 1 ) {
- serverLog ( LL_WARNING , "AOF was enabled but there is already an AOF rewriting in background. Stopping background AOF and starting a rewrite now." ) ;
- killAppendOnlyChild ( ) ;
- }
- if ( rewriteAppendOnlyFileBackground ( ) = = C_ERR ) {
- close ( newfd ) ;
- serverLog ( LL_WARNING , "Redis needs to enable the AOF but can't trigger a background AOF rewrite operation. Check the above logs for more info about the error." ) ;
- return C_ERR ;
- }
- }
- / * We correctly switched on AOF , now wait for the rewrite to be complete
- * in order to append data on disk . * /
- server . aof_state = AOF_WAIT_REWRITE ;
- server . aof_last_fsync = server . unixtime ;
- server . aof_fd = newfd ;
- return C_OK ;
- }
aof写的代码如下:
点击( 此处 )折叠或打开
- ssize_t aofWrite ( int fd , const char * buf , size_t len ) {
- ssize_t nwritten = 0 , totwritten = 0 ;
- while ( len ) {
- nwritten = write ( fd , buf , len ) ;
- if ( nwritten < 0 ) {
- if ( errno = = EINTR ) {
- continue ;
- }
- return totwritten ? totwritten : - 1 ;
- }
- len - = nwritten ;
- buf + = nwritten ;
- totwritten + = nwritten ;
- }
- return totwritten ;
- }
将aof的缓冲区(将aof选项置为 everysec的时候,中间会有缓冲),写入磁盘的代码如下,其中需要判断后台是否有fsync正在执行(如果正在执行,会阻塞write调用),如果有,则会延迟,但是如果force参数被设置的话,就啥都不管不顾了,直接开整~
点击( 此处 )折叠或打开
- #define AOF_WRITE_LOG_ERROR_RATE 30 / * Seconds between errors logging . * /
- void flushAppendOnlyFile ( int force ) {
- ssize_t nwritten ;
- int sync_in_progress = 0 ;
- mstime_t latency ;
- if ( sdslen ( server . aof_buf ) = = 0 ) return ;
- if ( server . aof_fsync = = AOF_FSYNC_EVERYSEC )
- sync_in_progress = bioPendingJobsOfType ( BIO_AOF_FSYNC ) ! = 0 ;//bio有讲过
- if ( server . aof_fsync = = AOF_FSYNC_EVERYSEC & & ! force ) {
- / * With this append fsync policy we do background fsyncing .
- * If the fsync is still in progress we can try to delay
- * the write for a couple of seconds . * /
- if ( sync_in_progress ) {
- if ( server . aof_flush_postponed_start = = 0 ) {
- / * No previous write postponing , remember that we are
- * postponing the flush and return . * /
- server . aof_flush_postponed_start = server . unixtime ;
- return ;
- } else if ( server . unixtime - server . aof_flush_postponed_start < 2 ) {
- / * We were already waiting for fsync to finish , but for less
- * than two seconds this is still ok . Postpone again . * /
- return ;
- }
- / * Otherwise fall trough , and go write since we can ' t wait
- * over two seconds . * /
- server . aof_delayed_fsync + + ;
- serverLog ( LL_NOTICE , "Asynchronous AOF fsync is taking too long (disk is busy?). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis." ) ;
- }
- }
- / * We want to perform a single write . This should be guaranteed atomic
- * at least if the filesystem we are writing is a real physical one .
- * While this will save us against the server being killed I don ' t think
- * there is much to do about the whole server stopping for power problems
- * or alike * /
- latencyStartMonitor ( latency ) ;
- nwritten = aofWrite ( server . aof_fd , server . aof_buf , sdslen ( server . aof_buf ) ) ;
- latencyEndMonitor ( latency ) ;
- / * We want to capture different events for delayed writes :
- * when the delay happens with a pending fsync , or with a saving child
- * active , and when the above two conditions are missing .
- * We also use an additional event name to save all samples which is
- * useful for graphing / monitoring purposes . * /
- if ( sync_in_progress ) {
- latencyAddSampleIfNeeded ( "aof-write-pending-fsync" , latency ) ;
- } else if ( server . aof_child_pid ! = - 1 | | server . rdb_child_pid ! = - 1 ) {
- latencyAddSampleIfNeeded ( "aof-write-active-child" , latency ) ;
- } else {
- latencyAddSampleIfNeeded ( "aof-write-alone" , latency ) ;
- }
- latencyAddSampleIfNeeded ( "aof-write" , latency ) ;
- / * We performed the write so reset the postponed flush sentinel to zero . * /
- server . aof_flush_postponed_start = 0 ;
- if ( nwritten ! = ( ssize_t ) sdslen ( server . aof_buf ) ) {
- static time_t last_write_error_log = 0 ;
- int can_log = 0 ;
- / * Limit logging rate to 1 line per AOF_WRITE_LOG_ERROR_RATE seconds . * /
- if ( ( server . unixtime - last_write_error_log ) > AOF_WRITE_LOG_ERROR_RATE ) {
- can_log = 1 ;
- last_write_error_log = server . unixtime ;
- }
- / * Log the AOF write error and record the error code . * /
- if ( nwritten = = - 1 ) {
- if ( can_log ) {
- serverLog ( LL_WARNING , "Error writing to the AOF file: %s" ,
- strerror ( errno ) ) ;
- server . aof_last_write_errno = errno ;
- }
- } else {
- if ( can_log ) {
- serverLog ( LL_WARNING , "Short write while writing to "
- "the AOF file: (nwritten=%lld, "
- "expected=%lld)" ,
- ( long long ) nwritten ,
- ( long long ) sdslen ( server . aof_buf ) ) ;
- }
- if ( ftruncate ( server . aof_fd , server . aof_current_size ) = = - 1 ) {
- if ( can_log ) {
- serverLog ( LL_WARNING , "Could not remove short write "
- "from the append-only file. Redis may refuse "
- "to load the AOF the next time it starts. "
- "ftruncate: %s" , strerror ( errno ) ) ;
- }
- } else {
- / * If the ftruncate ( ) succeeded we can set nwritten to
- * - 1 since there is no longer partial data into the AOF . * /
- nwritten = - 1 ;
- }
- server . aof_last_write_errno = ENOSPC ;
- }
- / * 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 {
- / * Recover from failed write leaving data into the buffer . However
- * set an error to stop accepting writes as long as the error
- * condition is not cleared . * /
- server . aof_last_write_status = C_ERR ;
- / * Trim the sds buffer if there was a partial write , and there
- * was no way to undo it with ftruncate ( 2 ) . * /
- if ( nwritten > 0 ) {
- server . aof_current_size + = nwritten ;
- sdsrange ( server . aof_buf , nwritten , - 1 ) ;
- }
- 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 . * /
- if ( server . aof_last_write_status = = C_ERR ) {
- serverLog ( LL_WARNING ,
- "AOF write error looks solved, Redis can write again." ) ;
- server . aof_last_write_status = C_OK ;
- }
- }
- server . aof_current_size + = nwritten ;
- / * Re - use AOF buffer when it is small enough . The maximum comes from the
- * arena size of 4k minus some overhead ( but is otherwise arbitrary ) . * /
- if ( ( sdslen ( server . aof_buf ) + sdsavail ( server . aof_buf ) ) < 4000 ) {
- sdsclear ( server . aof_buf ) ;
- } else {
- sdsfree ( server . aof_buf ) ;
- server . aof_buf = sdsempty ( ) ;
- }
- / * Don ' t fsync if no - appendfsync - on - rewrite is set to yes and there are
- * children doing I / O in the background . * /
- if ( server . aof_no_fsync_on_rewrite & &
- ( server . aof_child_pid ! = - 1 | | server . rdb_child_pid ! = - 1 ) )
- return ;
- / * Perform the fsync if needed . * /
- if ( server . aof_fsync = = AOF_FSYNC_ALWAYS ) {
- / * aof_fsync is defined as fdatasync ( ) for Linux in order to avoid
- * flushing metadata . * /
- latencyStartMonitor ( latency ) ;
- aof_fsync ( server . aof_fd ) ; / * Let ' s try to get this data on the disk * /
- latencyEndMonitor ( latency ) ;
- latencyAddSampleIfNeeded ( "aof-fsync-always" , latency ) ;
- server . aof_last_fsync = server . unixtime ;
- } else if ( ( server . aof_fsync = = AOF_FSYNC_EVERYSEC & &
- server . unixtime > server . aof_last_fsync ) ) {
- if ( ! sync_in_progress ) aof_background_fsync ( server . aof_fd ) ;
- server . aof_last_fsync = server . unixtime ;
- }
- }
另一个需要注意的点就是BGREWRITEAOF命令会重写AOF文件,使AOF文件尽可能的小,其中的大部分操作都是尽可能的使用占用空间小的内存类型,在此不再赘述了。在此期间的命令缓存是通过如下机制实现的。
1. 使用多个缓存block而非一整块大缓存,每个block10M,如下所示
点击( 此处 )折叠或打开
- #define AOF_RW_BUF_BLOCK_SIZE ( 1024 * 1024 * 10 ) / * 10 MB per block * /
- typedef struct aofrwblock {
- unsigned long used , free ;
- char buf [ AOF_RW_BUF_BLOCK_SIZE ] ;
- } aofrwblock ;
2. 向缓存中写数据的时候是先找到当前链表的最后一个元素,若满足,直接写,若不满足,填上空缺,重新建,继续写
点击( 此处 )折叠或打开
- / * Append data to the AOF rewrite buffer , allocating new blocks if needed . * /
- void aofRewriteBufferAppend ( unsigned char * s , unsigned long len ) {
- listNode * ln = listLast ( server . aof_rewrite_buf_blocks ) ;
- aofrwblock * block = ln ? ln - > value : NULL ;
- while ( len ) {
- / * If we already got at least an allocated block , try appending
- * at least some piece into it . * /
- if ( block ) {
- unsigned long thislen = ( block - > free < len ) ? block -
以上所述就是小编给大家介绍的《redis源码阅读之aof》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 【源码阅读】AndPermission源码阅读
- 【源码阅读】Gson源码阅读
- 如何阅读Java源码 ,阅读java的真实体会
- 我的源码阅读之路:redux源码剖析
- JDK源码阅读(六):HashMap源码分析
- 如何阅读源码?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Ajax Design Patterns
Michael Mahemoff / O'Reilly Media / 2006-06-29 / USD 44.99
Ajax, or Asynchronous JavaScript and XML, exploded onto the scene in the spring of 2005 and remains the hottest story among web developers. With its rich combination of technologies, Ajax provides a s......一起来看看 《Ajax Design Patterns》 这本书的介绍吧!