- 持久化
- RDB方式
- Redis實現(xiàn)快照的過程
- AOF方式
- 操作系統(tǒng)緩存
- RDB與AOF
- RDB方式
- 復(fù)制
- 主從數(shù)據(jù)庫
- 主從復(fù)制的意義
- 安全
持久化
Redis通過將數(shù)據(jù)存儲在內(nèi)存中而獲得了極快的速度,但為了保證Redis在重啟后數(shù)據(jù)不丟失,需要將數(shù)據(jù)從內(nèi)存持久化到硬盤中。
持久化的方式有兩種,二者可以只用一種,也可以組合使用:
- RDB方式
- AOF方式
RDB方式
RDB是Redis默認(rèn)采用的持久化方式,當(dāng)符合一定條件時Redis會自動將內(nèi)存中的所有數(shù)據(jù)進行快照(snapshotting)并存儲在硬盤上。進行快照的條件可以由用戶在配置文件中自定義,配置由兩個參數(shù)構(gòu)成:時間和改動的鍵的個數(shù)。當(dāng)在指定的時間內(nèi)被更改的鍵的個數(shù)大于指定的數(shù)值時就會進行快照。在配置文件redis.conf中已經(jīng)預(yù)置了3個條件:
save 900 1
save 300 10
save 60 10000
這些條件直接是“或”的關(guān)系。如果需要禁用自動快照,可以將所有的save配置刪除。
除了自動快照,還可以手動發(fā)送SAVE或BGSAVE命令讓Redis執(zhí)行快照,SAVE命令是由主進程進行快照操作,會阻塞住其他請求,而BGSAVE命令則會通過fork子進程進行快照操作。
Redis默認(rèn)會將快照文件存儲在當(dāng)前目錄的dump.rdb文件中,可以通過配置dir和dbfilename兩個參數(shù)分別指定快照文件的存儲路徑和文件名。
Redis實現(xiàn)快照的過程
RDB快照的過程為:
- Redis使用fork函數(shù)復(fù)制一份當(dāng)前進程(父進程)的副本(子進程);
- 父進程繼續(xù)接收并處理客戶端發(fā)來的命令,子進程則開始將內(nèi)存中的數(shù)據(jù)寫入硬盤中的臨時文件;
- 當(dāng)子進程寫入完所有數(shù)據(jù)后,會用該臨時文件替換舊的RDB文件,至此一次快照操作完成。
- Redis重新啟動時會讀取RDB快照文件,將數(shù)據(jù)從硬盤載入到內(nèi)存。(根據(jù)數(shù)據(jù)量大小與結(jié)構(gòu)和服務(wù)器性能不同,這個時間也不同。通常將一個記錄一千萬個字符串類型鍵、大小為1GB的快照文件載入到內(nèi)存中需要花費20~30秒鐘)。
Redis在進行快照的過程中不會修改RDB文件,只有快照結(jié)束后才會將舊的文件替換成新的,也就是說任何時候RDB文件都是完整的,所以可以通過定時備份RDB文件來實現(xiàn)Redis數(shù)據(jù)庫備份。RDB文件是經(jīng)過壓縮的二進制格式,占用的空間會小于內(nèi)存中的數(shù)據(jù)大小。但壓縮過程也會增加CPU占用,如有需要可以通過修改配置rdbcompression參數(shù)以禁用壓縮。
config set rdbcompression no
AOF方式
AOF全稱為append only file,在這種持久化方式下,每執(zhí)行一條會更改Redis中的數(shù)據(jù)的命令,Redis都會將該命令寫入硬盤中的AOF文件。
AOF文件的保存位置和RDB文件的位置相同,都可以通過dir參數(shù)設(shè)置,默認(rèn)的文件名是appendonly.aof,可以通過appendfilename參數(shù)修改。
AOF文件是純文本文件,其內(nèi)容是Redis客戶端向Redis發(fā)送的原始通信協(xié)議的內(nèi)容。設(shè)想執(zhí)行這樣幾條命令:
SET key1 1
SET key1 2
SET key1 3
AOF文件中會記錄這三次操作,但實際上前兩條實際上是多余的,只需要記錄最終一次的命令即可。隨著執(zhí)行的命令越來越多,AOF文件也會越來越大,而Redis可以通過去除這類多余命令記錄,自動對AOF文件進行優(yōu)化。
每當(dāng)達(dá)到一定條件時Redis就會自動重寫AOF文件,這個條件可以在配置文件中設(shè)置:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
auto-aof-rewrite-percentage設(shè)置當(dāng)目前的AOF文件大小超過上一次重寫時的AOF文件大小的百分之多少時會再次進行重寫,如果之前沒有重寫過,則以啟動時的AOF文件大小為依據(jù)。
auto-aof-rewrite-min-size則限制了允許重寫的最小AOF文件大小,通常在AOF文件很小的情況下即使其中有很多冗余的命令也不需要重寫。
除了讓Redis自動執(zhí)行重寫外,還可以主動使用BGREWRITEAOF命令手動執(zhí)行AOF重寫。
在重啟時Redis會逐個執(zhí)行AOF文件中的命令來將硬盤中的數(shù)據(jù)載入到內(nèi)存中,載入的速度相較RDB會慢一些。
操作系統(tǒng)緩存
雖然每次執(zhí)行更改數(shù)據(jù)庫內(nèi)容的操作時,AOF都會將命令記錄在AOF文件中,但實際上由于操作系統(tǒng)的緩存機制的存在,數(shù)據(jù)并沒有真正地寫入硬盤,而是進入了系統(tǒng)的硬盤緩存。在默認(rèn)情況下系統(tǒng)每30秒會執(zhí)行一次同步操作,以便將硬盤緩存中的內(nèi)容真正地寫入硬盤,在這30秒的過程中如果系統(tǒng)異常退出則會導(dǎo)致硬盤緩存中的數(shù)據(jù)丟失。一般來講啟用AOF持久化的應(yīng)用都無法容忍這樣的損失,這就需要Redis在寫入AOF文件后主動要求系統(tǒng)將緩存內(nèi)容同步到硬盤中。
可以通過appendfsync參數(shù)設(shè)置同步的時機:
config set appendfsync always/eversec/no
- always 每次執(zhí)行寫入都會執(zhí)行同步,這種模式最安全但也最慢
- everysec 每秒同步一次
- no 不主動進行同步操作,操作系統(tǒng)沒30秒同步一次
RDB與AOF
如果選擇RDB的持久化方式,一旦Redis異常退出,就會丟失最后一次快照以后更改的所有數(shù)據(jù)。這就需要開發(fā)者根據(jù)具體的應(yīng)用場合,通過組合設(shè)置自動快照條件的方式來將可能發(fā)生的數(shù)據(jù)損失控制在能夠接受的范圍。如果數(shù)據(jù)很重要以至于無法承受任何損失,則可以考慮使用AOF方式進行持久化。
可以同時開啟AOF和RDB,這樣既保證了數(shù)據(jù)安全,又使得進行備份等操作十分容易。此時重新啟動Redis后Redis會使用AOF文件來恢復(fù)數(shù)據(jù),因為AOF方式的持久化可能丟失的數(shù)據(jù)更少。
復(fù)制
Redis的持久化功能可以保證在服務(wù)器重啟的情況下不會損失(或少量損失)數(shù)據(jù)。但是由于數(shù)據(jù)只存儲在一臺服務(wù)器,如果這臺服務(wù)器的硬盤出現(xiàn)故障,也會導(dǎo)致數(shù)據(jù)丟失。為了避免單點故障,將數(shù)據(jù)庫復(fù)制多個副本以部署在不同的服務(wù)器上,組成集群,這樣即使有一臺服務(wù)器出現(xiàn)故障時,其他服務(wù)器依然可以繼續(xù)提供服務(wù),此外也提升了整體的性能。
Redis提供了復(fù)制(replication)功能用以保障構(gòu)成集群的多臺服務(wù)器之間數(shù)據(jù)的同步。
主從數(shù)據(jù)庫
構(gòu)成集群的數(shù)據(jù)庫分為兩類,主數(shù)據(jù)庫(master)和從數(shù)據(jù)庫(slave)。主數(shù)據(jù)庫可以進行讀寫操作,當(dāng)發(fā)生寫操作時自動將數(shù)據(jù)同步給從數(shù)據(jù)庫。而從數(shù)據(jù)庫一般是只讀的,并接受主數(shù)據(jù)庫同步過來的數(shù)據(jù)。主從數(shù)據(jù)庫是一對多的關(guān)系。
要把一個數(shù)據(jù)庫作為從數(shù)據(jù)庫,需要在啟動參數(shù)或者配置文件中加入:
slaveof 主數(shù)據(jù)庫的IP 端口
接下來使用redis的docker鏡像試驗主從復(fù)制,首先啟動兩個實例:
docker run --name redis-6379 -p 6379:6379 -d redis
docker run --name redis-6380 -p 6380:6379 -d redis
redis-6379將被作為主數(shù)據(jù)庫,redis-6380為從庫,首先獲取redis-6379容器的內(nèi)網(wǎng)IP地址:
docker inspect redis-6379
在"NetworkSettings"結(jié)點下可以看到IP和端口為172.17.0.2 6379
進入redis-6380,設(shè)置其為從數(shù)據(jù)庫:
> docker exec -it redis-6380 /bin/bash
root@cd19cbbab6d9:/data# redis-cli
127.0.0.1:6379> SLAVEOF 172.17.0.2 6379
這樣主從數(shù)據(jù)庫就設(shè)置好了,可以測試下在主數(shù)據(jù)庫插入一個鍵,然后在從數(shù)據(jù)庫讀取。
從數(shù)據(jù)庫默認(rèn)是只讀的,嘗試寫入將提示:
SET KEY1 1
(error) READONLY You can't write against a read only replica.
可以通過設(shè)置從數(shù)據(jù)庫的配置文件中的slave-read-only為no以使從數(shù)據(jù)庫可寫,但是對從數(shù)據(jù)庫的任何更改都不會同步給其他數(shù)據(jù)庫,并且一旦主數(shù)據(jù)庫中更新了對應(yīng)的數(shù)據(jù)就會覆蓋從數(shù)據(jù)庫中的改動。
在redis實例運行也可以使用SLAVEOF命令,如果該數(shù)據(jù)庫已經(jīng)是其他主數(shù)據(jù)庫的從數(shù)據(jù)庫,則SLAVEOF命令會停止和原來數(shù)據(jù)庫的同步轉(zhuǎn)而和新數(shù)據(jù)庫同步。還可以使用SLAVEOF NO ONE來使當(dāng)前數(shù)據(jù)庫停止接收其他數(shù)據(jù)庫的同步轉(zhuǎn)成主數(shù)據(jù)庫。
主從復(fù)制的意義
數(shù)據(jù)冗余:主從復(fù)制實現(xiàn)了數(shù)據(jù)的熱備份,是持久化之外的一種數(shù)據(jù)冗余方式。
故障恢復(fù):當(dāng)主節(jié)點出現(xiàn)問題時,可以由從節(jié)點提供服務(wù),實現(xiàn)快速的故障恢復(fù);實際上是一種服務(wù)的冗余。
讀寫分離:可以用于實現(xiàn)讀寫分離,主庫寫、從庫讀,讀寫分離不僅可以提高服務(wù)器的負(fù)載能力,同時可根據(jù)需求的變化,改變從庫的數(shù)量;
負(fù)載均衡:在主從復(fù)制的基礎(chǔ)上,配合讀寫分離,可以由主節(jié)點提供寫服務(wù),由從節(jié)點提供讀服務(wù)分擔(dān)服務(wù)器負(fù)載;尤其是在寫少讀多的場景下,通過多個從節(jié)點分擔(dān)讀負(fù)載,可以大大提高Redis服務(wù)器的并發(fā)量。
- 高可用基石:除了上述作用以外,主從復(fù)制還是哨兵和集群能夠?qū)嵤┑幕A(chǔ),因此說主從復(fù)制是Redis高可用的基礎(chǔ)。
安全
在安全方面,Redis提供了下面幾種策略。
可信的環(huán)境
Redis安全設(shè)計都是建立在“Redis運行在可信環(huán)境”這個前提下的,在生產(chǎn)環(huán)境運行時不能允許外界直接連接到Redis服務(wù)器上,而應(yīng)該通過應(yīng)用程序進行中轉(zhuǎn),運行在可信的環(huán)境中是保證Redis安全的最重要方法。
Redis的默認(rèn)會接受來自任何地址發(fā)送來的請求,要更改這一設(shè)置,可以在配置文件中修改bind參數(shù),如只允許本機應(yīng)用連接Redis,可以將bind參數(shù)改成:
bind 127.0.0.1
密碼
要設(shè)置密碼,可以修改配置文件中的requirepass參數(shù),例如:
requirepass 123456
docker鏡像也可以在啟動容器的時候設(shè)置密碼:
docker run --name redis-test -p 6379:6379 redis --requirepass 123456
添加密碼后,客戶端在連接時需要輸入密碼:
redis-cli -h 127.0.0.1 -p 6379 -a 123456
設(shè)置密碼后,如果要搭建主從數(shù)據(jù)庫,需要在從數(shù)據(jù)庫配置文件中的masterauth添加主數(shù)據(jù)庫的密碼。
需要注意的是,由于Redis的性能極高,并且輸入錯誤密碼后Redis并不會進行主動延遲,所以攻擊者可以通過窮舉法破解Redis的密碼(1秒內(nèi)能夠嘗試十幾萬個密碼),因此在設(shè)置時一定要選擇復(fù)雜的密碼。
命令重命名
Redis支持在配置文件中將命令重命名,比如將FLUSHALL命令重命名成一個比較復(fù)雜的名字,以保證只有自己的應(yīng)用可以使用該命令:
rename-command FLUSHALL oiuyhjkghjgyutdfhbuhbnjinjbgyvtcrd
如果希望直接禁用某個命令,可以將命令重命名成空字符串。