之前提到 Redis 有主從庫集群機制,以減輕主庫的請求壓力,實現(xiàn) Redis 的高可用性。 并且,我們已經(jīng)知道,請求的寫操作只會在主庫上執(zhí)行,然后主庫再同步到各個從庫上。 當(dāng)從庫掛掉時,還有主庫或者其他從庫可以提供讀操作,可是,當(dāng)主庫掛掉以后,寫操作該如何繼續(xù)執(zhí)行呢?
實際上,當(dāng)主庫掛掉了,會有其他從庫切換成主庫,繼續(xù)執(zhí)行寫操作,將數(shù)據(jù)同步給其他從庫。
那么,這個從庫切換成主庫的過程,就需要考慮以下幾個問題:
1、主庫真的掛了嗎?
2、選取哪個從庫切換成主庫?
3、某個從庫切換成主庫后,怎樣通知其他從庫?
Redis 的哨兵機制,就在此時體現(xiàn)出作用了,Redis 就是通過哨兵機制檢測主庫是否掛掉、選取從庫切換為主庫、將新主庫信息通知給其他從庫的。
Redis 的哨兵機制
哨兵實際上就是一個運行在特殊模式下的 Redis 進程,主從庫實例運行的同時,哨兵進程也在運行,哨兵主要負責(zé)三個任務(wù):監(jiān)控、選擇主庫、通知從庫變更
監(jiān)控
監(jiān)控就是指,哨兵會周期性地向主從庫發(fā)起心跳檢測,確認主從庫是否在線,然后標記主從庫的下線狀態(tài)。
下線狀態(tài)分為 “主觀下線”和“客觀下線”,如果主從庫在規(guī)定時間內(nèi),沒有響應(yīng)哨兵的心跳較檢測,那么哨兵就將此主、從庫標記為“主觀下線” 。
但是,需要注意的是,網(wǎng)絡(luò)環(huán)境是復(fù)雜的,很有可能這個 Redis 實例是因為其他原因,沒有響應(yīng)哨兵的心跳檢測,但實際上這個Redis 實例是正常運行的。 這個時候,就必須說到 Redis 的哨兵集群 —— 有一群哨兵對 Redis 實例進行心跳檢測,某個哨兵檢測到某個 Redis 實例下線,可以將其標記為“主觀下線”,但是,只有超過一定數(shù)量的哨兵,都認為此實例“主觀下線”了,這個 Redis 實例才能被標記為 “客觀下線”。
對于從庫來說,只要標記為 “主觀下線”,就可以判斷其已經(jīng)下線了,因為從庫下線不會對 Redis 整體產(chǎn)生太大的影響。
而對于主庫來說,必須將其標記為 “客觀下線”,也就是有一定數(shù)量的哨兵都認為 主庫 已經(jīng)“主觀下線”了,才能認為主庫掛了,從而進行下一步的主從庫切換。
如何選取新主庫?
在主庫被標記為 “客觀下線” 后,就應(yīng)該選舉某個從庫切換為主庫了。 一般來說,新主庫的選舉包括兩部分 “篩選 + 打分”
篩選:指的是從庫必須正常在線運行,才能被選舉為主庫。篩選時,除了判斷從庫當(dāng)前的連接狀態(tài),還應(yīng)該判斷之前的網(wǎng)絡(luò)連接狀態(tài)。 只有當(dāng)前,和之前的網(wǎng)絡(luò)連接狀態(tài)都良好,這個從庫才有資格被選為主庫。
打分:在篩選完成后,要從剩下的從庫中,依次進行三輪打分,分別是 從庫優(yōu)先級、從庫復(fù)制進度以及從庫ID號。 只要在某一輪中,選出了最高分的從庫,那么這個從庫直接成為新主庫。
1、根據(jù)從庫優(yōu)先級打分
從庫上可以根據(jù) slave-priority 配置項,配置該從庫的優(yōu)先級。 這個優(yōu)先級的設(shè)置,可以根據(jù)實例本身的機器內(nèi)存、磁盤、CPU配置設(shè)置這個優(yōu)先級。
2、根據(jù)舊主庫同步程度最接近的從庫打分
主庫同步數(shù)據(jù)給從庫的時候,會帶有一個 offset 標記同步進度。 實際上,只需要比較各個從庫的 offset,這個數(shù)據(jù)越大,說明越接近主庫數(shù)據(jù),那么在這一輪打分越高。
3、ID號小的從庫得分高
這個實際上就是一個托底邏輯,每個實例都會有一個ID,在前兩輪都無法確定出主庫的情況下,ID 號最小的從庫最分最高。
經(jīng)過網(wǎng)絡(luò)情況的篩選和上面三輪的打分,新主庫就被選舉出來了。
把新主庫的信息通知給從庫
哨兵會將新主庫的 IP 通知給其他從庫,讓其他從庫再次執(zhí)行以下 replicaof 命令設(shè)置主庫。
Redis 哨兵集群
之前已經(jīng)考慮過,從庫掛掉、主庫掛掉 Redis 會進行什么操作。 那么哨兵掛掉,又會發(fā)生什么事呢?
實際上,通過上文也可以知道,哨兵不止一個,而是由一組哨兵組成了哨兵集群。所以,當(dāng)某個哨兵掛掉了,其他哨兵還是一樣能完成監(jiān)控、選主、通知的操作的。
在配置哨兵的時候,需要用到配置項:
sentinel monitor <master-name> <ip> <redis-port> <quorum>
可以看到,這里只設(shè)置了主庫的IP和端口,并沒有配置其他哨兵和從庫的連接信息。那么,哨兵之間是如何組成集群,又是怎么連接從庫的呢?
哨兵之間是如何發(fā)現(xiàn)的 —— pub/sub 機制
哨兵之間能獲取對方的 IP 和端口號,要依賴于 Redis 提供的 pub/sub 機制(發(fā)布/訂閱機制)。 pub/sub 機制,就是在 Redis 注冊了一個頻道,發(fā)布就是向這個頻道發(fā)送消息,訂閱了這個頻道的應(yīng)用就能接收到這個消息,當(dāng)然,只有訂閱了這個頻道,才能向這個頻道發(fā)送消息。
而在 Redis 的主庫上,就有一個 "sentinel:hello" 頻道,當(dāng)設(shè)置一個新哨兵時,就會向這個頻道發(fā)布消息。此時,其他已存在哨兵就會接收到這個新哨兵的IP和端口號,從而向這個新哨兵建立連接。
哨兵是如何知道從庫的IP和端口號的
哨兵會向主庫發(fā)送 INFO 命令,主庫就會把從庫列表返回給哨兵。
主從庫的切換,是由哪個哨兵完成的?
我們已經(jīng)知道了,新主庫的選舉規(guī)則,那么在哨兵集群中,是由哪個哨兵執(zhí)行的主從庫切換呢?
實際上,由哪個哨兵執(zhí)行,也是通過哨兵之間的選舉完成的。
當(dāng)某個哨兵檢測到主庫 “主觀下線”,會向其他哨兵發(fā)送 "is-master-down-by-addr" 命令。然后,其他哨兵會根據(jù)自己和主庫的連接情況,返回 Y 或者 N 給這個哨兵。 當(dāng)一個哨兵獲取到了一定的 Y (配置為 quorum),也就是贊成票后,就能將主庫標記為 “客觀下線”。當(dāng)哨兵實例拿到了過半的贊成票,并且超過了設(shè)定的 quorum,那么這個哨兵就能執(zhí)行主從庫切換。