redis筆記2--數據持久化和集羣

數據持久化

數據持久化的用處:
1.恢復數據。
2.減少數據的運算,如:從關係型數據庫加載數據到redis後,redis服務重啓時不需要在去關係型數據庫獲取數據,直接讀取硬盤上的備份即可。

快照方式


記錄某個時刻的數據到硬盤上。

注意:快照這種方式,在上次快照保存後,下次快照保存之前,這之間寫入redis的數據,如果redis服務崩潰了,這部分數據會丟失

啓動快照的方法:

  • 在客戶端執行 bgsave命令,redis會新建一個子線程去保存快照,父線程繼續響應執行各個命令。
  • 客戶端執行 save 命令,阻塞式,redis會停止任何命令的執行,直到快照保存完成。一般我們沒有足夠的內存來執行bgsave或是允許等待save存儲快照完成的情況下執行該命令。
  • 配置文件中配置save 參數。如:save  60 10000 ,每分鐘至少10000次操作,redis會自動觸發bgsave操作。
  • redis服務器接收到了shutdown命令,redis會執行save命令,同時阻止客戶端再執行任何命令,然後關閉。
  • 如果redis服務器連接了另一個redis服務器,並且執行了sync命令,主機會執行bgsave 操作來備份數據。

幾種常見場景下的配置:

  • 開發環境(development)

作爲開發服務器,我們關心的是最小化快照的存儲。一般可以設置規則爲:save  900  1  。每15分鐘保存一次。

觸發保存快照的原則就是:不能觸發太頻繁,會耗費很多資源。也不能不觸發或觸發太少,容易丟失數據。

  • 記錄日誌(aggregating logs)

爲了恢復損失的數據,首先,我們需要知道我們丟失了什麼數據。因此我們要記錄操作信息到日誌中。假如我們有一個函數,每當新的日誌準備好處理時,就會調用這個函數。這個函數提供redis連接,日誌文件路徑,回調函數三個參數。在回調函數中,我們可以向日志中寫入操作記錄。(每次保存快照後,就新建一個日誌文件,記錄這次快照結束到下次快照保存之前這段時間內的操作記錄。)

通過記錄程序日誌,我們就可以在服務器宕機後及時恢復丟失的數據。因爲我們是pipeline中使用了事務控制,所以日誌文件中只會記錄執行完成的命令,不會記錄處理了一部分的信息。

  • 大數據(big data)

當我們存儲的數據上GB時,使用快照方式會比較合適。但是隨着內存佔用的持續增長,執行bgsave操作的時間也會持續增加。

如果redis用了10多GB的內存,導致沒有多餘的內存來執行bgsave命令。可能會造成系統停止等一系列問題(從而降低系統性能甚至造成系統不可用)。

爲了防止這種問題,我們需要停止自動保存快照功能,通過手動去調用save或是bgsave命令。如果是save命令,redis會阻塞直到快照保存完成。這種情況不會像bgsave一樣去創建子線程處理備份,這樣就不會有創建子線程的延遲,也不會有子線程和自己爭奪資源,所以save命令會更快速的完成備份工作。
作者經驗:

當redis服務器上有50GB數據時。使用bgsave命令,創建子線程需要花費大概15秒鐘或更久,然後保存快照需要大概15-20分鐘。如果是使用save命令,只需要3-5分鐘即可。

實際運用中,每天凌晨3:00保存一個快照。通過腳本去停止客戶端的連接,然後調用save命令去保存快照,保存完後再恢復客戶端連接。
總結:
當我們可以處理潛在的數據丟失時,使用快照很方便。但是如果我們不能容忍15min或1hr或更大量的數據丟失時,使用append-only file方式來持久化會是比較好的選擇。


AOF方式(append-only file)


每當有寫命令執行時,記錄命令到日誌文件中,當server重啓時,將這些寫操作重新執行一遍。這種方式會記錄每一次修改,最大限度保證數據的完整性。


這種方式,會記錄每一次的數據改動到日誌文件中,每次需要恢復數據,就將日誌記錄的信息從頭到尾再執行一遍。

通過設置appendonly  yes 參數

文件同步(File Syncing)

當將文件保存到硬盤上時,過程如下:

1.調用file.write()方法,將內容寫到緩存中。

2.調用file.flush(),將緩存中的數據刷新保存到硬盤。(程序只是發送一個寫磁盤的請求,具體有操作系統去執行,會阻塞。執行完後數據就保存在磁盤上了)。

