Redis 持久化 筆記

接觸redis並不久,作項目的時候,也大概的操做罷了,好比set,get..~等等的基礎操做,大概小嘍囉是夠用了java

最近大佬問我,你的redis數據有作持久化嗎?redis

個人想法..~ 設置了有效時間的key是未持久化的,永久的key就是持久化的數據庫

大佬一個勁的在嘲笑,尷尬... 偷偷笑,有我這麼想.確定還有人起步也這麼認爲的,哈哈哈數組

因而學習一下redis 持久化相關知識安全

Redis之因此速度這麼快,是由於Redis是基於內存的數據庫,進行讀寫操做時,redis都會在內存中完成,而後定時的刷新到磁盤中去,RDB和AOF就是兩種持久化內存中數據的方式bash

在硬盤中數據是持久化的,重啓機子也會存在服務器

在內存中數據不是持久化的,重啓機子就沒了網絡

根據一段本身寫的redis操做的代碼來學習,這邊使用的是Jedis(Java鏈接開發工具),來一段最簡單的setapp

/**
     * set 字節數組
     *
     * @param key   字節key
     * @param value 字節value
     * @return OK
     */
    public String set(byte[] key, byte[] value) {
        Jedis jedis = null;
        String result = null;
        try {
            jedis = getJedis();
            result = jedis.set(key, value);
        } catch (Exception e) {
            log.error("set byte[] key:{} value:{} error", key, value, e);
        } finally {
            returnSource(jedis);
        }
        return result;
    }

快照存儲 RDB(redis db)

redis 會把自身的數據以文件形式保存到硬盤中一份,在服務器重啓以後會自動把硬盤數據恢復到內存中
操做是一次性把redis中所有的數據保存一份到硬盤中,因此若是數據大的話,不太適合頻繁進行該操做async

默認文件名dump.rdb  能夠在redis.conf中設置

有三種方式觸發快照

第1種. redis客戶端發送的save命令進行快照,會阻塞(代碼中須要調用jedis.save()的方法實現)

阻塞redis服務器的進程,直到RDB文件建立完,在該段時間內,redis不能處理其餘的命令

第2種. redis客戶端發送的bgsave命令,不阻塞(代碼中須要調用jedis.bgsave()的方法實現)
實際執行過程:

  1. 客戶端bgsave命令
  2. 服務端返回ok
  3. 服務端fork建立一個子進程來執行備份
  4. 子進程執行完以後通知redis

主進程和子進程是同時存在的, 不會阻塞redis服務器進程, 建立子進程會消耗額外的內存,因此bgsave比save要慢

第3種. redis根據redis.conf中的配置自動執行bgsave

save 900 1           #900秒以內修改了1次,則執行  
save 300 10          #300秒以內修改了10次,則執行    
save 60 10000        #60秒以內修改了10000次,則執行

服務器每次執行以後,爲實現自動持久化而設置的時間計數器和次數計數器就會清零,從新計算

在redis命令執行config get save查看redis的save配置

可用jedis.lastsave()命令查看生成RDB文件是否成功, 返回上次成功保存到磁盤的unix時間戳(save和bgsave都會修改時間) ,RDB文件每次都是覆蓋,須要控制備份的話,要定時定點另存備份

從上面學習過程當中,得出主動方式應該選擇使用bgsave的方式來持久化

public void bgsave() {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            jedis.bgsave();
        } catch (Exception e) {
            log.error("bgsave error", e);
        } finally {
            returnSource(jedis);
        }
    }

給本身的工具類加個bgsave持久化方法,另外嘗試過程過遇到若是在一個Java方法中調兩次save或者bgsave是會報錯的,因此持久化單提出來,可能一個方法有好幾個redis操做

總結:
1.bgsave子線程建立RDB文件,不會對redis服務器性能形成大的影響
2.快照生成的RDB文件是一種壓縮的二進制文件,能夠方便的在網絡中傳輸和保存
3.在一次備份完RDB以後產生了新數據,但還未到達另外一次生成RDB文件的條件,這時redis服務器宕機,那麼新的數據會丟失掉
4.數據量大的時,觸發RDB持久化,包括建立子線程和生成RDB文件會佔很多系統資源和時間,會對redis產生影響

持久化AOF(append only file)

把操做執行的每一個指令都備份到aof文件中,還原數據的時候執行指令 , 每次在後面追加

aop重寫(不阻塞), redis.conf對應 appendonly yes 開啓aof

appendfilename "appendonly.aof"   //備份文件名
appendfsync always    //每次收到寫命令就當即寫入磁盤,最慢的方式,可是保證徹底的持久化
appendfsync everysec   //每秒鐘強烈寫入磁盤一次,在性能和持久化方面很好的折中,默認 
appendfsync no  //不一樣步到硬盤,由操做系統來決定

aof生成過程三個步驟:redis在執行完一個寫命令後,把執行的命令追加到redis內部的aof_buf緩衝區末尾

調用調用fsync函數, 緩衝區的寫命令會被寫入到 AOF 文件, 完成同步

在目前操做系統裏,執行系統調用write函數,將一些內容寫入到某個文件時, 先將內容放入一個內存緩衝區(buffer)裏面,等到緩衝區被填滿,或者用戶執行fsync調用和fdatasync調用時纔將存儲在緩衝區裏面的內容真正的寫入到硬盤裏,那麼在這個過程當中出問題了,數據是否就丟了?!

總結:

使用 AOF 持久化會讓 Redis 變得很是耐久:你能夠設置不一樣的 fsync策略,好比無 fsync,每秒鐘一次 fsync ,或者每次執行寫入命令時 fsync 。 AOF 的默認策略爲每秒鐘 fsync一次,在這種配置下,Redis 仍然能夠保持良好的性能,而且就算髮生故障停機,也最多隻會丟失一秒鐘的數據

aof文件由於某些緣由而包含了未寫入完整的命令redis-check-aof 工具也能夠輕易地修復這種問題

Redis 能夠在 AOF 文件體積變得過大時,自動地在後臺對 AOF 進行重寫: 重寫後的新 AOF 文件包含了恢復當前數據集所需的最小命令集合。 整個重寫操做是絕對安全的,由於 Redis 在建立新 AOF 文件的過程當中,會繼續將命令追加到現有的 AOF 文件裏面,即便重寫過程當中發生停機,現有的 AOF 文件也不會丟失。 而一旦新 AOF 文件建立完畢,Redis 就會從舊 AOF 文件切換到新 AOF 文件,並開始對新 AOF 文件進行追加操做
AOF文件可讀性交強,也可手動操做寫命令
AOF文件比RDB文件較大
官方文檔也指出,在某些狀況下,AOF的確也存在一些bug,好比使用阻塞命令時,這些bug的場景RDB是不存在的

------------------------------------