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