appendfsync:參數配置

  • always:每次redis的寫命令都會觸發保存記錄到磁盤,可以保證最小的數據丟失,但是會影響redis性能(由於頻繁的io操作)。
  • everysec:每秒同步一次,明確同步寫命令到磁盤
  • no:讓操作系統控制同步到磁盤
作爲中和的選擇,可以設置爲everysec。在保證數據安全的同時也能提供一個不錯的性能。對大多數普通應用來說,每秒同步和不做持久化相比,這之間沒有多大的性能損失(即每秒同步不會造成明顯的性能損失)。

當硬盤跟不上寫入數據的速度時,redis會減緩寫入速度來適應硬件驅動的最大寫入效率。

no選項不建議使用。

這種情況下,完全交給操作系統處理,不會有性能上的損失,但是一旦發生宕機,丟失的數據我們無法獲取或預測。而且,如果我們用的硬盤寫入速度不夠快,redis會執行到緩存區寫滿了才刷新到硬盤,這會導致redis變慢,在向磁盤寫數據的時候也會阻塞。

append-only files 方式很靈活,缺點就是附件文件比較大。

重寫/壓縮aof文件

通過附加文件(append-only files)的方式,我們可以最小化數據丟失,並且最小化持久化數據到硬盤的時間。
但是隨着時間的推移,aof文件會持續增長。可能造成磁盤空間不足。更常見的是,當我們重啓redis服務器時,會重新執行aof日誌文件裏的命令,當aof文件很大時,啓動redis會花費很長時間。

爲了解決這個問題:
使用bgrewriteaof命令:會刪除重複的命令。執行方式域bgsave命令類似。
創建一個子線程,重寫附加文件(快照中的問題,子線程時間延遲,內存消耗同樣存在,並且更嚴重。因爲aof文件可能是快照文件dump的好幾倍)

當aof重寫時,操作系統需要刪除aof文件,刪除10多GB的文件會導致系統掛起數秒鐘。
配置文件方式調用重寫:
auto-aof-rewrite-percentage 100:表示當aof文件比上次增長了一倍(100%)時
auto-aof-rewrite-min-size  64mb:aof文件至少有64mb大

如果重寫太頻繁,可以適當調整參數(將100調大),儘管可能造成redis重啓花費更長時間。

如果允許,建議備份快照和最新的重寫的aof文件到其他服務器。

集羣

集羣在關係型數據庫中很常見,主機(master)發送寫數據到多個從機(slaves),從機執行所有的查詢命令。redis也採用了這種模式。
           雖然redis速度很快,但是任然有很多場景下,光單機的redis提供服務是不夠的。實際應用中,對set和zset集合的操作可能涉及成千上萬,甚至上百萬條數據。當涉及到上百萬條數據時,set集合的 操作會花費數秒。
            
            在主機向集羣中其他服務器發送初始化數據拷貝後,客戶端向主機寫入數據,都會同步更新到從機上。以後查詢都是通過負載均衡連接到其中的一個從機去查詢,而不是直接連接主機了。

集羣配置

當從機連接到主機時,主機會執行一個bgsave操作。爲了配置集羣,需要保證快照配置中的dir和dbfilename參數正確有效,且可讀。

儘管從機自己有很多控制狀態的配置選項,其中只有一個選項是真正需要的:slaveof  host  port。當redis啓動時,就會把這個地址的機器當作主機去連接。如果是一個運行中的系統,可以通過slaveof  host  port命令去操作。

slaveof  no  one :停止與主機的同步更新

集羣啓動過程

概述:當slave連接master時,master會立刻保存一個快照,然後發送給slave。
詳細步驟:

        在集羣中,redis會設法保持大多數的服務器同步,除了網絡帶寬不夠快的情況,或者是主機沒有足夠的內存空間來創建子線程進行快照保存,或是記錄積壓的寫命令的內存不夠。
        儘管不是必須,但是最好還是保證redis主機只用了系統50-65%的內存,預留出30-45%的備用內存空間來執行bgsave命令和記錄積壓命令(command backlogs)

slave的配置很簡單,可以在配置文件中配置slaveof host port,或是在運行的時候執行slaveof命令。
           如果用的是配置文件方式,redis在啓動初始化時就會先加載快照或aof文件,然後連接到主機執行上面表中的流程。如果是命令方式,redis會立刻連接主機,如果連接成功,就會執行上面表中的流程。
  • 同步過程中,slave會刷新所有的數據
