① Redis RDB持久化和AOF持久化詳細講解
Redis支持RDB和AOF兩種持久化機制,持久化功能有效地避免因進程退出造成的數據丟失問題,當下次重啟時利用之前持久化的文件即可實現數據恢復。Redis支持兩種方式的持久化,一種是RDB方式,一種是AOF方式。可以單獨使用其中一種或將二者結合使用。
RDB持久化是把當前進程數據生成快照保存到硬碟的過程,觸發RDB持久化過程分為手動觸發和自動觸發。
手動觸發分別對應save和bgsave命令:
自動觸發
除了執行命令手動觸發之外,Redis內部還存在自動觸發RDB的持久化機制。如以下場景:
1)使用save相關配置,如「save m n」。表示m秒內數據集存在n次修改時,自動觸發bgsave。
2)如果從節點執行全量復制操作,主節點自動執行bgsave生成RDB文件並發送給從節點
3)執行debug reload命令重新載入Redis時,也會自動觸發save操作。
4)默認情況下執行shutdown命令時,如果沒有開啟AOF持久化功能則自動執行bgsave。
bgsave是主流的觸發RDB持久化方式,它的運作流程如下圖:
1)執行bgsave命令,Redis父進程判斷當前是否存在正在執行的子進程,如RDB/AOF子進程,如果存在bgsave命令直接返回。
2)父進程執行fork操作創建子進程,fork操作過程中父進程會阻塞,通過info stats命令查看latest_fork_usec選項,可以獲取最近一個fork操作的耗時,單位為微秒。
3)父進程fork完成後,bgsave命令返回「Background saving started」信息並不再阻塞父進程,可以繼續響應其他命令。
4)子進程創建RDB文件,根據父進程內存生成臨時快照文件,完成後對原有文件進行原子替換。執行lastsave命令可以獲取最後一次生成RDB的時間,對應info統計的rdb_last_save_time選項。
5)進程發送信號給父進程表示完成,父進程更新統計信息。
保存:RDB文件保存在dir配置指定的目錄下,文件名通過dbfilename配置指定。可以通過執行config set dir{newDir}和config setdbfilename{newFileName}運行期動態執行,當下次運行時RDB文件會保存到新目錄。
壓縮:Redis默認採用LZF演算法對生成的RDB文件做壓縮處理,壓縮後的文件遠遠小於內存大小,默認開啟,可以通過參數config set rdbcompression{yes|no}動態修改。
校驗:如果Redis載入損壞的RDB文件時拒絕啟動,並列印如下日誌:
這時可以使用Redis提供的redis-check-mp工具檢測RDB文件並獲取對應的錯誤報告。
RDB的優點:
RDB的缺點:
AOF(append only file)持久化:以獨立日誌的方式記錄每次寫命令,重啟時再重新執行AOF文件中的命令達到恢復數據的目的。AOF的主要作用是解決了數據持久化的實時性,目前已經是Redis持久化的主流方式。
開啟AOF功能需要設置配置:appendonly yes,默認不開啟。AOF文件名通過appendfilename配置設置,默認文件名是appendonly.aof。保存路徑同RDB持久化方式一致,通過dir配置指定。
AOF的工作流程操作:命令寫入(append)、文件同步(sync)、文件重寫(rewrite)、重啟載入(load)。如下圖所示:
流程如下:
1)所有的寫入命令會追加到aof_buf(緩沖區)中。
2)AOF緩沖區根據對應的策略向硬碟做同步操作。
3)隨著AOF文件越來越大,需要定期對AOF文件進行重寫,達到壓縮的目的。
4)當Redis伺服器重啟時,可以載入AOF文件進行數據恢復。
AOF命令寫入的內容直接是文本協議格式,開啟AOF後,所有寫入命令都包含追加操作,直接採用文本協議格式,避免了二次處理開銷。
Redis提供了多種AOF緩沖區同步文件策略,由參數appendfsync控制。
always:命令寫入aof_buf後,調用系統ysnyc操作同步到AOF文件,ysnyc完成後線程返回。
everysec:命令寫入aof_buf後,調用系統write操作,write完成後線程返回。ysnyc同步文件操作由專門線程每秒調用一次。
no:命令寫入aof_buf後,調用系統write操作,不對AOF文件做ysnyc同步,同步硬碟操作由操作系統負責,通常同步周期最長30秒。
系統調用write和fsync說明:
Redis引入AOF重寫機制壓縮文件體積。AOF文件重寫是把Redis進程內的數據轉化為寫命令同步到新AOF文件的過程。
AOF重寫機制壓縮文件體積的原因:
1)進程內已經超時的數據不再寫入文件。
2)舊的AOF文件含有無效命令,重寫使用進程內數據直接生成,這樣新的AOF文件只保留最終數據的寫入命令。
3)多條寫命令可以合並為一個,為了防止單條命令過大造成客戶端緩沖區溢出,對於list、set、hash、zset等類型操作,以64個元素為界拆分為多條。
AOF重寫過程可以手動觸發和自動觸發:
auto-aof-rewrite-min-size:表示運行AOF重寫時文件最小體積,默認為64MB。auto-aof-rewrite-percentage:代表當前AOF文件空間(aof_current_size)和上一次重寫後AOF文件空間(aof_base_size)的比值。
自動觸發時機=aof_current_size>auto-aof-rewrite-min-size&&(aof_current_size-aof_base_size)/aof_base_size>=auto-aof-rewrite-percentage。其中aof_current_size和aof_base_size可以在info Persistence統計信息中查看。
AOF重寫流程:如下圖
流程說明:
1)執行AOF重寫請求。如果當前進程正在執行AOF重寫,請求不執行並返回如下響應:
如果當前進程正在執行bgsave操作,重寫命令延遲到bgsave完成之後再執行,返回如下響應:
2)父進程執行fork創建子進程,開銷等同於bgsave過程。
3.1)主進程fork操作完成後,繼續響應其他命令。所有修改命令依然寫入AOF緩沖區並根據appendfsync策略同步到硬碟,保證原有AOF機制正確性。
3.2)由於fork操作運用寫時復制技術,子進程只能共享fork操作時的內存數據。由於父進程依然響應命令,Redis使用「AOF重寫緩沖區」保存這部分新數據,防止新AOF文件生成期間丟失這部分數據。
4)子進程根據內存快照,按照命令合並規則寫入到新的AOF文件。每次批量寫入硬碟數據量由配置aof-rewrite-incremental-fsync控制,默認為32MB,防止單次刷盤數據過多造成硬碟阻塞。
5.1)新AOF文件寫入完成後,子進程發送信號給父進程,父進程更新統計信息,具體見info persistence下的aof_*相關統計。
5.2)父進程把AOF重寫緩沖區的數據寫入到新的AOF文件。
5.3)使用新AOF文件替換老文件,完成AOF重寫。
AOF和RDB文件都可以用於伺服器重啟時的數據恢復。Redis持久化文件載入流程如下圖:
流程說明:
1)AOF持久化開啟且存在AOF文件時,優先載入AOF文件,列印如下日誌:
2)AOF關閉或者AOF文件不存在時,載入RDB文件,列印如下日誌:
3)載入AOF/RDB文件成功後,Redis啟動成功。
4)AOF/RDB文件存在錯誤時,Redis啟動失敗並列印錯誤信息。
載入損壞的AOF文件時會拒絕啟動,並列印如下日誌:
對於錯誤格式的AOF文件,先進行備份,然後採用redis-check-aof--fix命令進行修復,修復後使用diff-u對比數據的差異,找出丟失的數據,有些可以人工修改補全。
AOF文件可能存在結尾不完整的情況,Redis為我們提供了aof-load-truncated配置來兼容這種情況,默認開啟。載入AOF時,當遇到此問題時會忽略並繼續啟動,同時列印如下警告日誌:
② 如何將redis中的數據持久化到資料庫中
1、
快照的方式持久化到磁碟
自動持久化規則配置
save
900
1
save
300
10
save
60
10000
上面的配置規則意思如下:
#
In
the
example
below
the
behaviour
will
be
to
save:
#
after
900
sec
(15
min)
if
at
least
1
key
changed
#
after
300
sec
(5
min)
if
at
least
10
keys
changed
#
after
60
sec
if
at
least
10000
keys
changed
redis也可以關閉自動持久化,注釋掉這些save配置,或者save
「」
如果後台保存到磁碟發生錯誤,將停止寫操作.
stop-writes-on-bgsave-error
yes
使用LZF壓縮rdb文件,這會耗CPU,
但是可以減少磁碟佔用.
rdbcompression
yes
保存rdb和載入rdb文件的時候檢驗,可以防止錯誤,但是要付出約10%的性能,可以關閉他,提高性能。
rdbchecksum
yes
導出的rdb文件名
dbfilename
mp.rdb
設置工作目錄,
rdb文件會寫到該目錄,
append
only
file也會存儲在該目錄下.
dir
./
③ 如何在redis配置masterName
1. Redis默認不是以守護進程的方式運行,可以通過該配置項修改,使用yes啟用守護進程
daemonize no
2. 當Redis以守護進程方式運行時,Redis默認會把pid寫入/var/run/redis.pid文件,可以通過pidfile指定
pidfile /var/run/redis.pid
3. 指定Redis監聽埠,默認埠為6379,作者在自己的一篇博文中解釋了為什麼選用6379作為默認埠,因為6379在手機按鍵上MERZ對應的號碼,而MERZ取自義大利歌女Alessia Merz的名字
port 6379
4. 綁定的主機地址
bind 127.0.0.1
5.當 客戶端閑置多長時間後關閉連接,如果指定為0,表示關閉該功能
timeout 300
6. 指定日誌記錄級別,Redis總共支持四個級別:debug、verbose、notice、warning,默認為verbose
loglevel verbose
7. 日誌記錄方式,默認為標准輸出,如果配置Redis為守護進程方式運行,而這里又配置為日誌記錄方式為標准輸出,則日誌將會發送給/dev/null
logfile stdout
8. 設置資料庫的數量,默認資料庫為0,可以使用SELECT <dbid>命令在連接上指定資料庫id
databases 16
9. 指定在多長時間內,有多少次更新操作,就將數據同步到數據文件,可以多個條件配合
save <seconds> <changes>
Redis默認配置文件中提供了三個條件:
save 900 1
save 300 10
save 60 10000
分別表示900秒(15分鍾)內有1個更改,300秒(5分鍾)內有10個更改以及60秒內有10000個更改。
10. 指定存儲至本地資料庫時是否壓縮數據,默認為yes,Redis採用LZF壓縮,如果為了節省CPU時間,可以關閉該選項,但會導致資料庫文件變的巨大
rdbcompression yes
11. 指定本地資料庫文件名,默認值為mp.rdb
dbfilename mp.rdb
12. 指定本地資料庫存放目錄
dir ./
13. 設置當本機為slav服務時,設置master服務的IP地址及埠,在Redis啟動時,它會自動從master進行數據同步
slaveof <masterip> <masterport>
14. 當master服務設置了密碼保護時,slav服務連接master的密碼
masterauth <master-password>
15. 設置Redis連接密碼,如果配置了連接密碼,客戶端在連接Redis時需要通過AUTH <password>命令提供密碼,默認關閉
requirepass foobared
16. 設置同一時間最大客戶端連接數,默認無限制,Redis可以同時打開的客戶端連接數為Redis進程可以打開的最大文件描述符數,如果設置 maxclients 0,表示不作限制。當客戶端連接數到達限制時,Redis會關閉新的連接並向客戶端返回max number of clients reached錯誤信息
maxclients 128
17. 指定Redis最大內存限制,Redis在啟動時會把數據載入到內存中,達到最大內存後,Redis會先嘗試清除已到期或即將到期的Key,當此方法處理 後,仍然到達最大內存設置,將無法再進行寫入操作,但仍然可以進行讀取操作。Redis新的vm機制,會把Key存放內存,Value會存放在swap區
maxmemory <bytes>
18. 指定是否在每次更新操作後進行日誌記錄,Redis在默認情況下是非同步的把數據寫入磁碟,如果不開啟,可能會在斷電時導致一段時間內的數據丟失。因為 redis本身同步數據文件是按上面save條件來同步的,所以有的數據會在一段時間內只存在於內存中。默認為no
appendonly no
19. 指定更新日誌文件名,默認為appendonly.aof
appendfilename appendonly.aof
20. 指定更新日誌條件,共有3個可選值:
no:表示等操作系統進行數據緩存同步到磁碟(快)
always:表示每次更新操作後手動調用fsync()將數據寫到磁碟(慢,安全)
everysec:表示每秒同步一次(折衷,默認值)
appendfsync everysec
21. 指定是否啟用虛擬內存機制,默認值為no,簡單的介紹一下,VM機制將數據分頁存放,由Redis將訪問量較少的頁即冷數據swap到磁碟上,訪問多的頁面由磁碟自動換出到內存中(在後面的文章我會仔細分析Redis的VM機制)
vm-enabled no
22. 虛擬內存文件路徑,默認值為/tmp/redis.swap,不可多個Redis實例共享
vm-swap-file /tmp/redis.swap
23. 將所有大於vm-max-memory的數據存入虛擬內存,無論vm-max-memory設置多小,所有索引數據都是內存存儲的(Redis的索引數據 就是keys),也就是說,當vm-max-memory設置為0的時候,其實是所有value都存在於磁碟。默認值為0
vm-max-memory 0
24. Redis swap文件分成了很多的page,一個對象可以保存在多個page上面,但一個page上不能被多個對象共享,vm-page-size是要根據存儲的 數據大小來設定的,作者建議如果存儲很多小對象,page大小最好設置為32或者64bytes;如果存儲很大大對象,則可以使用更大的page,如果不 確定,就使用默認值
vm-page-size 32
25. 設置swap文件中的page數量,由於頁表(一種表示頁面空閑或使用的bitmap)是在放在內存中的,在磁碟上每8個pages將消耗1byte的內存。
vm-pages 134217728
26. 設置訪問swap文件的線程數,最好不要超過機器的核數,如果設置為0,那麼所有對swap文件的操作都是串列的,可能會造成比較長時間的延遲。默認值為4
vm-max-threads 4
27. 設置在向客戶端應答時,是否把較小的包合並為一個包發送,默認為開啟
glueoutputbuf yes
28. 指定在超過一定的數量或者最大的元素超過某一臨界值時,採用一種特殊的哈希演算法
hash-max-zipmap-entries 64
hash-max-zipmap-value 512
29. 指定是否激活重置哈希,默認為開啟(後面在介紹Redis的哈希演算法時具體介紹)
activerehashing yes
30. 指定包含其它的配置文件,可以在同一主機上多個Redis實例之間使用同一份配置文件,而同時各個實例又擁有自己的特定配置文件
include /path/to/local.conf
④ Redis持久化
Redis支持RDB和AOF兩種持久化機制,持久化功能有效地避免因進程退出造成的數據丟失問題,當下次重啟時利用之前持久化的文件即可實現數據恢復。理解掌握持久化機制對於Redis運維非常重要。本章內容如下:
·首先介紹RDB、AOF的配置和運行流程,以及控制持久化的相關命令,如bgsave和bgrewriteaof。
·其次對常見持久化問題進行分析定位和優化。
·最後結合Redis常見 的單機多實例部署場景進行優化。
5.1RDB
RDB持久化是把當前進程數據生成快照保存到硬碟的過程,觸發RDB持久化過程分為手動觸發和自動觸發。
5.1.1觸發機制
手動觸發分別對應save和bgsave命令:
·save命令:阻塞當前Redis伺服器,直到RDB過程完成為止,對於內存比較大的實例會造成長時間阻塞,線上環境不建議使用。運行save命令對應
的Redis日誌如下:
* DB saved on disk
·bgsave命令:Redis進程執行fork操作創建子進程,RDB持久化過程由子進程負責,完成後自動結束。阻塞只發生在fork階段,一般時間很短。運行bgsave命令對應的Redis日誌如下:
* Background saving started by pid 3151
* DB saved on disk
* RDB: 0 MB of memory used by -on-write
* Background saving terminated with success
顯然bgsave命令是針對save阻塞問題做的優化。因此Redis內部所有的涉及RDB的操作都採用bgsave的方式,而save命令已經廢棄。
除了執行命令手動觸發之外,Redis內部還存在自動觸發RDB的持久化機制,例如以下場景:
1)使用save相關配置,如「save m n」。表示m秒內數據集存在n次修改時,自動觸發bgsave。
2)如果從節點執行全量復制操作,主節點自動執行bgsave生成RDB文件並發送給從節點,更多細節見6.3節介紹的復制原理。
3)執行debug reload命令重新載入Redis時,也會自動觸發save操作。
4)默認情況下執行shutdown命令時,如果沒有開啟AOF持久化功能則自動執行bgsave。
5.1.2流程說明
bgsave是主流的觸發RDB持久化方式,下面根據圖5-1了解它的運作流程。
1)執行bgsave命令,Redis父進程判斷當前是否存在正在執行的子進程,如RDB/AOF子進程,如果存在bgsave命令直接返回。
2)父進程執行fork操作創建子進程,fork操作過程中父進程會阻塞,通過info stats命令查看latest_fork_usec選項,可以獲取最近一個fork操作的耗時,單位為微秒。
3)父進程fork完成後,bgsave命令返回「Background saving started」信息並不再阻塞父進程,可以繼續響應其他命令。
4)子進程創建RDB文件,根據父進程內存生成臨時快照文件,完成後對原有文件進行原子替換。執行lastsave命令可以獲取最後一次生成RDB的時間,對應info統計的rdb_last_save_time選項。
5)進程發送信號給父進程表示完成,父進程更新統計信息,具體見info Persistence下的rdb_*相關選項。
5.1.3RDB文件的處理
保存:RDB文件保存在dir配置指定的目錄下,文件名通過dbfilename配置指定。可以通過執行config set dir{newDir}和config setdbfilename{newFileName}運行期動態執行,當下次運行時RDB文件會保存到新目錄。
運維提示
當遇到壞盤或磁碟寫滿等情況時,可以通過config set dir{newDir}在線修改文件路徑到可用的磁碟路徑,之後執行bgsave進行磁碟切換,同樣適用於AOF持久化文件。
壓縮:Redis默認採用LZF演算法對生成的RDB文件做壓縮處理,壓縮後的文件遠遠小於內存大小,默認開啟,可以通過參數config set rdbcompression{yes|no}動態修改。
運維提示
雖然壓縮RDB會消耗CPU,但可大幅降低文件的體積,方便保存到硬碟或通過網路發送給從節點,因此線上建議開啟。
校驗:如果Redis載入損壞的RDB文件時拒絕啟動,並列印如下日誌:
# Short read or OOM loading DB. Unrecoverable error, aborting now.
這時可以使用Redis提供的redis-check-mp工具檢測RDB文件並獲取對應的錯誤報告。
5.1.4RDB的優缺點
RDB的優點:
·RDB是一個緊湊壓縮的二進制文件,代表Redis在某個時間點上的數據快照。非常適用於備份,全量復制等場景。比如每6小時執行bgsave備份,並把RDB文件拷貝到遠程機器或者文件系統中(如hdfs),用於災難恢復。
·Redis載入RDB恢復數據遠遠快於AOF的方式。
RDB的缺點:
·RDB方式數據沒辦法做到實時持久化/秒級持久化。因為bgsave每次運行都要執行fork操作創建子進程,屬於重量級操作,頻繁執行成本過高。
·RDB文件使用特定二進制格式保存,Redis版本演進過程中有多個格式的RDB版本,存在老版本Redis服務無法兼容新版RDB格式的問題。針對RDB不適合實時持久化的問題,Redis提供了AOF持久化方式來解決。
5.2AOF
AOF(append only file)持久化:以獨立日誌的方式記錄每次寫命令,重啟時再重新執行AOF文件中的命令達到恢復數據的目的。AOF的主要作用是解決了數據持久化的實時性,目前已經是Redis持久化的主流方式。理解掌握好AOF持久化機制對我們兼顧數據安全性和性能非常有幫助。
5.2.1使用AOF
開啟AOF功能需要設置配置:appendonly yes,默認不開啟。AOF文件名通過appendfilename配置設置,默認文件名是appendonly.aof。保存路徑同RDB持久化方式一致,通過dir配置指定。AOF的工作流程操作:命令寫入(append)、文件同步(sync)、文件重寫(rewrite)、重啟載入(load),如圖5-2所示。
1)所有的寫入命令會追加到aof_buf(緩沖區)中。
2)AOF緩沖區根據對應的策略向硬碟做同步操作。
3)隨著AOF文件越來越大,需要定期對AOF文件進行重寫,達到壓縮的目的。
4)當Redis伺服器重啟時,可以載入AOF文件進行數據恢復。了解AOF工作流程之後,下面針對每個步驟做詳細介紹。
5.2.2命令寫入
AOF命令寫入的內容直接是文本協議格式。例如set hello world這條命令,在AOF緩沖區會追加如下文本:*3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n
Redis協議格式具體說明見4.1客戶端協議小節,這里不再贅述,下面介
紹關於AOF的兩個疑惑:
1)AOF為什麼直接採用文本協議格式?可能的理由如下:
·文本協議具有很好的兼容性。
·開啟AOF後,所有寫入命令都包含追加操作,直接採用協議格式,避免了二次處理開銷。
·文本協議具有可讀性,方便直接修改和處理。
2)AOF為什麼把命令追加到aof_buf中?Redis使用單線程響應命令,如果每次寫AOF文件命令都直接追加到硬碟,那麼性能完全取決於當前硬碟負載。先寫入緩沖區aof_buf中,還有另一個好處Redis可以提供多種緩沖區同步硬碟的策略,在性能和安全性方面做出平衡。
5.2.3文件同步
Redis提供了多種AOF緩沖區同步文件策略,由參數appendfsync控制,不同值的含義如表5-1所示。
表5-1AOF緩沖區同步文件策略
系統調用write和fsync說明:
·write操作會觸發延遲寫(delayed write)機制。linux在內核提供頁緩沖區用來提高硬碟IO性能。write操作在寫入系統緩沖區後直接返回。同步硬碟操作依賴於系統調度機制,例如:緩沖區頁空間寫滿或達到特定時間周期。同步文件之前,如果此時系統故障宕機,緩沖區內數據將丟失。
·fsync針對單個文件操作(比如AOF文件),做強制硬碟同步,fsync將阻塞直到寫入硬碟完成後返回,保證了數據持久化。除了write、fsync,Linux還提供了sync、fdatasync操作,具體API說明參
見:http://linux.die.net/man/2/write,http://linux.die.net/man/2/fsync,http://linux.die.net/man/2/sync
·配置為always時,每次寫入都要同步AOF文件,在一般的SATA硬碟上,Redis只能支持大約幾百TPS寫入,顯然跟Redis高性能特性背道而馳,不建議配置。
·配置為no,由於操作系統每次同步AOF文件的周期不可控,而且會加大每次同步硬碟的數據量,雖然提升了性能,但數據安全性無法保證。
·配置為everysec,是建議的同步策略,也是默認配置,做到兼顧性能和數據安全性。理論上只有在系統突然宕機的情況下丟失1秒的數據。(嚴格來說最多丟失1秒數據是不準確的,5.3節會做具體介紹到。)
5.2.4重寫機制
隨著命令不斷寫入AOF,文件會越來越大,為了解決這個問題,Redis引入AOF重寫機制壓縮文件體積。AOF文件重寫是把Redis進程內的數據轉化為寫命令同步到新AOF文件的過程。
重寫後的AOF文件為什麼可以變小?有如下原因:
1)進程內已經超時的數據不再寫入文件。
2)舊的AOF文件含有無效命令,如del key1、hdel key2、srem keys、set
a111、set a222等。重寫使用進程內數據直接生成,這樣新的AOF文件只保留最終數據的寫入命令。
3)多條寫命令可以合並為一個,如:lpush list a、lpush list b、lpush list c可以轉化為:lpush list a b c。為了防止單條命令過大造成客戶端緩沖區溢出,對於list、set、hash、zset等類型操作,以64個元素為界拆分為多條。
AOF重寫降低了文件佔用空間,除此之外,另一個目的是:更小的AOF文件可以更快地被Redis載入。AOF重寫過程可以手動觸發和自動觸發:
·手動觸發:直接調用bgrewriteaof命令。
·自動觸發:根據auto-aof-rewrite-min-size和auto-aof-rewrite-percentage參數確定自動觸發時機。
·auto-aof-rewrite-min-size:表示運行AOF重寫時文件最小體積,默認為64MB。
·auto-aof-rewrite-percentage:代表當前AOF文件空間(aof_current_size)和上一次重寫後AOF文件空間(aof_base_size)的比值。自動觸發時機=aof_current_size>auto-aof-rewrite-min-size&&(aof_current_size-aof_base_size)/aof_base_size>=auto-aof-rewrite-percentage其中aof_current_size和aof_base_size可以在info Persistence統計信息中查看。當觸發AOF重寫時,內部做了哪些事呢?下面結合圖5-3介紹它的運行流程。
圖5-3AOF重寫運作流程
流程說明:
1)執行AOF重寫請求。
如果當前進程正在執行AOF重寫,請求不執行並返回如下響應:
ERR Background append only file rewriting already in progress
如果當前進程正在執行bgsave操作,重寫命令延遲到bgsave完成之後再執行,返回如下響應:
Background append only file rewriting scheled
2)父進程執行fork創建子進程,開銷等同於bgsave過程。
3.1)主進程fork操作完成後,繼續響應其他命令。所有修改命令依然寫入AOF緩沖區並根據appendfsync策略同步到硬碟,保證原有AOF機制正確性。
3.2)由於fork操作運用寫時復制技術,子進程只能共享fork操作時的內存數據。由於父進程依然響應命令,Redis使用「AOF重寫緩沖區」保存這部分新數據,防止新AOF文件生成期間丟失這部分數據。
4)子進程根據內存快照,按照命令合並規則寫入到新的AOF文件。每次批量寫入硬碟數據量由配置aof-rewrite-incremental-fsync控制,默認為32MB,防止單次刷盤數據過多造成硬碟阻塞。
5.1)新AOF文件寫入完成後,子進程發送信號給父進程,父進程更新統計信息,具體見info persistence下的aof_*相關統計。
5.2)父進程把AOF重寫緩沖區的數據寫入到新的AOF文件。
5.3)使用新AOF文件替換老文件,完成AOF重寫。
5.2.5重啟載入
AOF和RDB文件都可以用於伺服器重啟時的數據恢復。如圖5-4所示,表示Redis持久化文件載入流程。
流程說明:
1)AOF持久化開啟且存在AOF文件時,優先載入AOF文件,列印如下日誌:
* DB loaded from append only file: 5.841 seconds
2)AOF關閉或者AOF文件不存在時,載入RDB文件,列印如下日誌:
* DB loaded from disk: 5.586 seconds
3)載入AOF/RDB文件成功後,Redis啟動成功。
4)AOF/RDB文件存在錯誤時,Redis啟動失敗並列印錯誤信息。
5.2.6文件校驗
載入損壞的AOF文件時會拒絕啟動,並列印如下日誌:
# Bad file format reading the append only file: make a backup of your AOF file,
then use ./redis-check-aof --fix <filename>
運維提示
對於錯誤格式的AOF文件,先進行備份,然後採用redis-check-aof--fix命令進行修復,修復後使用diff-u對比數據的差異,找出丟失的數據,有些可以人工修改補全。
AOF文件可能存在結尾不完整的情況,比如機器突然掉電導致AOF尾部文件命令寫入不全。Redis為我們提供了aof-load-truncated配置來兼容這種情況,默認開啟。載入AOF時,當遇到此問題時會忽略並繼續啟動,同時列印
如下警告日誌:
# !!! Warning: short read while loading the AOF file !!!
# !!! Truncating the AOF at offset 397856725 !!!
# AOF loaded anyway because aof-load-truncated is enabled
5.3問題定位與優化
Redis持久化功能一直是影響Redis性能的高發地,本節我們結合常見的持久化問題進行分析定位和優化。
5.3.1fork操作
當Redis做RDB或AOF重寫時,一個必不可少的操作就是執行fork操作創建子進程,對於大多數操作系統來說fork是個重量級錯誤。雖然fork創建的子進程不需要拷貝父進程的物理內存空間,但是會復制父進程的空間內存頁表。例如對於10GB的Redis進程,需要復制大約20MB的內存頁表,因此fork操作耗時跟進程總內存量息息相關,如果使用虛擬化技術,特別是Xen虛擬機,fork操作會更耗時。
fork耗時問題定位:對於高流量的Redis實例OPS可達5萬以上,如果fork操作耗時在秒級別將拖Redis幾萬條命令執行,對線上應用延遲影響非常明顯。正常情況下fork耗時應該是每GB消耗20毫秒左右。可以在info stats統計中查latest_fork_usec指標獲取最近一次fork操作耗時,單位微秒。
如何改善fork操作的耗時:
1)優先使用物理機或者高效支持fork操作的虛擬化技術,避免使用Xen。
2)控制Redis實例最大可用內存,fork耗時跟內存量成正比,線上建議每個Redis實例內存控制在10GB以內。
3)合理配置Linux內存分配策略,避免物理內存不足導致fork失敗,具體細節見12.1節「Linux配置優化」。
4)降低fork操作的頻率,如適度放寬AOF自動觸發時機,避免不必要的全量復制等。
5.3.2子進程開銷監控和優化
子進程負責AOF或者RDB文件的重寫,它的運行過程主要涉及CPU、內存、硬碟三部分的消耗。
1.CPU
·CPU開銷分析。子進程負責把進程內的數據分批寫入文件,這個過程屬於CPU密集操作,通常子進程對單核CPU利用率接近90%.
·CPU消耗優化。Redis是CPU密集型服務,不要做綁定單核CPU操作。由於子進程非常消耗CPU,會和父進程產生單核資源競爭。不要和其他CPU密集型服務部署在一起,造成CPU過度競爭。如果部署多個Redis實例,盡量保證同一時刻只有一個子進程執行重寫工作,具體細節見5.4節多實例部署」。
2.內存
·內存消耗分析。子進程通過fork操作產生,佔用內存大小等同於父進程,理論上需要兩倍的內存來完成持久化操作,但Linux有寫時復制機制(-on-write)。父子進程會共享相同的物理內存頁,當父進程處理寫請求時會把要修改的頁創建副本,而子進程在fork操作過程中共享整個父進程內存快照。
·內存消耗監控。RDB重寫時,Redis日誌輸出容如下:
* Background saving started by pid 7692
* DB saved on disk
* RDB: 5 MB of memory used by -on-write
* Background saving terminated with success
如果重寫過程中存在內存修改操作,父進程負責創建所修改內存頁的副本,從日誌中可以看出這部分內存消耗了5MB,可以等價認為RDB重寫消耗了5MB的內存。
AOF重寫時,Redis日誌輸出容如下:
* Background append only file rewriting started by pid 8937
* AOF rewrite child asks to stop sending diffs.
* Parent agreed to stop sending diffs. Finalizing AOF...
* Concatenating 0.00 MB of AOF diff received from parent.
* SYNC append only file rewrite performed
* AOF rewrite: 53 MB of memory used by -on-write
* Background AOF rewrite terminated with success
* Resial parent diff successfully flushed to the rewritten AOF (1.49 MB)
* Background AOF rewrite finished successfully
父進程維護頁副本消耗同RDB重寫過程類似,不同之處在於AOF重寫需要AOF重寫緩沖區,因此根據以上日誌可以預估內存消耗為:53MB+1.49MB,也就是AOF重寫時子進程消耗的內存量。
運維提示
編寫shell腳本根據Redis日誌可快速定位子進程重寫期間內存過度消耗情況。
內存消耗優化:
1)同CPU優化一樣,如果部署多個Redis實例,盡量保證同一時刻只有一個子進程在工作。
2)避免在大量寫入時做子進程重寫操作,這樣將導致父進程維護大量頁副本,造成內存消耗。Linux kernel在2.6.38內核增加了Transparent Huge Pages(THP),支持huge page(2MB)的頁分配,默認開啟。當開啟時可以降低fork創建子進程的速度,但執行fork之後,如果開啟THP,復制頁單位從原來4KB變為2MB,會大幅增加重寫期間父進程內存消耗。建議設置「sudo echo never>/sys/kernel/mm/transparent_hugepage/enabled」關閉THP。更多THP細節和配置見12.1Linux配置優化」。
3.硬碟
·硬碟開銷分析。子進程主要職責是把AOF或者RDB文件寫入硬碟持久化。勢必造成硬碟寫入壓力。根據Redis重寫AOF/RDB的數據量,結合系統工具如sar、iostat、iotop等,可分析出重寫期間硬碟負載情況。·硬碟開銷優化。優化方法如下:
a)不要和其他高硬碟負載的服務部署在一起。如:存儲服務、消息隊列服務等。
b)AOF重寫時會消耗大量硬碟IO,可以開啟配置no-appendfsync-on-rewrite,默認關閉。表示在AOF重寫期間不做fsync操作。
c)當開啟AOF功能的Redis用於高流量寫入場景時,如果使用普通機械磁碟,寫入吞吐一般在100MB/s左右,這時Redis實例的瓶頸主要在AOF同步硬碟上。
d)對於單機配置多個Redis實例的情況,可以配置不同實例分盤存儲AOF文件,分攤硬碟寫入壓力。運維提示
配置no-appendfsync-on-rewrite=yes時,在極端情況下可能丟失整個AOF重寫期間的數據,需要根據數據安全性決定是否配置。
5.3.3AOF追加阻塞
當開啟AOF持久化時,常用的同步硬碟的策略是everysec,用於平衡性能和數據安全性。對於這種方式,Redis使用另一條線程每秒執行fsync同步硬碟。當系統硬碟資源繁忙時,會造成Redis主線程阻塞,如圖5-5所示。
阻塞流程分析:
1)主線程負責寫入AOF緩沖區。
2)AOF線程負責每秒執行一次同步磁碟操作,並記錄最近一次同步時間。
3)主線程負責對比上次AOF同步時間:
·如果距上次同步成功時間在2秒內,主線程直接返回。
·如果距上次同步成功時間超過2秒,主線程將會阻塞,直到同步操作完成。
通過對AOF阻塞流程可以發現兩個問題:
1)everysec配置最多可能丟失2秒數據,不是1秒。
2)如果系統fsync緩慢,將會導致Redis主線程阻塞影響效率。
AOF阻塞問題定位:
1)發生AOF阻塞時,Redis輸出如下日誌,用於記錄AOF fsync阻塞導致拖慢Redis服務的行為:
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
2)每當發生AOF追加阻塞事件發生時,在info Persistence統計中,aof_delayed_fsync指標會累加,查看這個指標方便定位AOF阻塞問題。
3)AOF同步最多允許2秒的延遲,當延遲發生時說明硬碟存在高負載問題,可以通過監控工具如iotop,定位消耗硬碟IO資源的進程。優化AOF追加阻塞問題主要是優化系統硬碟負載,優化方式見上一節。
5.4多實例部署
Redis單線程架構導致無法充分利用CPU多核特性,通常的做法是在一台機器上部署多個Redis實例。當多個實例開啟AOF重寫後,彼此之間會產生對CPU和IO的競爭。本節主要介紹針對這種場景的分析和優化。上一節介紹了持久化相關的子進程開銷。對於單機多Redis部署,如果同一時刻運行多個子進程,對當前系統影響將非常明顯,因此需要採用一種措施,把子進程工作進行隔離。Redis在info Persistence中為我們提供了監控子進程運行狀況的度量指標,如表5-2所示。
我們基於以上指標,可以通過外部程序輪詢控制AOF重寫操作的執行,整個過程如圖5-6所示。
流程說明:
1)外部程序定時輪詢監控機器(machine)上所有Redis實例。
2)對於開啟AOF的實例,查看(aof_current_size-aof_base_size)/aof_base_size確認增長率。
3)當增長率超過特定閾值(如100%),執行bgrewriteaof命令手動觸發當前實例的AOF重寫。
4)運行期間循環檢查aof_rewrite_in_progress和aof_current_rewrite_time_sec指標,直到AOF重寫結束。
5)確認實例AOF重寫完成後,再檢查其他實例並重復2)~4)步操作。從而保證機器內每個Redis實例AOF重寫串列化執行。
5.5本章重點回顧
1)Redis提供了兩種持久化方式:RDB和AOF。
2)RDB使用一次性生成內存快照的方式,產生的文件緊湊壓縮比更高,因此讀取RDB恢復速度更快。由於每次生成RDB開銷較大,無法做到實時持久化,一般用於數據冷備和復制傳輸。
3)save命令會阻塞主線程不建議使用,bgsave命令通過fork操作創建子進程生成RDB避免阻塞。
4)AOF通過追加寫命令到文件實現持久化,通過appendfsync參數可以控制實時/秒級持久化。因為需要不斷追加寫命令,所以AOF文件體積逐漸變大,需要定期執行重寫操作來降低文件體積。
5)AOF重寫可以通過auto-aof-rewrite-min-size和auto-aof-rewrite-percentage參數控制自動觸發,也可以使用bgrewriteaof命令手動觸發。
6)子進程執行期間使用-on-write機制與父進程共享內存,避免內存消耗翻倍。AOF重寫期間還需要維護重寫緩沖區,保存新的寫入命令避免數據丟失。
7)持久化阻塞主線程場景有:fork阻塞和AOF追加阻塞。fork阻塞時間跟內存量和系統有關,AOF追加阻塞說明硬碟資源緊張。
8)單機下部署多個實例時,為了防止出現多個子進程執行重寫操作,建議做隔離控制,避免CPU和IO資源競爭。
⑤ redis在Windows下配置除了問題
# Redis configuration file example
# Note on units: when memory size is needed, it is possible to specifiy
# it in the usual form of 1k 5GB 4M and so forth:
#
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#
# units are case insensitive so 1GB 1Gb 1gB are all the same.
# By default Redis does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
daemonize no
Redis默認不是以守護進程的方式運行,可以通過該配置項修改,使用yes啟用守護進程
# When running daemonized, Redis writes a pid file in /var/run/redis.pid by
# default. You can specify a custom pid file location here.
pidfile /var/run/redis.pid
當Redis以守護進程方式運行時,Redis默認會把pid寫入/var/run/redis.pid文件,可以通過pidfile指定
# Accept connections on the specified port, default is 6379.
# If port 0 is specified Redis will not listen on a TCP socket.
port 6379
指定Redis監聽埠,默認埠為6379
# If you want you can bind a single interface, if the bind option is not
# specified all the interfaces will listen for incoming connections.
#
# bind 127.0.0.1
綁定的主機地址
# Specify the path for the unix socket that will be used to listen for
# incoming connections. There is no default, so Redis will not listen
# on a unix socket when not specified.
#
# unixsocket /tmp/redis.sock
# unixsocketperm 755
# Close the connection after a client is idle for N seconds (0 to disable)
timeout 0
當 客戶端閑置多長時間後關閉連接,如果指定為0,表示關閉該功能
# Set server verbosity to 'debug'
# it can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in proction probably)
# warning (only very important / critical messages are logged)
loglevel verbose
指定日誌記錄級別,Redis總共支持四個級別:debug、verbose、notice、warning,默認為verbose
# Specify the log file name. Also 'stdout' can be used to force
# Redis to log on the standard output. Note that if you use standard
# output for logging but daemonize, logs will be sent to /dev/null
logfile stdout
日誌記錄方式,默認為標准輸出,如果配置Redis為守護進程方式運行,而這里又配置為日誌記錄方式為標准輸出,則日誌將會發送給/dev/null
# To enable logging to the system logger, just set 'syslog-enabled' to yes,
# and optionally update the other syslog parameters to suit your needs.
# syslog-enabled no
# Specify the syslog identity.
# syslog-ident redis
# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7.
# syslog-facility local0
# Set the number of databases. The default database is DB 0, you can select
# a different one on a per-connection basis using SELECT <dbid> where
# dbid is a number between 0 and 'databases'-1
databases 16
設置資料庫的數量,默認資料庫為0,可以使用SELECT <dbid>命令在連接上指定資料庫id
################################ SNAPSHOTTING #################################
#
# Save the DB on disk:
#
# save <seconds> <changes>
#
# Will save the DB if both the given number of seconds and the given
# number of write operations against the DB occurred.
#
# In the example below the behaviour will be to save:
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed
# after 60 sec if at least 10000 keys changed
#
# Note: you can disable saving at all commenting all the "save" lines.
save 900 1
save 300 10
save 60 10000
分別表示900秒(15分鍾)內有1個更改,300秒(5分鍾)內有10個更改以及60秒內有10000個更改。
指定在多長時間內,有多少次更新操作,就將數據同步到數據文件,可以多個條件配合
# Compress string objects using LZF when mp .rdb databases?
# For default that's set to 'yes' as it's almost always a win.
# If you want to save some CPU in the saving child set it to 'no' but
# the dataset will likely be bigger if you have compressible values or keys.
rdbcompression yes
指定存儲至本地資料庫時是否壓縮數據,默認為yes,Redis採用LZF壓縮,如果為了節省CPU時間,可以關閉該選項,但會導致資料庫文件變的巨大
# The filename where to mp the DB
dbfilename mp.rdb
指定本地資料庫文件名,默認值為mp.rdb
# The working directory.
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
#
# Also the Append Only File will be created inside this directory.
#
# Note that you must specify a directory here, not a file name.
dir ./
指定本地資料庫存放目錄
################################# REPLICATION #################################
# Master-Slave replication. Use slaveof to make a Redis instance a of
# another Redis server. Note that the configuration is local to the slave
# so for example it is possible to configure the slave to save the DB with a
# different interval, or to listen to another port, and so on.
#
# slaveof <masterip> <masterport>
slaveof <masterip> <masterport> 設置當本機為slav服務時,設置master服務的IP地址及埠,在Redis啟動時,它會自動從master進行數據同步
# If the master is password protected (using the "requirepass" configuration
# directive below) it is possible to tell the slave to authenticate before
# starting the replication synchronization process, otherwise the master will
# refuse the slave request.
#
# masterauth <master-password>
masterauth <master-password> 當master服務設置了密碼保護時,slav服務連接
⑥ Redis-port導出文件很小
Redis-port導出文件很小該現象是一個正常的行為,在導出後應該注意的是Keys數量是否相同,而不是文件Size大小。
只要確認兩個Redis庫之間Keys數量基本一致。那就表明,沒有數據丟失。可以在AzureRedis門戶Overview頁面,通過Console數據infokeyspace來查看當前庫中所含Keys的數量。
關於壓縮比的問題,因為導出功能是把Redis中的Key/Value生成RDB文件,這是Redis本身的行為,並不是Azure平台的特性功能。通過查看Redis的官方文檔默認使用的是LZF壓縮演算法。
⑦ linux redis 怎麼設置集群
redis.conf 配置文件說明
daemonize no --是否把redis-server啟動在後台,默認是「否」。若改成yes
pidfile /var/run/redis.pid --當Redis以守護進程方式運行時,Redis默認會把pid寫入/var/run/redis.pid文件,可以通過pidfile指定
prot 6379 --指定Redis監聽埠,默認埠為6379
bind 10.252.1.14 ---綁定的主機地址
timeout 0 ---當 客戶端閑置多長時間後關閉連接,如果指定為0,表示關閉該功能
loglevel notice ---指定日誌記錄級別,Redis總共支持四個級別:debug、verbose、notice、warning,默認為verbose
logfile /mnt/redis/log/redis.log --日誌記錄方式,默認為標准輸出,如果配置Redis為守護進程方式運行,而這里又配置為日誌記錄方式為標准輸出,則日誌將會發送給/dev/null
databases 16 設置資料庫的數量,默認資料庫為0,可以使用SELECT <dbid>命令在連接上指定資料庫id
save 900 1 指定在多長時間內,有多少次更新操作,就將數據同步到數據文件,可以多個條件配合
Redis默認配置文件中提供了三個條件:
save 900 1
save 300 10
save 60 10000
分別表示900秒(15分鍾)內有1個更改,300秒(5分鍾)內有10個更改以及60秒內有10000個更改
rdbcompression yes --指定存儲至本地資料庫時是否壓縮數據,默認為yes,Redis採用LZF壓縮,如果為了節省CPU時間,可以關閉該選項,但會導致資料庫文件變的巨大
dbfilename mp.rdb --指定本地資料庫文件名,默認值為mp.rdb
dir /mnt/redis/data/ --指定本地資料庫存放目錄
slaveof <masterip> <masterport> -- 設置當本機為slav服務時,設置master服務的IP地址及埠,在Redis啟動時,它會自動從master進行數據同步
masterauth <master-password> --當master服務設置了密碼保護時,slav服務連接master的密碼
requirepass foobared --設置Redis連接密碼,如果配置了連接密碼,客戶端在連接Redis時需要通過AUTH <password>命令提供密碼,默認關閉
maxclients 128 --- 設置同一時間最大客戶端連接數,默認無限制
maxmemory <bytes> ---指定Redis最大內存限制,Redis在啟動時會把數據載入到內存中,達到最大內存後,Redis會先嘗試清除已到期或即將到期的Key,當此方法處理 後,仍然到達最大內存設置,將無法再進行寫入操作,但仍然可以進行讀取操作。Redis新的vm機制,會把Key存放內存,Value會存放在swap區
appendonly no --指定是否在每次更新操作後進行日誌記錄,Redis在默認情況下是非同步的把數據寫入磁碟,如果不開啟,可能會在斷電時導致一段時間內的數據丟失。因為 redis本身同步數據文件是按上面save條件來同步的,所以有的數據會在一段時間內只存在於內存中。默認為no
appendfilename appendonly.aof ---指定更新日誌文件名,默認為appendonly.aof
appendfsync everysec ---指定更新日誌條件,共有3個可選值: no:表示等操作系統進行數據緩存同步到磁碟(快) . always:表示每次更新操作後手動調用fsync()將數據寫到磁碟(慢,安全). everysec:表示每秒同步一次(折衷,默認值)
vm-enabled no ---指定是否啟用虛擬內存機制,默認值為no,簡單的介紹一下,VM機制將數據分頁存放,由Redis將訪問量較少的頁即冷數據swap到磁碟上,訪問多的頁面由磁碟自動換出到內存中(在後面的文章我會仔細分析Redis的VM機制)
vm-swap-file /tmp/redis.swap ---虛擬內存文件路徑,默認值為/tmp/redis.swap,不可多個Redis實例共享
vm-max-memory 0 將所有大於vm-max-memory的數據存入虛擬內存,無論vm-max-memory設置多小,所有索引數據都是內存存儲的(Redis的索引數據 就是keys),也就是說,當vm-max-memory設置為0的時候,其實是所有value都存在於磁碟。默認值為0
vm-page-size 32 ---Redis swap文件分成了很多的page,一個對象可以保存在多個page上面,但一個page上不能被多個對象共享,vm-page-size是要根據存儲的 數據大小來設定的,作者建議如果存儲很多小對象,page大小最好設置為32或者64bytes;如果存儲很大大對象,則可以使用更大的page,如果不 確定,就使用默認值
vm-pages 134217728 ---設置swap文件中的page數量,由於頁表(一種表示頁面空閑或使用的bitmap)是在放在內存中的,,在磁碟上每8個pages將消耗1byte的內存。
vm-max-threads 4 ---設置訪問swap文件的線程數,最好不要超過機器的核數,如果設置為0,那麼所有對swap文件的操作都是串列的,可能會造成比較長時間的延遲。默認值為4
glueoutputbuf yes ---設置在向客戶端應答時,是否把較小的包合並為一個包發送,默認為開啟
hash-max-zipmap-entries 64 ---指定在超過一定的數量或者最大的元素超過某一臨界值時,採用一種特殊的哈希演算法
hash-max-zipmap-value 512 ---指定在超過一定的數量或者最大的元素超過某一臨界值時,採用一種特殊的哈希演算法
activerehashing yes ---指定是否激活重置哈希,默認為開啟(後面在介紹Redis的哈希演算法時具體介紹)
include /path/to/local.conf ---指定包含其它的配置文件,可以在同一主機上多個Redis實例之間使用同一份配置文件,而同時各個實例又擁有自己的特定配置文件
主伺服器配置
mkdir /mnt/redis/redisDB
mkdir /mnt/redis/redisLog
vi /etc/redis/redis.conf
dbfilename /mnt/redisDB/mp.rdb --修改磁碟上保存資料庫文件的位置
loglevel warning --修改日誌級別
logfile /mnt/redis/redisLog/redis.log --修改日誌文件的位置
從機配置
cp redis.conf /etc/redis_slave.conf
vim redis_slave.conf
修改其中的一行
配置master的ip地址和redis-server的埠。
slaveof <10.45.39.39> <6379> --設置主從伺服器的主伺服器的地址和埠
daemonize no --是否把redis-server啟動在後台,默認是「否」。若改成yes,會生成一個pid文件。
主從測試
主機: redis-server /etc/redis.conf
從機: redis-server /etc/redis_slave.conf
3.1 測試
在主機上啟動redis客戶端:
ssh 192.168.1.1
redis-cli
>set k1 v1
>get k1
"v1"
.登陸從機,並在從機上啟動客戶端:
ssh 192.168.1.2
redis-cli
>get k1
"v1"
可以看到redis已經把數據同步過來了。
⑧ 怎麼在Linux下安裝配置Redis伺服器
1、安裝編譯工具
yum install wget make gcc gcc-c++ zlib-devel openssl openssl-devel pcre-devel kernel keyutils patch perl
2、安裝tcl組件包(安裝Redis需要tcl支持)
下載: tcl8.6.1-src.tar.gz
上傳tcl8.6.1-src.tar.gz到/usr/local/src目錄
cd /usr/local/src #進入軟體包存放目錄
tar zxvf tcl8.6.1-src.tar.gz #解壓
cd tcl8.6.1 #進入安裝目錄
cd unix
./configure --prefix=/usr --without-tzdata --mandir=/usr/share/man $([ $(uname -m) = x86_64 ] && echo --enable-64bit) #配置
make #編譯
sed -e "s@^(TCL_SRC_DIR=').*@1/usr/include'@" -e "/TCL_B/s@='(-L)?.*unix@='1/usr/lib@" -i tclConfig.sh
make install #安裝
make install-private-headers
ln -v -sf tclsh8.6 /usr/bin/tclsh
chmod -v 755 /usr/lib/libtcl8.6.so
3、安裝Redis
下載:http://download.redis.io/redis-stable.tar.gz
上傳redis-stable到/usr/local/src目錄
cd /usr/local/src
tar -zxvf redis-stable.tar.gz #解壓
mv redis-stable /usr/local/redis #移動文件到安裝目錄
cd /usr/local/redis #進入安裝目錄
make #編譯
make install #安裝
cd /usr/local/bin #查看是否有下面文件,如果沒有,拷貝下面文件到/usr/local/bin目錄
cd /usr/local/redis
mkdir -p /usr/local/bin
cp -p redis-server /usr/local/bin
cp -p redis-benchmark /usr/local/bin
cp -p redis-cli /usr/local/bin
cp -p redis-check-mp /usr/local/bin
cp -p redis-check-aof /usr/local/bin
ln -s /usr/local/redis/redis.conf /etc/redis.conf #添加配置文件軟連接
vi /etc/redis.conf #編輯
daemonize yes #設置後台啟動redis
:wq! #保存退出
redis-server /etc/redis.conf #啟動redis服務
redis-cli shutdown #關閉redis
vi /etc/sysctl.conf #編輯,在最後一行添加下面代碼
vm.overcommit_memory = 1
:wq! #保存退出
sysctl -p #使設置立即生效
4、設置redis開機啟動
vi /etc/init.d/redis #編輯,添加以下代碼
#!/bin/sh
# chkconfig: 2345 90 10
# description: Redis is a persistent key-value database
# redis Startup script for redis processes
# processname: redis
redis_path="/usr/local/bin/redis-server"
redis_conf="/etc/redis.conf"
redis_pid="/var/run/redis.pid"
# Source function library.
. /etc/rc.d/init.d/functions
[ -x $redis_path ] || exit 0
RETVAL=0
prog="redis"
# Start daemons.
start() {
if [ -e $redis_pid -a ! -z $redis_pid ];then
echo $prog" already running...."
exit 1
fi
echo -n $"Starting $prog "
# Single instance for all caches
$redis_path $redis_conf
RETVAL=$?
[ $RETVAL -eq 0 ] && {
touch /var/lock/subsys/$prog
success $"$prog"
}
echo
return $RETVAL
}
# Stop daemons.
stop() {
echo -n $"Stopping $prog "
killproc -d 10 $redis_path
echo
[ $RETVAL = 0 ] && rm -f $redis_pid /var/lock/subsys/$prog
RETVAL=$?
return $RETVAL
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status $prog
RETVAL=$?
;;
restart)
stop
start
;;
condrestart)
if test "x`pidof redis`" != x; then
stop
start
fi
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart}"
exit 1
esac
exit $RETVAL
:wq! #保存退出
chmod 755 /etc/init.d/redis #添加腳本執行許可權
chkconfig --add redis #添加開啟啟動
chkconfig --level 2345 redis on #設置啟動級別
chkconfig --list redis #查看啟動級別
service redis restart #重新啟動redis
5、設置redis配置文件參數
mkdir -p /usr/local/redis/var #創建redis資料庫存放目錄
vi /etc/redis.conf #編輯
daemonize yes #以後台daemon方式運行redis
pidfile "/var/run/redis.pid" #redis以後台運行,默認pid文件路徑/var/run/redis.pid
port 6379 #默認埠
bind 127.0.0.1 #默認綁定本機所有ip地址,為了安全,可以只監聽內網ip
timeout 300 #客戶端超時設置,單位為秒
loglevel verbose #設置日誌級別,支持四個級別:debug、notice、verbose、warning
logfile stdout #日誌記錄方式,默認為標准輸出,logs不寫文件,輸出到空設備/deb/null
logfile "/usr/local/redis/var/redis.log" #可以指定日誌文件路徑
databases 16 #開啟資料庫的數量
save 900 1
save 300 10
save 60 10000
創建本地資料庫快照,格式:save * *
900秒內,執行1次寫操作
300秒內,執行10次寫操作
60秒內,執行10000次寫操作
rdbcompression yes #啟用資料庫lzf壓縮,也可以設置為no
dbfilename mp.rdb #本地快照資料庫名稱
dir "/usr/local/redis/var/" #本地快照資料庫存放目錄
requirepass 123456 #設置redis資料庫連接密碼
maxclients 10000 #同一時間最大客戶端連接數,0為無限制
maxmemory 1024MB #設定redis最大使用內存,值要小於物理內存,必須設置
appendonly yes #開啟日誌記錄,相當於MySQL的binlog
appendfilename "appendonly.aof" #日誌文件名,注意:不是目錄路徑
appendfsync everysec #每秒執行同步,還有兩個參數always、no一般設置為everysec,相當於MySQL事物日誌的寫方式
:wq! #保存退出
service redis restart #重啟
6、測試redis資料庫
redis-cli -a 123456 #連接redis資料庫,注意:-a後面跟redis資料庫密碼
set name 111cn.net #寫數據
get name #讀取數據
exit #退出redis資料庫控制台
redis-benchmark -h 127.0.0.1 -p 6379 -c 1000 -n 100000 #1000個並發連接,100000個請求,測試127.0.0.1埠為6379的redis伺服器性能
⑨ Redis 持久化 ★
1、RDB
2、AOF
3、兩種的使用場景
在指定的時間間隔內將內存中的數據集快照寫入磁碟, 也就是行話講的Snapshot快照,它恢復時是將快照文件直接讀到內存里
Redis會單獨創建(fork)一個子進程來進行持久化,會先將數據寫入到 一個臨時文件中,待持久化過程都結束了,再用這個臨時文件替換上次持久化好的文件。 整個過程中,主進程是不進行任何IO操作的,這就確保了極高的性能 如果需要進行大規模數據的恢復,且對於數據恢復的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺點是最後一次持久化後的數據可能丟失。
(1)Fork的作用是復制一個與當前進程一樣的進程。新進程的所有數據(變數、環境變數、程序計數器等) 數值都和原進程一致,但是是一個全新的進程,並作為原進程的子進程
(2)在Linux程序中,fork()會產生一個和父進程完全相同的子進程,但子進程在此後多會exec系統調用,出於效率考慮,Linux中引入了「寫時復制技術」
(3)一般情況父進程和子進程會共用同一段物理內存,只有進程空間的各段的內容要發生變化時,才會將父進程的內容復制一份給子進程。
在redis.conf中配置文件名稱,默認為mp.rdb
rdb文件的保存路徑,也可以修改。默認為Redis啟動時命令行所在的目錄下
dir "/myredis/"
dir ./ 表示在當前配置文件的文件夾下生成 .rdb文件
(1)配置文件中默認的快照配置
(2)命令save VS bgsave
save :save時只管保存,其它不管,全部阻塞。手動保存。不建議。
bgsave:Redis會在後台非同步進行快照操作, 快照同時還可以響應客戶端請求。
可以通過lastsave 命令獲取最後一次成功執行快照的時間
(3)save(禁用)
格式:save 秒鍾 寫操作次數
RDB是整個內存的壓縮過的Snapshot,RDB的數據結構,可以配置復合的快照觸發條件,
默認是1分鍾內改了1萬次,或5分鍾內改了10次,或15分鍾內改了1次。(短時間內越多越快)
不設置save指令,或者給save傳入空字元串
(4)stop-writes-on-bgsave-error
如果配置成no,表示你不在乎數據不一致或者有其他的手段發現和控制
(5)rdbcompression 壓縮文件
對於存儲到磁碟中的快照,可以設置是否進行壓縮存儲。如果是的話,redis會採用LZF演算法進行壓縮。如果你不想消耗CPU來進行壓縮的話,可以設置為關閉此功能:
(6)rdbchecksum
在存儲快照後,還可以讓redis使用CRC64演算法來進行數據校驗,但是這樣做會增加大約10%的性能消耗,如果希望獲取到最大的性能提升,可以關閉此功能:
(7)rdb的備份
1)將備份文件 (mp.rdb) 移動到 redis 安裝目錄並啟動服務即可
2)CONFIG GET dir獲取目錄
(1)優點:
適合大規模的數據恢復
對數據完整性和一致性要求不高更適合使用
節省磁碟空間
恢復速度快
(2)缺點:
Fork的時候,內存中的數據被克隆了一份,大致2倍的膨脹性需要考慮
雖然Redis在fork時使用了寫時拷貝技術,但是如果數據龐大時還是比較消耗性能。
在備份周期在一定間隔時間做一次備份,所以如果Redis意外down掉的話,就會丟失最後一次快照後的所有修改。
以日誌的形式來記錄每個寫操作(增量保存),將Redis執行過的所有寫指令記錄下來(讀操作不記錄), 只許追加文件但不可以改寫文件,redis啟動之初會讀取該文件重新構建數據,換言之,redis 重啟的話就根據日誌文件的內容將寫指令從前到後執行一次以完成數據的恢復工作
(1)客戶端的請求寫命令會被append追加到AOF緩沖區內;
(2)AOF緩沖區根據AOF持久化策略[always,everysec,no]將操作sync同步到磁碟的AOF文件中;
(3)AOF文件大小超過重寫策略或手動重寫時,會對AOF文件rewrite重寫,壓縮AOF文件容量;
(4)Redis服務重啟時,會重新load載入AOF文件中的寫操作達到數據恢復的目的
可以在redis.conf中配置文件名稱,默認為 appendonly.aof
AOF文件的保存路徑,同RDB的路徑一致。
AOF和RDB同時開啟,系統默認取AOF的數據(數據不會存在丟失)
AOF的備份機制和性能雖然和RDB不同, 但是備份和恢復的操作同RDB一樣,都是拷貝備份文件,需要恢復時再拷貝到Redis工作目錄下,啟動系統即載入。
正常恢復:
修改默認的appendonly no,改為yes
將有數據的aof文件復制一份保存到對應目錄(查看目錄:config get dir)
恢復:重啟redis然後重新載入
異常恢復:
修改默認的appendonly no,改為yes
如遇到AOF文件損壞,通過/usr/local/bin/redis-check-aof--fix appendonly.aof進行恢復
備份被寫壞的AOF文件
恢復:重啟redis,然後重新載入
appendfsync always
始終同步,每次Redis的寫入都會立刻記入日誌;性能較差但數據完整性比較好
appendfsync everysec
每秒同步,每秒記入日誌一次,如果宕機,本秒的數據可能丟失。
appendfsync no
redis不主動進行同步,把同步時機交給操作系統。
(1)是什麼
AOF採用文件追加方式,文件會越來越大為避免出現此種情況,新增了重寫機制, 當AOF文件的大小超過所設定的閾值時,Redis就會啟動AOF文件的內容壓縮, 只保留可以恢復數據的最小指令集.可以使用命令bgrewriteaof
(2)重寫原理,如何實現重寫
AOF文件持續增長而過大時,會fork出一條新進程來將文件重寫(也是先寫臨時文件最後再rename),redis4.0版本後的重寫,是指上就是把rdb 的快照,以二級制的形式附在新的aof頭部,作為已有的歷史數據,替換掉原來的流水賬操作。
no-appendfsync-on-rewrite:
如果 no-appendfsync-on-rewrite=yes ,不寫入aof文件只寫入緩存,用戶請求不會阻塞,但是在這段時間如果宕機會丟失這段時間的緩存數據。(降低數據安全性,提高性能)
重寫雖然可以節約大量磁碟空間,減少恢復時間。但是每次重寫還是有一定的負擔的,因此設定Redis要滿足一定條件才會進行重寫。
(3)重寫流程
(1)bgrewriteaof觸發重寫,判斷是否當前有bgsave或bgrewriteaof在運行,如果有,則等待該命令結束後再繼續執行。
(2)主進程fork出子進程執行重寫操作,保證主進程不會阻塞。
(3)子進程遍歷redis內存中數據到臨時文件,客戶端的寫請求同時寫入aof_buf緩沖區和aof_rewrite_buf重寫緩沖區保證原AOF文件完整以及新AOF文件生成期間的新的數據修改動作不會丟失。
(4)
1).子進程寫完新的AOF文件後,向主進程發信號,父進程更新統計信息。
2).主進程把aof_rewrite_buf中的數據寫入到新的AOF文件。
(5)使用新的AOF文件覆蓋舊的AOF文件,完成AOF重寫。
備份機制更穩健,丟失數據概率更低。
可讀的日誌文本,通過操作AOF穩健,可以處理誤操作。
比起RDB佔用更多的磁碟空間。
恢復備份速度要慢。
每次讀寫都同步的話,有一定的性能壓力。
存在個別Bug,造成恢復不能。
官方推薦兩個都啟用。
如果對數據不敏感,可以選單獨用RDB。
不建議單獨用 AOF,因為可能會出現Bug。
如果只是做純內存緩存,可以都不用。
https://blog.csdn.net/xm393392625/article/details/89053171
⑩ 剛剛問我,redis持久化數據到資料庫是怎麼操作的
1、 快照的方式持久化到磁碟
自動持久化規則配置
save 900 1
save 300 10
save 60 10000
上面的配置規則意思如下:
# In the example below the behaviour will be to save:
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed
# after 60 sec if at least 10000 keys changed
redis也可以關閉自動持久化,注釋掉這些save配置,或者save 「」
如果後台保存到磁碟發生錯誤,將停止寫操作.
stop-writes-on-bgsave-error yes
使用LZF壓縮rdb文件,這會耗CPU, 但是可以減少磁碟佔用.
rdbcompression yes
保存rdb和載入rdb文件的時候檢驗,可以防止錯誤,但是要付出約10%的性能,可以關閉他,提高性能。
rdbchecksum yes
導出的rdb文件名
dbfilename mp.rdb
設置工作目錄, rdb文件會寫到該目錄, append only file也會存儲在該目錄下.
dir ./
Redis自動快照保存到磁碟或者調用bgsave,是後台進程完成的,其他客戶端仍然和可以讀寫redis伺服器,後台保存快照到磁碟會佔用大量內存。調用save保存內存中的數據到磁碟,將阻塞客戶端請求,直到保存完畢。
調用shutdown命令,Redis伺服器會先調用save,所有數據持久化到磁碟之後才會真正退出。
對於數據丟失的問題:
如果伺服器crash,從上一次快照之後的數據將全部丟失。所以在設置保存規則的時候,要根據實際業務設置允許的范圍。
如果對於數據敏感的業務,在程序中要使用恰當的日誌,在伺服器crash之後,通過日誌恢復數據。
2、 Append-only file 的方式持久化
另外一種方式為遞增的方式,將會引起數據變化的操作, 持久化到文件中, 重啟redis的時候,通過操作命令,恢復數據.
每次執行寫操作命令之後,都會將數據寫到server.aofbuf中。
# appendfsync always
appendfsync everysec
# appendfsync no
當配置為always的時候,每次server.aofbuf中的數據寫入到文件之後,才會返回給客戶端,這樣可以保證數據不丟,但是頻繁的IO操作,會降低性能。
everysec每秒寫一次,這可能會丟失一秒內的操作。
aof最大的問題就是隨著時間append file會變的很大,所以我們需要bgrewriteaof命令重新整理文件,只保留最新的kv數據。