redis 硬件要求_Redis持久化机制
介紹
Redis所有的數(shù)據(jù)都保存在內(nèi)存中,數(shù)據(jù)的更新將異步的保存到硬盤上,當需要恢復數(shù)據(jù)時,從硬盤上將數(shù)據(jù)再讀取到內(nèi)存中,這就是Redis的持久化過程。主流的持久化方式有兩種:
快照:MySQL的Dump以及Redis的RDB等
寫日志:MySQL的Binlog,Hbase的HLong以及Redis的AOF等
一、Redis的持久化機制
Redis將所有的數(shù)據(jù)都存儲在內(nèi)存中,那么如果服務器重啟了,Redis中的數(shù)據(jù)怎么恢復呢?
為了使Redis在重啟之后仍能保證數(shù)據(jù)不丟失,需要將數(shù)據(jù)從內(nèi)存中同步到硬盤中。Redis支持兩種方式的持久化,一種是RDB方式,一種是AOF方式。可以單獨使用其中一種或?qū)⒍呓Y合使用。
二、RDB方式
RDB方式的持久化是通過快照(snapshotting)完成的,當符合一定條件時Redis會自動將內(nèi) 存中的所有數(shù)據(jù)進行快照并存儲在硬盤上。進行快照的條件可以由用戶在配置文件中自定 義,由兩個參數(shù)構成:時間和改動的鍵的個數(shù)。當在指定的時間內(nèi)被更改的鍵的個數(shù)大于指定 的數(shù)值時就會進行快照。RDB是Redis默認采用的持久化方式,在配置文件中已經(jīng)預置了3個條 件:
save 900 1 save 300 10 save 60 10000Redis默認會將快照文件存儲在當前目錄的dump.rdb文件中,可以通過配置dir和 dbfilename兩個參數(shù)分別指定快照文件的存儲路徑和文件名。最佳配置實踐:
dbfilename?dump-${port}.rdb快照的過程如下:
Redis使用fork函數(shù)復制一份當前進程(父進程)的副本(子進程)
父進程繼續(xù)接收并處理客戶端發(fā)來的命令,而子進程開始將內(nèi)存中的數(shù)據(jù)寫入硬盤中的臨時文件
當子進程寫入完所有數(shù)據(jù)后會用該臨時文件替換舊的RDB文件,至此一次快照操作完 成。
寫時復制(copy-on-write)策略:在執(zhí)行fork的時候操作系統(tǒng)會使用寫時復制策略,即fork函數(shù)發(fā)生的一刻父子進程共享同一內(nèi)存數(shù)據(jù),當父進程要更改其中某片數(shù)據(jù)時(如執(zhí)行一個寫命令),操作系統(tǒng)會將該片數(shù)據(jù)復制一份以保證子進程的數(shù)據(jù)不受影響,所以新的RDB文件存儲的是執(zhí)行fork一刻的內(nèi)存數(shù)據(jù)。
Redis在進行快照的過程中不會修改RDB文件,只有快照結束后才會將舊的文件替換成新的,也就是說任何時候RDB文件都是完整的。這樣我們可以通過定時備份RDB文件來實現(xiàn)Redis數(shù)據(jù)庫備份。
RDB文件是經(jīng)過壓縮的二進制格式:
可以配置rdbcompression參數(shù)以禁用壓縮節(jié)省CPU占用,所以占用的空間會小于內(nèi)存中的數(shù)據(jù)大小,更加利于傳輸。其他兩個配置參數(shù):
stop-writes-on-bgsave-error yes // bgsave發(fā)生錯誤,停止寫入rdbchecksum?yesrdbcompression yes除了自動快照,還可以手動發(fā)送SAVE或BGSAVE命令讓Redis執(zhí)行快照,兩個命令的區(qū)別:
SAVE是由主進程進行快照操作,會阻塞住客戶端其他請求,不會消耗額外的內(nèi)存
BGSAVE會通過fork子進程進行快照操作,不會阻塞客戶端命令,fork會消耗內(nèi)存
兩者的時間復雜度都是o(n)
RDB文件觸發(fā)機制
除了前面介紹的三種:自動,save,bgsave外,還有下面幾種方式也會生成RDB文件:
全量復制:主從復制中,主節(jié)點會自動生成RDB文件給從節(jié)點同步使用
debug reload
shutdown
Redis啟動后會讀取RDB快照文件,將數(shù)據(jù)從硬盤載入到內(nèi)存。通常將一個記錄一千萬個字符串類型鍵、大小為1GB的快照文件載入到內(nèi)存中需要花費20~30秒鐘。通過RDB方式實現(xiàn)持久化,一旦Redis異常退出,就會丟失最后一次快照以后更改的所有數(shù)據(jù)。如果數(shù)據(jù)很重要以至于無法承受任何損失,則可以考慮使用AOF方式進行持久化。
RDB方式的優(yōu)點:
性能最大化,fork子進程來完成寫操作,讓主進程繼續(xù)處理命令,使用單獨子進程來進行持久化,保證了redis的高性能
當重啟恢復數(shù)據(jù)的時候,數(shù)據(jù)量比較大時,Redis直接解析RDB二進制文件,生成對應的數(shù)據(jù)存儲在內(nèi)存中,比AOF的啟動效率更高
RDB方式的缺點:
數(shù)據(jù)安全性低,RDB是間隔一段時間進行持久化,如果持久化之間redis發(fā)生故障,會發(fā)生數(shù)據(jù)丟失,所以這種方式更適合數(shù)據(jù)要求不嚴謹?shù)臅r候
linux fork之后,kernel把父進程中所有的內(nèi)存頁的權限都設為read-only,然后子進程的地址空間指向父進程。當父子進程都只讀內(nèi)存時,相安無事。
當其中某個進程寫內(nèi)存時,CPU硬件檢測到內(nèi)存頁是read-only的,于是觸發(fā)頁的異常中斷(page-fault),陷入kernel的一個中斷例程
中斷例程中,kernel的copyonwrite機制就會把觸發(fā)的異常的頁復制一份,于是父子進程各自持有獨立的一份,如果這時有大量的寫入操作,會產(chǎn)生大量的分頁錯誤,這樣就得耗費不少性能在復制上
三、AOF方式
默認情況下Redis沒有開啟AOF(append only file)方式的持久化,可以通過appendonly參數(shù)開啟:
appendonly yes開啟AOF持久化后每執(zhí)行一條會更改Redis中的數(shù)據(jù)的命令,Redis就會將該命令寫入硬盤中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通過dir參數(shù)設置的,默認的文件名是appendonly.aof,可以通過appendfilename參數(shù)修改:
appendfilename appendonly.aof下面介紹AOF持久化的具體實現(xiàn),假設在開啟AOF持久化的情況下執(zhí)行了如下4個命令:
SET foo 1 SET foo 2 SET foo 3 GET fooRedis會將前3條命令寫入AOF文件中,此時AOF文件中的內(nèi)容如下:
*2$6SELECT$10*3$3set$3foo$11*3$3set$3foo$12*3$3set$3foo$13可見AOF文件是純文本文件,其內(nèi)容正是Redis客戶端向Redis發(fā)送的原始通信協(xié)議的內(nèi)容。
這里有一個問題是前2條命令其實都是冗余的, 因為這兩條的執(zhí)行結果會被第三條命令覆蓋。隨著執(zhí)行的命令越來越多,AOF文件的大小也會越來越大。實際上每當達到一定條件時Redis就會自動重寫AOF文件,這個條件可以在配置文件中設置:
auto-aof-rewrite-percentage?100?//代表當前AOF文件空間和上一次重寫后AOF文件空間的比值auto-aof-rewrite-min-size?64mb?//表示運行AOF重寫時文件最小體積,默認64MBauto-aof-rewrite-percentage參數(shù)的意思是當目前的AOF文件大小超過上一次重寫時的AOF 文件大小的百分之多少時會再次進行重寫,如果之前沒有重寫過,則以啟動時的AOF文件大小為依據(jù)
auto-aof-rewrite-min-size參數(shù)限制了允許重寫的最小AOF文件大小,通常在AOF文 件很小的情況下即使其中有很多冗余的命令我們也并不太關心
除了讓Redis自動執(zhí)行重寫外,還可以主動使用BGREWRITEAOF命令手動執(zhí)行AOF重寫。
AOF文件重寫后的內(nèi)容為:
*2$6SELECT$10*3$3set$3foo$13在啟動時Redis會逐個執(zhí)行AOF文件中的命令來將硬盤中的數(shù)據(jù)載入到內(nèi)存中,載入的速度相較RDB會慢一些。下面是AOF重寫的流程:
注意:雖然每次執(zhí)行更改數(shù)據(jù)庫內(nèi)容的操作時,AOF都會將命令記錄在AOF文件中,但是由于操作系統(tǒng)的緩存機制,數(shù)據(jù)并沒有真正地寫入硬盤,而是進入了系統(tǒng)的硬盤緩存。在默認情況下系統(tǒng)每30秒會執(zhí)行一次同步操作,以便將硬盤緩存中的內(nèi)容真正地寫入硬盤,在這30秒的過程中如果系統(tǒng)異常退出則會導致硬盤緩存中的數(shù)據(jù)丟失。一般來講啟用AOF持久化的應用都無法容忍這樣的損失,這就需要Redis在寫入AOF文件后主動要求系統(tǒng)將緩存內(nèi)容同步到硬盤中。在Redis中我們可以通過appendfsync參數(shù)設置同步的時機:
# appendfsync always appendfsync everysec # appendfsync no默認情況下Redis采用everysec 規(guī)則,即每秒執(zhí)行一次同步操作
always表示每次執(zhí)行寫入都會執(zhí)行同步,這是最安全也是最慢的方式
no表示不主動進行同步操作,而是完全交由操作系統(tǒng)來做(即每30秒一次),這是最快但最不安全的方式
AOF追加阻塞
主線程為了達到每秒刷盤的策略,它會執(zhí)行AOF追加阻塞,流程如下:
所以可能產(chǎn)生的問題:
主線程阻塞,主線程需要執(zhí)行我們?nèi)粘C畹奶幚?#xff0c;所以主線程不能阻塞
每秒刷盤的策略不是只丟失1秒的數(shù)據(jù),實際上可能丟失2秒的數(shù)據(jù)
AOF阻塞定位可以通過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也可以通過Redis命令:
127.0.0.1:6379>?info?persistence......aof_delayed_fsync:100......也可以通過top命令觀察硬盤IO資源比較緊張的情況:
AOF配置參數(shù)最佳實踐
appendonly yesappendfilename?appendonly-${port}.aofappendfsync everysec no-appendfsync-on-rewrite?yes?//?aof重寫時是否做aof的append操作(否)Redis允許同時開啟AOF和RDB,既保證了數(shù)據(jù)安全又使得進行備份等操作十分容易。此時重新啟動Redis后Redis會使用AOF文件來恢復數(shù)據(jù),因為AOF方式的持久化可能丟失的數(shù)據(jù)更少。
AOF方式的優(yōu)點:
數(shù)據(jù)安全
AOF方式的缺點:
數(shù)據(jù)集大的時候,比RDB啟動效率低
fork操作介紹
fork操作只是做一個內(nèi)存頁(4K)的拷貝而不是拷貝整個內(nèi)存,所以在大部分情況下是非常快的。info:latest_fork_usec可以查看Redis持久化的時間。改善fork可以通過:
使用物理機或者高效支持fork操作的虛擬化技術
控制Redis實例最大可用內(nèi)存:maxmemory
合理配置Linux內(nèi)存分配策略:vm.overcommit_memory=1,當沒有足夠內(nèi)存去做內(nèi)存分配的時候就不去分配內(nèi)存,默認值是0
降低fork頻率,例如放寬AOF重寫機制的觸發(fā)時機,減少不必要的全量復制
子進程開銷和優(yōu)化
1. CPU
開銷:RDB和AOF文件生成,屬于CPU密集型,大量寫操作集中在這個時候
優(yōu)化:不做CPU綁定,不和CPU密集型部署
2.?內(nèi)存
開銷:copy-on-write,父子進程共享一個物理內(nèi)存頁,寫時會fork一個副本
優(yōu)化:不允許單機多部署時大量產(chǎn)生重寫
3.?硬盤
開銷:RDB和AOF文件寫入,可以結合iostat,iotop分析
優(yōu)化:不要和高硬盤負載服務部署一起:存儲服務,消息隊列等;no-appendfsync-on-rewrite=yes;大寫入量可以選用ssd;單機多實例持久化文件目錄可以考慮分盤
四、RDB與AOF對比
| 命令 | RDB | AOF |
| 啟動優(yōu)先級 | 低 | 高 |
| 體積 | 小 | 大 |
| 恢復速度 | 快 | 慢 |
| 數(shù)據(jù)安全性 | 丟數(shù)據(jù) | 根據(jù)策略決定 |
| 操作量級 | 重 | 輕 |
五、混合持久化
可以通過參數(shù)設置:aof-use-rdb-preamble yes開啟。
加載時,首先會識別AOF文件是否以REDIS字符串開頭,如果是,就按RDB格式加載,加載完RDB之后繼續(xù)按照AOF格式加載剩余部分。混合式持久化方案兼顧了RDB的速度和AOF的安全性。
推薦閱讀
Redis值類型之sorted set
Redis數(shù)據(jù)結構與內(nèi)部編碼,你知道多少?
看完本文有收獲?請轉發(fā)分享給更多人
關注「并發(fā)編程之美」,一起交流Java學習心得
總結
以上是生活随笔為你收集整理的redis 硬件要求_Redis持久化机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hi3516配置wifi_HISI 35
- 下一篇: mysql查询父子关系树_swt 生成树