Redis Sentinel-深入淺出原理和實戰

2021-02-13 SH的全棧筆記

本篇博客會簡單的介紹Redis的Sentinel相關的原理,同時也會在最後的文章給出「硬核的」實戰教程,讓你在了解原理之後,能夠實際上手的體驗整個過程。

之前的文章聊到了Redis的主從複製,聊到了其相關的原理和缺點,具體的建議可以看看我之前寫的文章Redis的主從複製。

總的來說,為了滿足Redis在真正複雜的生產環境的高可用,僅僅是用主從複製是明顯不夠的。例如,當master節點宕機了之後,進行主從切換的時候,我們需要人工的去做failover。

同時在流量方面,主從架構只能通過增加slave節點來擴展讀請求,「寫能力」由於受到master單節點的資源限制是無法進行擴展的。

這也是為什麼我們需要引入Sentinel。

Sentinel功能概覽

Sentinel其大致的功能如下圖。

Sentinel

Sentinel是Redis高可用的解決方案之一,本身也是分布式的架構,包含了「多個」Sentinel節點和「多個」Redis節點。而每個Sentinel節點會對Redis節點和其餘的Sentinel節點進行監控。

當其發現某個節點不可達時,如果是master節點就會與其餘的Sentinel節點協商。當大多數的Sentinel節點都認為master不可達時,就會選出一個Sentinel節點對master執行故障轉移,並通知Redis的調用方相關的變更。

相對於「主從」下的手動故障轉移,Sentinel的故障轉移是全自動的,「無需」人工介入。

Sentinel自身高可用❝

666,那我怎麼知道滿足它自身的高可用需要部署多少個Sentinel節點?

因為Sentinel本身也是分布式的,所以也需要部署多實例來保證自身集群的高可用,但是這個數量是有個最低的要求,最低需要「3個」

我去,你說3個就3個?我今天偏偏就只部署2個

你別槓...等我說了為什麼就必須要3個...

因為哨兵執行故障轉移需要「大部分」的哨兵都同意才行,如果只有兩個哨兵實例,正常運作還好,就像這樣。

如果哨兵所在的那臺機器由於機房斷電啊,光纖被挖啊等極端情況整個掛掉了,那麼另一臺哨兵即使發現了master故障之後想要執行故障轉移,但是它無法得到任何「其餘哨兵節點」的同意,此時也「永遠」無法執行故障轉移,那Sentinel豈不是成了一個擺設?

所以我們需要至少3個節點,來保證Sentinel集群自身的高可用。當然,這三個Sentinel節點肯定都推薦部署到「不同的」機器上,如果所有的Sentinel節點都部署到了同一臺機器上,那當這臺機器掛了,整個Sentinel也就不復存在了。

redis-sentinel-successquorum&majority❝

大部分?大哥這可是要上生產環境,大部分這個數量未免也太敷衍了,咱就不能專業一點?

前面提到的大部分哨兵同意涉及到兩個參數,一個叫quorum,如果Sentinel集群有quorum個哨兵認為master宕機了,就「客觀」的認為master宕機了。另一個叫majority...

等等等等,不是已經有了一個叫什麼quorum的嗎?為什麼還需要這個majority?

你能不能等我把話說完...

quorum剛剛講過了,其作用是判斷master是否處於宕機的狀態,僅僅是一個「判斷」作用。而我們在實際的生產中,不是說只「判斷」master宕機就完了, 我們不還得執行「故障轉移」,讓集群正常工作嗎?

同理,當哨兵集群開始進行故障轉移時,如果有majority個哨兵同意進行故障轉移,才能夠最終選出一個哨兵節點,執行故障轉移操作。

主觀宕機&客觀宕機❝

你剛剛是不是提到了「客觀宕機」?笑死,難不成還有主觀宕機這一說?

1607390948-22870

Sentinel中認為一個節點掛了有兩種類型:

Subjective Down,簡稱「sdown」,主觀的認為master宕機Objective Down,簡稱「odown」,客觀的認為master宕機

當一個Sentinel節點與其監控的Redis節點A進行通信時,發現連接不上,此時這個哨兵節點就會「主觀」的認為這個Redis數據A節點sdown了。為什麼是「主觀」?我們得先知道什麼叫主觀

未經分析推算,下結論、決策和行為反應,暫時不能與其他不同看法的對象仔細商討,稱為主觀。

簡單來說,因為有可能「只是」當前的Sentinel節點和這個A節點的網絡通信有問題,其餘的Sentinel節點仍然可以和A正常的通信。

sentinel-sdown

這也是為什麼我們需要引入「odown」,當大於等於了「quorum」個Sentinel節點認為某個節點宕機了,我們就「客觀」的認為這個節點宕機了。

當Sentinel集群客觀的認為master宕機,就會從所有的Sentinel節點中,選出一個Sentinel節點,來最終執行master的故障轉移。

那這個「故障轉移」具體要執行些什麼操作呢?我們通過一個圖來看一下。

通知調用的客戶端master發生了變化

通知其餘的原slave節點,去複製Sentinel選舉出來的新的master節點

如果此時原來的master又重新恢復了,Sentinel也會讓其去複製新的master節點。成為一個新的slave節點。

硬核教程❝

硬核教程旨在用最快速的方法,讓你在本地體驗Redis主從架構和Sentinel集群的搭建,並體驗整個故障轉移的過程。

❞前置要求準備compose文件

首先需要準備一個目錄,然後分別建立兩個子目錄。如下。

$ tree .
.
├── redis
│   └── docker-compose.yml
└── sentinel
    ├── docker-compose.yml
    ├── sentinel1.conf
    ├── sentinel2.conf
    └── sentinel3.conf

2 directories, 5 files

搭建Redis主從伺服器

redis目錄下的docker-compose.yml內容如下。

version: '3'
services:
  master:
    image: redis
    container_name: redis-master
    ports:
      - 6380:6379
  slave1:
    image: redis
    container_name: redis-slave-1
    ports:
      - 6381:6379
    command:  redis-server --slaveof redis-master 6379
  slave2:
    image: redis
    container_name: redis-slave-2
    ports:
      - 6382:6379
    command: redis-server --slaveof redis-master 6379

以上的命令,簡單解釋一下slaveof

就是讓兩個slave節點去複製container_name為redis-master的節點,這樣就組成了一個簡單的3個節點的主從架構

然後用命令行進入當前目錄,直接敲命令docker-compose up即可,剩下的事情交給docker-compose去做就好,它會把我們所需要的節點全部啟動起來。

此時我們還需要拿到剛剛我們啟動的master節點的IP,簡要步驟如下:

通過docker ps找到對應的master節點的containerID

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
9f682c199e9b        redis               "docker-entrypoint.s…"   3 seconds ago       Up 2 seconds        0.0.0.0:6381->6379/tcp   redis-slave-1
2572ab587558        redis               "docker-entrypoint.s…"   3 seconds ago       Up 2 seconds        0.0.0.0:6382->6379/tcp   redis-slave-2
f70a9d9809bc        redis               "docker-entrypoint.s…"   3 seconds ago       Up 2 seconds        0.0.0.0:6380->6379/tcp   redis-master

也就是f70a9d9809bc。

通過docker inspect f70a9d9809bc,拿到對應容器的IP,在NetworkSettings -> Networks -> IPAddress欄位。

然後把這個值給記錄下來,此處我的值為172.28.0.3。

搭建Sentinel集群

sentinel目錄下的docker-compose.yml內容如下。

version: '3'
services:
  sentinel1:
    image: redis
    container_name: redis-sentinel-1
    ports:
      - 26379:26379
    command: redis-sentinel /usr/local/etc/redis/sentinel.conf
    volumes:
      - ./sentinel1.conf:/usr/local/etc/redis/sentinel.conf
  sentinel2:
    image: redis
    container_name: redis-sentinel-2
    ports:
    - 26380:26379
    command: redis-sentinel /usr/local/etc/redis/sentinel.conf
    volumes:
      - ./sentinel2.conf:/usr/local/etc/redis/sentinel.conf
  sentinel3:
    image: redis
    container_name: redis-sentinel-3
    ports:
      - 26381:26379
    command: redis-sentinel /usr/local/etc/redis/sentinel.conf
    volumes:
      - ./sentinel3.conf:/usr/local/etc/redis/sentinel.conf
networks:
  default:
    external:
      name: redis_default

同樣在這裡解釋一下命令

redis-sentinel 命令讓 redis 以 sentinel 的模式啟動,本質上就是一個運行在特殊模式的 redis 伺服器。

和 redis-server 的區別在於,他們分別載入了不同的命令表,sentinel 中無法執行各種redis中特有的 set get操作。

建立三份一模一樣的文件,分別命名為sentinel1.conf、sentinel2.conf和sentinel3.conf。其內容如下:

port 26379
dir "/tmp"
sentinel deny-scripts-reconfig yes
sentinel monitor mymaster 172.28.0.3 6379 2
sentinel config-epoch mymaster 1
sentinel leader-epoch mymaster 1

可以看到,我們對於sentinel的配置文件中,sentinel monitor mymaster 172.28.0.3 6379 2表示讓它去監聽名為mymaster的master節點,注意此處的IP一定要是你自己master節點的IP,然後最後面的2就是我們之前提到的quorum。

然後命令行進入名為sentinel的目錄下,敲docker-compose up即可。至此,Sentinel集群便啟動了起來。

手動模擬master掛掉

然後我們需要手動模擬master掛掉,來驗證我們搭建的Sentinel集群是否可以正常的執行故障轉移。

命令行進入名為redis的目錄下,敲入如下命令。

docker-compose pause master

此時就會將master容器給暫停運行,讓我們等待「10秒」之後,就可以看到sentinel這邊輸出了如下的日誌。

redis-sentinel-2 | 1:X 07 Dec 2020 01:58:05.459 # +sdown master mymaster 172.28.0.3 6379
.
.
.
redis-sentinel-1 | 1:X 07 Dec 2020 01:58:06.932 # +switch-master mymaster 172.28.0.3 6379 172.28.0.2 6379

得得得,你幹什麼就甩一堆日誌文件上來?湊字數?你這樣鬼能看懂?

的確,光從日誌文件一行一行的看,就算是我自己過兩周再來看,也是一臉懵逼。日誌文件完整了描述了整個Sentinel集群從開始執行故障轉移到最終執行完成的所有細節,但是在這裡直接放出來不方便大家的理解。

所以為了讓大家能夠更加直觀的了解這個過程,我簡單的把過程抽象了成了一張圖,大家看圖結合日誌,應該能夠更容易理解。

sentinel-process

裡面關鍵的步驟步驟的相關解釋我也一併放入了圖片中。

最終的結果就是,master已經從我們最開始的172.28.0.3切換到了172.28.0.2,後者則是原來的slave節點之一。此時我們也可以連接到172.28.0.2這個容器裡去,通過命令來看一下其現在的情況。

role:master
connected_slaves:1
slave0:ip=172.28.0.4,port=6379,state=online,offset=18952,lag=0
master_replid:f0bf5d1c843ec3ab005c5ac2b864f7ffdc6a8217
master_replid2:72c43e1f9c05d4b08bea6bf9b2549997587e261c
master_repl_offset:18952
second_repl_offset:16351
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:18952

可以看到,現在的172.28.0.2這個節點的角色已經變成了「master」,與其相連接的slave節點只有1個,因為現在的「原master」還沒有啟動起來,總共存活的只有2個實例。

原master重啟啟動

接下來我們模擬原master重新啟動,來看一下會發什麼什麼。

還是通過命令行進入到名為redis的本地目錄,通過docker-compose unpause master來模擬原master故障恢復之後的上線。同樣我們連接到原master的機器上去。

$ docker exec -it f70a9d9809bc1e924a5be0135888067ad3eb16552f9eaf82495e4c956b456cd9 /bin/sh; exit
# redis-cli
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:172.28.0.2
master_port:6379
master_link_status:up
.

master斷線重連之後,角色也變成了新的master(也就是172.28.0.2這個節點)的一個slave。

然後我們也可以通過再看一下新master節點的replication情況作證。

