三千字介紹Redis主從+哨兵+叢集

女友在高考發表於2021-09-30

一、Redis持久化策略

1.RDB

每隔幾分鐘或者一段時間會將redis記憶體中的資料全量的寫入到一個檔案中去。

優點:

  1. 因為他是每隔一段時間的全量備份,代表了每個時間段的資料。所以適合做冷備份。
  2. RDB對redis的讀寫影響非常小,因為redis主程式只需要fork一個子程式進行磁碟IO操作就行了。
  3. 相對於AOF來說,恢復較快,因為一個RDB就是資料檔案,而AOF存的是指令日誌。

缺點:

  1. 因為是一段時間才備份,所以容易丟資料。
  2. 如果一次寫入的檔案大,會導致讀寫服務暫停幾毫秒,甚至幾秒。

2.AOF

會將每條寫入指令都寫入到linux os快取中去,然後每秒鐘會將linux os中的指令作為日誌追加到AOF的檔案裡面。

當redis記憶體大小達到一定的量,會通過LRU(最近最少使用)淘汰機制淘汰掉資料,然後再重寫一個新的AOF檔案出來。這樣也保證了AOF檔案不會無限制的增大。

優點:

  1. 不易丟資料
  2. AOF日誌檔案是以append-only的模式寫入,沒有磁碟定址的開銷,寫入效能高,檔案也不易破損
  3. AOF檔案過大的時候,後臺重寫操作,也不會影響客戶端。再rewrite的時候,會對指令壓縮,建立出一份需要恢復的最小日誌出來,再建立新日誌檔案時,老的檔案照常寫入,當新檔案準備好了,再交換新老日誌檔案就行了
  4. 日誌檔案的命令是可讀的,可以作為誤刪的緊急恢復。停了服務,再把那條刪除指令刪除,再恢復就行了。

缺點:

  1. AOF日誌檔案佔用的磁碟空間比較大
  2. 開啟AOF後,寫操作的QPS會下降
  3. 以前出過bug,恢復的資料和原來不一樣,健壯性沒有RDB高
  4. 恢復資料慢,且不適合做冷備(需要手動寫指令碼)

3.混合持久化(Redis 4.0)

開啟混合持久化

aof-use-rdb-preamble yes

綜合來說:

我們可以採用兩種都用的的方案,RDB做冷備,為了保證資料不丟失,AOF做資料恢復的第一選擇。

如何配置持久化?

  1. 找到/usr/local/package/redis-4.0.9/redis.conf

  2. RDB的配置

 //每隔60秒,如果有10000個key發生改變就持久化一次
    save 60 10000
  1. 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
  1. AOF rewrite過程

    1. redis fork一個子程式
    2. 子程式基於當前記憶體中的資料開始寫入一個新的aof的檔案
    3. 這時新的命令進來,會存在記憶體中,也會存在舊的aof檔案中
    4. 當新的aof檔案寫好了,這個過程中的新的命令也會追加到aof裡來
    5. 然後用新日誌檔案替換掉舊的日誌檔案

注意:當使用shutdown命令關閉redis服務時,會自動備份一個快照

當RDB生成快照時,AOF不會rewrite。反之亦然。

redis如果遇到斷電或機器故障問題時怎麼辦?

答:一般使用持久化加伺服器檔案(將檔案備份到阿里雲)備份的方案

二、Redis淘汰策略

LRU:(least recently used)最近最少使用

  1. 標準的LRU演算法:

使用HashMap+雙向連結串列

核心步驟:

  1. save操作時,在hashmap中找對應的key值,如果存在,更新他並移到隊頭,如果不存在,則構建新節點,並移到隊頭,如果佇列滿了,則移除隊尾的節點,並在hashmap中移除該key
  2. get操作時,在hashmap中找到對應的節點,將他移到隊頭

