一、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