redis能保證數據100%不丟失嗎?


       我們都知道 Redis 的數據全部在內存里,如果突然宕機,數據就會全部丟失,因此必須有一種機制來保證 Redis 的數據不會因為故障而丟失,這種機制就是 Redis 的持久化機制。

        眾所周知,Redis 的持久化機制有兩種,第一種是快照RDB,第二種是 AOF 日志。快照是一次全量備份,AOF 日志是連續的增量備份。快照是內存數據的二進制序列化形式,在存儲上非常緊湊,基本一次五分鍾左右,而 AOF 日志記錄的是內存數據修改的指令記錄文本。AOF 日志在長期的運行過程中會變得無比龐大,數據庫重啟時需要加載 AOF 日志進行指令重放,這個時間就會無比漫長,所以需要定期進行 AOF 重寫,給 AOF 日志進行瘦身。

        那么,RDB或者AOF能否保證數據百分百不丟失?疑問的我在百度上搜了搜,發現很多博客都講,將appendfsync值設置為always就可以了。這回答讓我對《redis設計與實現》產生了懷疑。難道新版本的redis能夠保證數據100%不丟失?!

我們來看一下aof 設置always的源碼分析

         

void flushAppendOnlyFile(int force) {    
    if (sdslen(server.aof_buf) == 0) return;
    if (server.aof_fsync == AOF_FSYNC_EVERYSEC)
        sync_in_progress = bioPendingJobsOfType(BIO_AOF_FSYNC) != 0;
    if (server.aof_fsync == AOF_FSYNC_EVERYSEC && !force) {
        if (sync_in_progress) {
            if (server.aof_flush_postponed_start == 0) {
                server.aof_flush_postponed_start = server.unixtime;
                return;
            } else if (server.unixtime - server.aof_flush_postponed_start < 2) {
                return;
            }
            server.aof_delayed_fsync++;
        }
    }
    //將aof_buf中的內容寫入到aof文件
    nwritten = write(server.aof_fd,server.aof_buf,sdslen(server.aof_buf));
    server.aof_flush_postponed_start = 0;
    ……
    server.aof_current_size += nwritten;
    if ((sdslen(server.aof_buf)+sdsavail(server.aof_buf)) < 4000) {
        sdsclear(server.aof_buf);
    } else {
        sdsfree(server.aof_buf);
        server.aof_buf = sdsempty();
    }
    //appendfsync為no或者有后台進程在進行aof或rdb,不進行文件同步
    if (server.aof_no_fsync_on_rewrite &&
        (server.aof_child_pid != -1 || server.rdb_child_pid != -1))
            return;
    /* appendfsync為always */
    if (server.aof_fsync == AOF_FSYNC_ALWAYS) {/
        aof_fsync(server.aof_fd); //同步aof文件
        server.aof_last_fsync = server.unixtime;//記錄同步時間
    } else if ((server.aof_fsync == AOF_FSYNC_EVERYSEC &&
                server.unixtime > server.aof_last_fsync)) {
        /* appendfsync為EVERYSEC*/
        if (!sync_in_progress) aof_background_fsync(server.aof_fd);
        server.aof_last_fsync = server.unixtime;
    }
}
void aof_background_fsync(int fd) {
    bioCreateBackgroundJob(BIO_AOF_FSYNC,(void*)(long)fd,NULL,NULL);
}

        可以看到,在方法中,有if (server.aof_fsync == AOF_FSYNC_ALWAYS)的判斷,如果條件符合,會使用fdatasync()的方法來寫磁盤。

        大體就是:先把寫命令追加到aof buffer中,下一次進入事件循環循環后,再將buffer寫到磁盤上。結合while循環處方法的調用順序,可以看出確實是這樣的。那么也就是說,這次寫到磁盤上的內容是上一個事件循環產生的

        所以,即使設置為always,也會丟失一個循環的數據。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM