1. 程式人生 > >redis筆記2--資料持久化和叢集

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(哨兵):該工具可以自動檢測處理節點宕機的情況。