一、Redis持久化策略
1.RDB
每隔幾分鐘或者一段時間會將redis記憶體中的資料全量的寫入到一個檔案中去。
優點:
- 因為他是每隔一段時間的全量備份,代表了每個時間段的資料。所以適合做冷備份。
- RDB對redis的讀寫影響非常小,因為redis主程式只需要fork一個子程式進行磁碟IO操作就行了。
- 相對於AOF來說,恢復較快,因為一個RDB就是資料檔案,而AOF存的是指令日誌。
缺點:
- 因為是一段時間才備份,所以容易丟資料。
- 如果一次寫入的檔案大,會導致讀寫服務暫停幾毫秒,甚至幾秒。
2.AOF
會將每條寫入指令都寫入到linux os快取中去,然後每秒鐘會將linux os中的指令作為日誌追加到AOF的檔案裡面。
當redis記憶體大小達到一定的量,會通過LRU(最近最少使用)淘汰機制淘汰掉資料,然後再重寫一個新的AOF檔案出來。這樣也保證了AOF檔案不會無限制的增大。
優點:
- 不易丟資料
- AOF日誌檔案是以append-only的模式寫入,沒有磁碟定址的開銷,寫入效能高,檔案也不易破損
- AOF檔案過大的時候,後臺重寫操作,也不會影響客戶端。再rewrite的時候,會對指令壓縮,建立出一份需要恢復的最小日誌出來,再建立新日誌檔案時,老的檔案照常寫入,當新檔案準備好了,再交換新老日誌檔案就行了
- 日誌檔案的命令是可讀的,可以作為誤刪的緊急恢復。停了服務,再把那條刪除指令刪除,再恢復就行了。
缺點:
- AOF日誌檔案佔用的磁碟空間比較大
- 開啟AOF後,寫操作的QPS會下降
- 以前出過bug,恢復的資料和原來不一樣,健壯性沒有RDB高
- 恢復資料慢,且不適合做冷備(需要手動寫指令碼)
3.混合持久化(Redis 4.0)
開啟混合持久化
aof-use-rdb-preamble yes
綜合來說:
我們可以採用兩種都用的的方案,RDB做冷備,為了保證資料不丟失,AOF做資料恢復的第一選擇。
如何配置持久化?
-
找到/usr/local/package/redis-4.0.9/redis.conf
-
RDB的配置
//每隔60秒,如果有10000個key發生改變就持久化一次
save 60 10000
- AOF的配置
# redis預設關閉AOF機制,可以將no改成yes實現AOF持久化
appendonly no
# AOF檔案
appendfilename "appendonly.aof"
# AOF持久化同步頻率,always表示每個Redis寫命令都要同步fsync寫入到磁碟中,但是這種方式會嚴重降低redis的速度;everysec表示每秒執行一次同步fsync,顯示的將多個寫命令同步到磁碟中;no表示讓作業系統來決定應該何時進行同步fsync,Linux系統往往可能30秒才會執行一次
# appendfsync always
appendfsync everysec
# appendfsync no
# 在日誌進行BGREWRITEAOF時,如果設定為yes表示新寫操作不進行同步fsync,只是暫存在緩衝區裡,避免造成磁碟IO操作衝突,等重寫完成後在寫入。redis中預設為no
no-appendfsync-on-rewrite no
# 當前AOF檔案大小是上次日誌重寫時的AOF檔案大小兩倍時,發生BGREWRITEAOF操作。
auto-aof-rewrite-percentage 100
#當前AOF檔案執行BGREWRITEAOF命令的最小值,避免剛開始啟動Reids時由於檔案尺寸較小導致頻繁的BGREWRITEAOF。
auto-aof-rewrite-min-size 64mb
# Redis再恢復時,忽略最後一條可能存在問題的指令(因為最後一條指令可能存在問題,比如寫一半時突然斷電了)
aof-load-truncated yes
#Redis4.0新增RDB-AOF混合持久化格式,在開啟了這個功能之後,AOF重寫產生的檔案將同時包含RDB格式的內容和AOF格式的內容,其中RDB格式的內容用於記錄已有的資料,而AOF格式的記憶體則用於記錄最近發生了變化的資料,這樣Redis就可以同時兼有RDB持久化和AOF持久化的優點(既能夠快速地生成重寫檔案,也能夠在出現問題時,快速地載入資料)。
aof-use-rdb-preamble no
-
AOF rewrite過程
- redis fork一個子程式
- 子程式基於當前記憶體中的資料開始寫入一個新的aof的檔案
- 這時新的命令進來,會存在記憶體中,也會存在舊的aof檔案中
- 當新的aof檔案寫好了,這個過程中的新的命令也會追加到aof裡來
- 然後用新日誌檔案替換掉舊的日誌檔案
注意:當使用shutdown命令關閉redis服務時,會自動備份一個快照
。
當RDB生成快照時,AOF不會rewrite。反之亦然。
redis如果遇到斷電或機器故障問題時怎麼辦?
答:一般使用持久化加伺服器檔案(將檔案備份到阿里雲)備份的方案
二、Redis淘汰策略
LRU:(least recently used)最近最少使用
- 標準的LRU演算法:
使用HashMap+雙向連結串列
核心步驟:
- save操作時,在hashmap中找對應的key值,如果存在,更新他並移到隊頭,如果不存在,則構建新節點,並移到隊頭,如果佇列滿了,則移除隊尾的節點,並在hashmap中移除該key
- get操作時,在hashmap中找到對應的節點,將他移到隊頭
redis裡面沒有使用雙向連結串列的實現方式,而是使用了一個pool池.
- Redis的LRU實現
常用策略:allkeys-lru
Redis使用的是近似LRU演算法
- 給每個 key 增加一個額外 24bit 長度的小欄位, 儲存該 key 的最後一次訪問時間戳
- 當空間滿時, 隨機取樣取出 5 個 key (數量可配置), 按時間戳淘汰掉最舊的 key
- 迴圈第二步, 直到記憶體低於 maxmemory 值
- 隨機取樣的範圍取決於配置的策略是 volatile 還是 allkeys
Redis 3.0 開始, 增加了淘汰池進一步提升了近似 LRU 的效果:
- 上一次隨機取樣後未淘汰的 key, 會放入 淘汰池 留待下一次迴圈,
- 下一次隨機取樣的key會先和淘汰池中的key合併後, 再計算淘汰最舊的key
三、Redis主從架構
1.主從特性
- 採用非同步的方式複製到slave節點,不過redis2.8之後,每個slave節點會週期性的確認自己每次複製的資料量
- 一個master可以配置多個slave
- slave node也可以連線其他的slave node
- slave複製時不影響master的工作
- slave複製時也不會影響slave的查詢操作,他會用舊的資料提供服務。但是當複製完成,需要刪除舊資料,載入新資料集時,會暫停服務。
- slave主要用來做橫向擴容,做讀寫分離
2.主從複製步驟
- 當slave第一次連線時,master會生成一個全量RDB檔案給他做恢復,並將這個過程中新的寫入命令快取在記憶體中,等slave把RDB檔案讀入之後發給他
- 當slave斷開一段時間後重連,master會將缺失的資料發給他
- 平時情況下,master收到一個指令,都會馬上覆制給slave
3.斷點續傳
從redis2.8開始,就支援主從複製的斷點續傳
master中存了backlog,master和slave都會儲存一個replica offset,還有一個master id。如果中途網路斷了,slave會讓master從上次的replica offset開始繼續複製。
4.過期key處理
slave不會過期key,只會等master過期key之後或者根據,模LRU淘汰了key之後擬一個del命令發給slave
5.配置主從伺服器
- 安裝redis
- cp utils/redis_init_script /etc/init.d/redis_6379
- redis自啟動 chkconfig redis_6379 on
- mkdir /etc/redis
- mkdir -p /var/redis/6379
- cp redis.conf /etc/redis/6379.conf
- 修改配置檔案6379.conf
- daemonize yes //讓redis以daemon程式執行
- dir /var/redis/6379
- slaveof CentOS01 6379
- slave 伺服器的配置檔案上配 masterauth 123456
- master伺服器的配置檔案上配
requirepass 123456- 每個6379.conf裡都要將bind 127.0.0.1改成bind 自己本機的ip
- 讓redis跟隨系統啟動自動啟動
在redis_6379指令碼中,最上面,加入兩行註釋
#chkconfig: 2345 90 10
#description: Redis is a persistent key-value database
然後執行
chkconfig redis_6379 on
8. 壓測效能 ./redis-benchmark -c 50 -n 10000
複製原理圖:
注意:主從架構建議必須開啟master節點的持久化。
四、哨兵模式
1.概念介紹
介紹:
- 叢集監控,監控master和slave是否正常
- 訊息通知,如果某個redis例項故障了,負責發訊息給管理員
- 故障轉移,如果master節點掛掉了,會自動轉移到slave上
- 配置中心,如果故障轉移發生了,通知client新的master地址
2.故障轉移
哨兵至少要3個例項
如圖:
如果只有2個哨兵會如何呢?
master當機,s1和s2中只要有1個哨兵認為master當機就可以進行切換,同時s1和s2中會選舉出一個哨兵來執行故障轉移
同時這個時候,需要majority,也就是大多數哨兵都是執行的,2個哨兵的majority就是2(2的majority=2,3的majority=2,5的majority=3,4的majority=2),2個哨兵都執行著,就可以允許執行故障轉移
但是如果整個M1和S1執行的機器當機了,那麼哨兵只有1個了,此時就沒有majority來允許執行故障轉移,雖然另外一臺機器還有一個R1,但是故障轉移不會執行
3.解決非同步複製和腦裂導致的資料丟失
min-slaves-to-write 1
min-slaves-max-lag 10
要求至少有1個slave,資料複製和同步的延遲不能超過10秒
4.sdown和odown轉換機制
sdown:主觀當機,即一個哨兵覺得master當機了
odown:客觀當機,即quorum數量的哨兵覺得master當機了
5.哨兵叢集的自動發現機制
哨兵互相之間的發現,是通過redis的pub/sub系統實現的,每個哨兵都會往__sentinel__:hello這個channel裡傳送一個訊息,這時候所有其他哨兵都可以消費到這個訊息,並感知到其他的哨兵的存在
每隔兩秒鐘,每個哨兵都會往自己監控的某個master+slaves對應的__sentinel__:hello channel裡傳送一個訊息,內容是自己的host、ip和runid還有對這個master的監控配置
每個哨兵也會去監聽自己監控的每個master+slaves對應的__sentinel__:hello channel,然後去感知到同樣在監聽這個master+slaves的其他哨兵的存在
每個哨兵還會跟其他哨兵交換對master的監控配置,互相進行監控配置的同步
6.選舉演算法
如果一個master被認為odown了,而且majority哨兵都允許了主備切換,那麼某個哨兵就會執行主備切換操作,此時首先要選舉一個slave來
會考慮slave的一些資訊
(1)跟master斷開連線的時長
(2)slave優先順序
(3)複製offset
(4)run id
7.部署哨兵
- 複製配置檔案
mkdir -p /var/sentinel/5000
mkdir /etc/sentinel
mkdir -p /var/log/sentinal/5000
mv /usr/local/package/redis-4.0.9/sentinel.conf /etc/sentinel/5000.conf
- 修改配置檔案
port 5000
bind 192.168.1.14
sentinel monitor mymaster 192.168.1.12 6379 2
dir /var/sentinel/5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 60000
sentinel down-after-milliseconds mymaster 30000
sentinel auth-pass mymaster 123456
daemonize yes
logfile /var/log/sentinal/5000/sentinel.log
注意:sentinel monitor mymaster 192.168.1.12 6379 2 這行要放在使用mymaster的那些其他配置之前
- 啟動哨兵
./redis-sentinel /etc/sentinel/5000.conf
五、redis叢集
1.概念介紹
- 自動對資料進行分片,每個master上存放一部分資料
- 提供內建的高可用支援,部分master不可用了,還是可以繼續工作的
2.部署選型
redis cluster VS replication + sentinel
當資料量少,主要承載的是高併發時,單機就足夠了。一個master多個slave,在搭建一個sentinel叢集來保證高可用性
redis cluster主要還是用來做海量資料的快取。
3.分散式Hash演算法
當需要把資料分到不同的幾個機器儲存時,就需要一個演算法了。
- 方法一:取模
對資料的hash值取模,比如有3臺集器,那麼就用hash%3,得到的就是0-2的三個數字,就可以確定將資料存在哪一臺上面了
缺點:如果有一臺機器掛掉了,那麼資料會對2取模,那麼得到的機器號就錯亂了,導致大量資料不能從正確的機器上去取
- 方法二:一致性hash演算法(圓環演算法)
將3臺機器放在一個圓環上,然後要快取的資料經過計算也落在圓環的某一個點,然後順時針去環上找離他最近的那個機器。
優點:當一臺機器掛掉,不影響其他的機器上存的資料
缺點:具有熱點問題,可能某一個機器會有大量資料,這就需要將每個機器都多設定幾個虛擬節點,均勻分佈在圓環上。
- 方法三:redis cluster的hash slot演算法
redis cluster有固定的16384個slot,對每個key計算CRC16值,然後對16384取模,獲取對應的slot,每個master都有部分的slot。這樣的話如果增加一個master,就將其他master上的slot分點給她就行了。
4.部署redis叢集
- 建立目錄
mkdir -p /etc/redis-cluster
mkdir -p /var/log/redis
mkdir /var/redis/7001
mkdir /var/redis/7002
- 修改配置檔案 7001.conf
port 7001
cluster-enabled yes
cluster-config-file /etc/redis-cluster/node-7001.conf
cluster-node-timeout 15000
pidfile "/var/run/redis_7001.pid"
dir "/var/redis/7001"
logfile "/var/log/redis/7001.log"
- 修改配置檔案
vi /usr/local/share/gems/gems/redis-3.2.1/lib/redis/client.rb
password=123456
- 執行
echo never > /sys/kernel/mm/transparent_hugepage/enabled
- 啟動指令碼
cd /etc/init.d/
cp redis_6379 redis_7001
修改redis_7001配置
REDISPORT=7001
- 安裝ruby
yum install -y ruby
下載一個redis-3.2.1.gem,然後執行
gem install redis
cp /usr/local/package/redis-4.0.9/src/redis-trib.rb /usr/local/bin
/usr/local/bin/redis-trib.rb create --replicas 1 192.168.1.12:7001 192.168.1.12:7002 192.168.1.13:7003 192.168.1.13:7004 192.168.1.14:7005 192.168.1.14:7006
- 檢查節點狀態
./redis-trib.rb check 192.168.1.12 7001