就是爲了保證數據一致性:當slave連接到master時,任何當前內存中保存的數據都會被清除,替換成從master機器發送過來的數據。
  • 警告:redis不支持主機和主機之間的複製
有時候可能會出現下面這種配置:兩臺redis服務器相互做主從關係(都配置slaveof指向對方)。顯然這種配置是不起作用的。兩臺機器會來回通信,依賴於我們連接哪臺機器去查詢,可能會導致我們獲取的數據不一致或者根本獲取不到數據。

當多個slave嘗試去連接redis時,可能會有不同的情況發生


         對大多數情況,redis會保證只做必要的工作。某些情況下,slave會在不恰當的 時機去連接主機,這樣會導致主機做更多的工作。另一方面,多個slave在同時連接主機時,最初用來保證slave同步的帶寬會佔用很多資源,可能造成其他的命令很難通過,同時可能造成網絡速度變慢,影響同一網絡下的其他設備。

主/從服務器鏈(Master/slave chains)

        當我們去添加很多個slave節點時,會發現有時候網絡跟不上(尤其是在互聯網上或是兩個數據中心之間)。由於主機和從機之間沒有什麼區別,slave節點也可以有自己的slave節點,這樣就可以形成主/從服務器鏈
         當讀負載明顯高出寫負載時,或者是當讀數據的請求量超出了一個單機redis的處理範圍。常見的處理方法就是給主機添加從節點來分攤壓力。
         當負載持續增長時,總會有某一個時刻,單個的redis主機服務器無法及時同步數據到所有的slave節點(或者是在同步或連接是超載了)。爲了緩解這種問題,我們可以建立一個能夠進行主/從複製的中間層的redis節點,如下圖:

        說回aof數據備份方式,這種方式會同步所有的寫操作到硬盤中,以此防止數據的丟失,但是也嚴重限制了服務器的性能。或者設置成每秒同步一次,性能會好很多,但是可能丟失這一秒鐘內的數據。
        對於上面的問題,可以結合使用集羣複製和aof文件備份方式來解決上面的問題。
        爲了保證數據存放在多個機器的磁盤上,必須顯示的設置主機和從機。通過配置appendonly  yes和appendfsync  everysec兩個參數,可以使這組集羣機器每秒同步數據到硬盤。但是我們必須等待數據一一同步到各個從節點。

驗證硬盤寫操作(verifying disk writes)

要檢查寫入主節點的數據是否同步到了從節點很簡單,只需要在每次重要數據操作之後都輸出一個唯一的臨時文件,然後在slave節點上去驗證這個文件。

通過

        info

命令查看redis服務器的各個狀態信息

系統故障處理(handling system failures)

            如果我們將redis作爲我們應用的唯一數據庫,就必須保證我們永遠不丟失數據。不像傳統數據庫的4個特性:原子性(atomicity),一致性(consistency),隔離性(isolation)和持久性(durability)。redis需要做一些額外的工作來保證數據的一致性。

1.驗證快照和aof文件

         當系統崩潰時,我們有工具來幫助自己恢復數據。
redis-check-aof   :檢測aof文件的狀態
redis-check-dump    :檢測dump快照文件的狀態

          如果提供了--fix參數,命令就會修復這個參數指定的aof文件。通過掃描aof文件,查找未完成或錯誤的命令,從第一個錯誤的命令開始,丟棄後面所有的部分。
          目前沒有修復損壞的快照文件的工具,儘管我們同樣可以發現第一個錯誤命令發生的地方,但是因爲快照本身被壓縮了,中途錯誤可能導致文件不可讀取。由於這個原因,建議對重要的快照文件保留多個備份,在恢復的同時通過計算sha1和sha256來驗證內容。
         checksums  and  hashes:CRC family checksum適合發現網絡傳輸或磁盤損壞的錯誤。hash密碼適合發現任意的錯誤。

2.替換故障的主機(replacing a failed master)

場景:
          A機器跑了一個redis的master節點,B機器跑了一個slave節點。由於某些目前無法確定的原因,A機器失去了網絡連接。但是我們有一個C機器安裝了。
方案:
         B機器執行save命令,保存當前最新的快照文件,拷貝快照文件到C 機器的指定目錄。啓動C機器加載快照數據到內存中。告訴B機器去連接C機器,作爲其slave幾點。
  1. B機器執行save命令
  2. 拷貝dump.rdb到C機器的redis目錄下
  3. 啓動C機器
  4. B機器執行slaveof  host  port 指向C機器。
關鍵字:redis  sentinel(哨兵):該工具可以自動檢測處理節點宕機的情況。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章