redis裡面沒有使用雙向連結串列的實現方式,而是使用了一個pool池.

  1. 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.主從特性

  1. 採用非同步的方式複製到slave節點,不過redis2.8之後,每個slave節點會週期性的確認自己每次複製的資料量
  2. 一個master可以配置多個slave
  3. slave node也可以連線其他的slave node
  4. slave複製時不影響master的工作
  5. slave複製時也不會影響slave的查詢操作,他會用舊的資料提供服務。但是當複製完成,需要刪除舊資料,載入新資料集時,會暫停服務。
  6. slave主要用來做橫向擴容,做讀寫分離

2.主從複製步驟

  1. 當slave第一次連線時,master會生成一個全量RDB檔案給他做恢復,並將這個過程中新的寫入命令快取在記憶體中,等slave把RDB檔案讀入之後發給他
  2. 當slave斷開一段時間後重連,master會將缺失的資料發給他
  3. 平時情況下,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.配置主從伺服器

  1. 安裝redis
  2. cp utils/redis_init_script /etc/init.d/redis_6379
  3. redis自啟動 chkconfig redis_6379 on
  4. mkdir /etc/redis
  5. mkdir -p /var/redis/6379
  6. cp redis.conf /etc/redis/6379.conf
  7. 修改配置檔案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
  1. 讓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.概念介紹

介紹:

  1. 叢集監控,監控master和slave是否正常
  2. 訊息通知,如果某個redis例項故障了,負責發訊息給管理員
  3. 故障轉移,如果master節點掛掉了,會自動轉移到slave上
  4. 配置中心,如果故障轉移發生了,通知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.部署哨兵

  1. 複製配置檔案
    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
  1. 修改配置檔案
  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的那些其他配置之前

  1. 啟動哨兵

./redis-sentinel /etc/sentinel/5000.conf

五、redis叢集

1.概念介紹

  1. 自動對資料進行分片,每個master上存放一部分資料
  2. 提供內建的高可用支援,部分master不可用了,還是可以繼續工作的

2.部署選型
redis cluster VS replication + sentinel

當資料量少,主要承載的是高併發時,單機就足夠了。一個master多個slave,在搭建一個sentinel叢集來保證高可用性

redis cluster主要還是用來做海量資料的快取。

3.分散式Hash演算法

當需要把資料分到不同的幾個機器儲存時,就需要一個演算法了。

  1. 方法一:取模
    對資料的hash值取模,比如有3臺集器,那麼就用hash%3,得到的就是0-2的三個數字,就可以確定將資料存在哪一臺上面了

缺點:如果有一臺機器掛掉了,那麼資料會對2取模,那麼得到的機器號就錯亂了,導致大量資料不能從正確的機器上去取

  1. 方法二:一致性hash演算法(圓環演算法)

將3臺機器放在一個圓環上,然後要快取的資料經過計算也落在圓環的某一個點,然後順時針去環上找離他最近的那個機器。

優點:當一臺機器掛掉,不影響其他的機器上存的資料

缺點:具有熱點問題,可能某一個機器會有大量資料,這就需要將每個機器都多設定幾個虛擬節點,均勻分佈在圓環上。

  1. 方法三:redis cluster的hash slot演算法

redis cluster有固定的16384個slot,對每個key計算CRC16值,然後對16384取模,獲取對應的slot,每個master都有部分的slot。這樣的話如果增加一個master,就將其他master上的slot分點給她就行了。

4.部署redis叢集

  1. 建立目錄
  mkdir -p /etc/redis-cluster
  mkdir -p /var/log/redis
  mkdir /var/redis/7001
  mkdir /var/redis/7002
  1. 修改配置檔案 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"
  1. 修改配置檔案
vi /usr/local/share/gems/gems/redis-3.2.1/lib/redis/client.rb

password=123456
  1. 執行
 echo never > /sys/kernel/mm/transparent_hugepage/enabled
  1. 啟動指令碼
   cd /etc/init.d/
   cp redis_6379 redis_7001
修改redis_7001配置

  REDISPORT=7001
  1. 安裝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
  1. 檢查節點狀態
 ./redis-trib.rb check 192.168.1.12 7001

相關文章