# Replication
role:master
connected_slaves:2
slave0:ip=172.28.0.4,port=6379,state=online,offset=179800,lag=0
slave1:ip=172.28.0.3,port=6379,state=online,offset=179800,lag=1
.

原master短線重連之後,其「connected_slaves」變成了2,且「原master」172.28.0.3被清晰的標註為了slave1,同樣與我們開篇和圖中所講的原理相符合。

好了,以上就是本篇博客的全部內容

歡迎微信關注「SH的全棧筆記」,查看更多相關的文章

相關焦點

  • Redis 單例、主從模式、sentinel 以及集群的配置方式及優缺點對比
    redis主從模式解決了數據備份和單例可能存在的性能問題,但是其也引入了新的問題。由於主從模式配置了三個redis實例,並且每個實例都使用不同的ip(如果在不同的機器上)和埠號。根據前面所述,主從模式下可以將讀寫操作分配給不同的實例進行從而達到提高系統吞吐量的目的,但也正是因為這種方式造成了使用上的不便,因為每個客戶端連接redis實例的時候都是指定了ip和埠號的,如果所連接的redis實例因為故障下線了,而主從模式也沒有提供一定的手段通知客戶端另外可連接的客戶端地址,因而需要手動更改客戶端配置重新連接。
  • 面試官:Redis有哪幾種集群方案?原理和優缺點是什麼?
    雖然現在各大雲平臺有提供緩存服務可以直接使用,但了解一下其背後的實現與原理總還是有些必要(比如面試), 本文就一起來學習一下Redis的幾種集群方案。主從複製模式主從複製模式中包含一個主資料庫實例(master)與一個或多個從資料庫實例(slave),如下圖
  • Redis哨兵(Sentinel)模式如何做到高可用的?
    1 Sentinel簡介下面以四張圖來引出今天的主要內容,請大家耐心閱讀,徹底了解Sentinel實現原理。伺服器與Sentinel系統2 Sentinel的初始化過程啟動一個Sentinel可以使用命令:$ redis-sentinel sentinel.conf或者$ redis-server sentinel.conf --sentinel這兩個命令的效果完全相同。
  • 三歪推薦:Redis常見的面試題
    整個過程如下:初始化sentinel,將普通的redis代碼替換成sentinel專用代碼初始化masters字典和伺服器信息,伺服器信息主要保存ip:port,並記錄實例的地址和ID創建和master的兩個連接,命令連接和訂閱連接,並且訂閱sentinel:hello頻道每隔10秒向master發送info命令,獲取master和它下面所有slave的當前信息當發現master有新的slave
  • 5分鐘完全掌握 Redis
    整個過程如下:初始化sentinel,將普通的redis代碼替換成sentinel專用代碼初始化masters字典和伺服器信息,伺服器信息主要保存ip:port,並記錄實例的地址和ID創建和master的兩個連接,命令連接和訂閱連接,並且訂閱sentinel:hello頻道每隔10秒向master發送info命令,獲取master和它下面所有slave的當前信息當發現master有新的slave
  • Redis5.0:簡單的集群模式——主從模式詳解
    基本上redis的性能瓶頸主要在於網絡IO和內存主頻上面,單機版Redis在不考慮高可用的情況下基本滿足80%的項目需要,因為單機版Redis可以實現10W/S的請求,除非緩存K-V值過大,通過讀寫分離緩存網卡的壓力,否則這個並發處理能力可以應對大部分項目。
  • 國內外三個不同領域巨頭分享的Redis實戰經驗及使用場景
    這裡我們將為大家分享社交巨頭新浪微博、傳媒巨頭Viacom及圖片分享領域佼佼者Pinterest帶來的Redis實踐,首先我們看新浪微博 @啟盼cobain的Redis實戰經驗分享:新浪微博:史上最大的Redis集群Tape is Dead,Disk is Tape,Flash is Disk
  • 認識Redis集群——Redis Cluster
    Redis Cluster與其它集群模式的區別相比較sentinel模式,多個master節點保證主要業務(比如master節點主要負責寫)穩定性,不需要搭建多個sentinel實例監控一個master節點;相比較一主多從的模式,不需要手動切換,具有自我故障檢測,故障轉移的特點;相比較其他兩個模式而言
  • Redis服務​之Redis Cluster
    概述 在之前的分享中我們聊到了redis的高可用組件sentinel的相關配置,回顧請參考Redis服務之高可用組件sentinel;sentinel在redis主從同步架構中主要起到了監控集群master是否正常,如果master不正常,或者宕機,那麼sentinel會提升一個slave當選新的master,從而保證了redis服務的正常使用
  • 一不小心肝出了4W字的Redis面試教程
    這是關於Redis五種數據結構詳解,包括這五種的數據結構的底層原理實現。理論肯定是要用於實踐的,因此最重要的還是實戰部分,也就是這裡還會講解五種數據結構的應用場景。實際布隆過濾器存儲數據和查詢數據的原理圖如下:
  • Redis 2.8.19 發布
    (antirez)5509c14 Add symlink to redis-sentinel during make install (Rhommel Lamas)7de1ef7 SORT: Don't sort Set elements if not needed.
  • 爬蟲大殺器 | Python學習之Scrapy-Redis實戰京東圖書
    https://github.com/rmax/scrapy-redis/tree/master/example-project在example-project中有三個demo,分別是dmoz,myspider_redis,以及mycrawler_redis。本次主要是對dmoz這個demo進行學習和實戰練習。
  • 去pdd面試,redis把我面哭了【附面試答案】
    2、看你在項目中用了redis,我們先聊聊redis吧,常用的數據結構有哪幾種,在你的項目中用過哪幾種,以及在業務中使用的場景,redis的hash怎麼實現的,rehash過程講一下和JavaHashMap的rehash有什麼區別?redis cluster有沒有了解過,怎麼做到高可用的?3redis集群和哨兵機制有什麼區別?redis的持久化機制了解嗎?
  • redis源碼學習之lua執行原理
    」「額,還可以啦」「那你說說redis執行lua腳本的原理」「這個,這個,不就是那麼執行的嗎,eval 一段lua腳本就行了」「好的,了解了,今天面試先到這個吧,後續有消息會通知你」「好的,祝您生活愉快」
  • window中安裝redis
    java實戰幹活項目,最新文檔首發網址java一號1.首先在Window下下載安裝Redis下載地址:https://github.com/MicrosoftArchive/redis/releases
  • 原理+代碼|深入淺出Python隨機森林預測實戰
    能夠理解基本原理並將代碼用於實際的業務案例是本文的目標,本文將詳細介紹如何利用Python實現集成學習中隨機森林這個經典的方法來預測寬帶客戶的流失,主要將分為兩個部分:本文的主角是隨機森林,所以我們將以隨機森林所屬的分支 —— 裝袋法 入手,深入淺出該集成學習方法的原理步驟
  • Redis——伺服器的serverCron函數
    如下        ...省略,其他細節的可以自行去看redis的源碼}上面是redisServer結構,轉換成java,其實redisServer就是一個對象,下面維護著一堆變量,這些變量,其實就是redis伺服器的各種身體指標。
  • Caffeine 和 Redis 居然可以這麼搭,想不到吧!
    二級緩存:redis是一高性能、高可用的key-value資料庫,支持多種數據類型,支持集群,和應用伺服器分開部署易於橫向擴展。實戰多級緩存的用法以下演示項目的代碼在公眾號【Garnett的Java之路】後臺回復【多級緩存】可以自取哦!
  • Redis:從應用到底層,都在這兒了!
    現在找出值為 37 的節點為例,來對比說明跳表和普遍的鍊表。沒有跳表查詢比如我查詢數據 37,如果沒有上面的索引時候路線如下圖:有跳表查詢有跳表查詢 37 的時候路線如下圖:應用場景:積分排行榜、時間排序新聞、延時隊列。1.6、Redis Geo以前寫過 Redis Geo 核心原理解析,想看的直接跳轉即可。
  • Redis源碼分析之服務端
    if (strstr(argv[0],"redis-sentinel") ![0],"redis-check-rdb") != NULL) redis_check_rdb_main(argc,argv,NULL); else if (strstr(argv[0],"redis-check-aof") !