怎么保證redis集群的高並發和高可用的?


redis不支持高並發的瓶頸在哪里?

單機.單機版的redis支持上萬到幾萬的QPS不等.

  主要根據你的業務操作的復雜性,redis提供了很多復雜的操作,lua腳本.

2.如果redis要支撐超過10萬+()怎么解決?

單機版的redis幾乎不可能說QPS超過10萬+,除非一些特殊情況,比如說你的機器性能特別好,配置特別高,物理機,維護做的特別好,而且你的整體的操作不是太復雜.可能有超過10萬+/

一般情況下的redis都是在幾萬.

使用讀寫分離的架構來進行redis支撐10萬+的模式.

讀寫分離,一般來說,對緩存,一般都是用來支撐讀高並發的,寫的請求是比較少的,可能寫請求也就一秒鍾幾千,一兩千

大量的請求都是讀,一秒鍾二十萬次讀

讀寫分離

主從架構 -> 讀寫分離 -> 支撐10萬+讀QPS的架構

redis的replication(復制)的基本原理:

master和salver進行數據的異步復制的原理:

redis replication的核心機制:

(1)redis采用異步方式復制數據到slave節點,不過redis 2.8開始,slave node會周期性地確認自己每次復制的數據量
(2)一個master node是可以配置多個slave node的
(3)slave node也可以連接其他的slave node
(4)slave node做復制的時候,是不會block master node的正常工作的
(5)slave node在做復制的時候,也不會block對自己的查詢操作,它會用舊的數據集來提供服務; 但是復制完成的時候,需要刪除舊數據集,加載新數據集,這個時候就會暫停對外服務了
(6)slave node主要用來進行橫向擴容,做讀寫分離,擴容的slave node可以提高讀的吞吐量

master持久化對於主從架構的安全保障的意義?

如果采用了主從架構,那么建議必須開啟master node的持久化!

不建議用slave node作為master node的數據熱備,因為那樣的話,如果你關掉master的持久化,可能在master宕機重啟的時候數據是空的,
然后可能一經過復制,salve node數據也丟了

master -> RDB和AOF都關閉了 -> 全部在內存中

master宕機,重啟,是沒有本地數據可以恢復的,然后就會直接認為自己IDE數據是空的

master就會將空的數據集同步到slave上去,所有slave的數據全部清空

100%的數據丟失

主從架構的核心原理?

第一次啟動:

當啟動一個slave node的時候,它會發送一個PSYNC命令給master node

如果這是slave node重新連接master node,那么master node僅僅會復制給slave部分缺少的數據; 否則如果是slave node第一次連接master node,那么會觸發一次full resynchronization

開始full resynchronization的時候,master會啟動一個后台線程,開始生成一份RDB快照文件,同時還會將從客戶端收到的所有寫命令緩存在內存中。RDB文件生成完畢之后,master會將這個RDB發送給slave,slave會先寫入本地磁盤,然后再從本地磁盤加載到內存中。然后master會將內存中緩存的寫命令發送給slave,slave也會同步這些數據。

slave node如果跟master node有網絡故障,斷開了連接,會自動重連。master如果發現有多個slave node都來重新連接,僅僅會啟動一個rdb save操作,用一份數據服務所有slave node。

 

一般情況下:

  都是寫入一個寫請求,然后異步的方式,將數據同步到slave.

 redis的斷點續傳?

從redis 2.8開始,就支持主從復制的斷點續傳,如果主從復制過程中,網絡連接斷掉了,那么可以接着上次復制的地方,繼續復制下去,而不是從頭開始復制一份

master node會在內存中常見一個backlog,master和slave都會保存一個replica offset還有一個master id,offset就是保存在backlog中的。
如果master和slave網絡連接斷掉了,slave會讓master從上次的replica offset開始繼續復制

但是如果沒有找到對應的offset,那么就會執行一次full resynchronization

無磁盤化復制?

master在內存中直接創建rdb,然后發送給slave,不會在自己本地落地磁盤了

repl-diskless-sync no  這個是無磁盤化復制
repl-diskless-sync-delay:5,等待一定時長再開始復制,因為要等更多slave重新連接過來

過期key處理?

slave不會過期key,只會等待master過期key。如果master過期了一個key,或者通過LRU淘汰了一個key,那么會模擬一條del命令發送給slave。

復制的完整的流程:

(1)slave node啟動,僅僅保存master node的信息,包括master node的host和ip,但是復制流程沒開始

    master host和ip是從哪兒來的,redis.conf里面的slaveof配置的

(2)slave node內部有個定時任務,每秒檢查是否有新的master node要連接和復制,如果發現,就跟master node建立socket網絡連接
(3)slave node發送ping命令給master node
(4)口令認證,如果master設置了requirepass,那么salve node必須發送masterauth的口令過去進行認證
(5)master node第一次執行全量復制,將所有數據發給slave node
(6)master node后續持續將寫命令,異步復制給slave node

數據同步相關的核心機制

指的就是第一次slave連接msater的時候,執行的全量復制,那個過程里面你的一些細節的機制

(1)master和slave都會維護一個offset

master會在自身不斷累加offset,slave也會在自身不斷累加offset
slave每秒都會上報自己的offset給master,同時master也會保存每個slave的offset

這個倒不是說特定就用在全量復制的,主要是master和slave都要知道各自的數據的offset,才能知道互相之間的數據不一致的情況

(2)backlog

master node有一個backlog,默認是1MB大小
master node給slave node復制數據時,也會將數據在backlog中同步寫一份
backlog主要是用來做全量復制中斷候的增量復制的

(3)master run id

info server,可以看到master run id
如果根據host+ip定位master node,是不靠譜的,如果master node重啟或者數據出現了變化,那么slave node應該根據不同的run id區分,run id不同就做全量復制
如果需要不更改run id重啟redis,可以使用redis-cli debug reload命令

 

(4)psync

從節點使用psync從master node進行復制,psync runid offset
master node會根據自身的情況返回響應信息,可能是FULLRESYNC runid offset觸發全量復制,可能是CONTINUE觸發增量復制

全量復制

(1)master執行bgsave,在本地生成一份rdb快照文件
(2)master node將rdb快照文件發送給salve node,如果rdb復制時間超過60秒(repl-timeout),那么slave node就會認為復制失敗,可以適當調節大這個參數
(3)對於千兆網卡的機器,一般每秒傳輸100MB,6G文件,很可能超過60s
(4)master node在生成rdb時,會將所有新的寫命令緩存在內存中,在salve node保存了rdb之后,再將新的寫命令復制給salve node
(5)client-output-buffer-limit slave 256MB 64MB 60,如果在復制期間,內存緩沖區持續消耗超過64MB,或者一次性超過256MB,那么停止復制,復制失敗
(6)slave node接收到rdb之后,清空自己的舊數據,然后重新加載rdb到自己的內存中,同時基於舊的數據版本對外提供服務
(7)如果slave node開啟了AOF,那么會立即執行BGREWRITEAOF,重寫AOF

rdb生成、rdb通過網絡拷貝、slave舊數據的清理、slave aof rewrite,很耗費時間

如果復制的數據量在4G~6G之間,那么很可能全量復制時間消耗到1分半到2分鍾

增量復制

(1)如果全量復制過程中,master-slave網絡連接斷掉,那么salve重新連接master時,會觸發增量復制
(2)master直接從自己的backlog中獲取部分丟失的數據,發送給slave node,默認backlog就是1MB
(3)msater就是根據slave發送的psync中的offset來從backlog中獲取數據的

heartbeat

主從節點互相都會發送heartbeat信息

master默認每隔10秒發送一次heartbeat,salve node每隔1秒發送一個heartbeat

異步復制

master每次接收到寫命令之后,現在內部寫入數據,然后異步發送給slave node

什么是不可用?

什么是99.99%的高可用?

架構上,高可用性,99.99%的高可用性

講的學術,99.99%,公式,系統可用的時間 / 系統故障的時間,365天,在365天 * 99.99%的時間內,你的系統都是可以嘩嘩對外提供服務的,那就是高可用性,99.99%

系統可用的時間 / 總的時間 = 高可用性,然后會對各種時間的概念,說一大堆解釋

什么是redis的不可用?

怎么保證了redis的99.99%的高可用性?

(高可用的保證)哨兵的介紹

sentinal,中文名是哨兵

哨兵是redis集群架構中非常重要的一個組件,主要功能如下

(1)集群監控,負責監控redis master和slave進程是否正常工作
(2)消息通知,如果某個redis實例有故障,那么哨兵負責發送消息作為報警通知給管理員
(3)故障轉移,如果master node掛掉了,會自動轉移到slave node上
(4)配置中心,如果故障轉移發生了,通知client客戶端新的master地址

哨兵本身也是分布式的,作為一個哨兵集群去運行,互相協同工作

(1)故障轉移時,判斷一個master node是宕機了,需要大部分的哨兵都同意才行,涉及到了分布式選舉的問題
(2)即使部分哨兵節點掛掉了,哨兵集群還是能正常工作的,因為如果一個作為高可用機制重要組成部分的故障轉移系統本身是單點的,那就很坑爹了

目前采用的是sentinal 2版本,sentinal 2相對於sentinal 1來說,重寫了很多代碼,主要是讓故障轉移的機制和算法變得更加健壯和簡單

哨兵的核心知識

(1)哨兵至少需要3個實例,來保證自己的健壯性
(2)哨兵 + redis主從的部署架構,是不會保證數據零丟失的,只能保證redis集群的高可用性
(3)對於哨兵 + redis主從這種復雜的部署架構,盡量在測試環境和生產環境,都進行充足的測試和演練

為什么redis哨兵集群只有2個節點無法正常工作?

哨兵集群必須部署2個以上節點

如果哨兵集群僅僅部署了個2個哨兵實例,quorum=1

+----+      +----+
| M1 |      | R1 |
| S1 |    | S2 |
+----+      +----+

Configuration: quorum = 1

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節點哨兵集群+----+

| M1 |
| S1 |
+----+
|
+----+      +----+
| R2 |    +  | R3 |
| S2 |        | S3 |
+----+       +----+

Configuration: quorum = 2,majority

如果M1所在機器宕機了,那么三個哨兵還剩下2個,S2和S3可以一致認為master宕機,然后選舉出一個來執行故障轉移

同時3個哨兵的majority是2,所以還剩下的2個哨兵運行着,就可以允許執行故障轉移

 

兩種數據丟失的情況

主備切換的過程,可能會導致數據丟失

(1)異步復制導致的數據丟失

因為master -> slave的復制是異步的,所以可能有部分數據還沒復制到slave,master就宕機了,此時這些部分數據就丟失了

(2)腦裂導致的數據丟失

腦裂,也就是說,某個master所在機器突然脫離了正常的網絡,跟其他slave機器不能連接,但是實際上master還運行着

此時哨兵可能就會認為master宕機了,然后開啟選舉,將其他slave切換成了master

這個時候,集群里就會有兩個master,也就是所謂的腦裂

此時雖然某個slave被切換成了master,但是可能client還沒來得及切換到新的master,還繼續寫向舊master的數據可能也丟失了

因此舊master再次恢復的時候,會被作為一個slave掛到新的master上去,自己的數據會清空,重新從新的master復制數據

解決異步復制和腦裂導致的數據丟失

min-slaves-to-write 1
min-slaves-max-lag 10

要求至少有1個slave,數據復制和同步的延遲不能超過10秒

如果說一旦所有的slave,數據復制和同步的延遲都超過了10秒鍾,那么這個時候,master就不會再接收任何請求了

上面兩個配置可以減少異步復制和腦裂導致的數據丟失

(1)減少異步復制的數據丟失

有了min-slaves-max-lag這個配置,就可以確保說,一旦slave復制數據和ack延時太長,就認為可能master宕機后損失的數據太多了,那么就拒絕寫請求,這樣可以把master宕機時由於部分數據未同步到slave導致的數據丟失降低的可控范圍內

(2)減少腦裂的數據丟失

如果一個master出現了腦裂,跟其他slave丟了連接,那么上面兩個配置可以確保說,如果不能繼續給指定數量的slave發送數據,而且slave超過10秒沒有給自己ack消息,那么就直接拒絕客戶端的寫請求

這樣腦裂后的舊master就不會接受client的新數據,也就避免了數據丟失

上面的配置就確保了,如果跟任何一個slave丟了連接,在10秒后發現沒有slave給自己ack,那么就拒絕新的寫請求

因此在腦裂場景下,最多就丟失10秒的數據

sdown和odown轉換機制:

sdown和odown兩種失敗狀態

sdown是主觀宕機,就一個哨兵如果自己覺得一個master宕機了,那么就是主觀宕機

odown是客觀宕機,如果quorum數量的哨兵都覺得一個master宕機了,那么就是客觀宕機

sdown達成的條件很簡單,如果一個哨兵ping一個master,超過了is-master-down-after-milliseconds指定的毫秒數之后,就主觀認為master宕機

sdown到odown轉換的條件很簡單,如果一個哨兵在指定時間內,收到了quorum指定數量的其他哨兵也認為那個master是sdown了,那么就認為是odown了,客觀認為master宕機

哨兵集群的自動發現機制:

哨兵互相之間的發現,是通過redis的pub/sub系統實現的,每個哨兵都會往__sentinel__:hello這個channel里發送一個消息,這時候所有其他哨兵都可以消費到這個消息,並感知到其他的哨兵的存在

每隔兩秒鍾,每個哨兵都會往自己監控的某個master+slaves對應的__sentinel__:hello channel里發送一個消息,內容是自己的host、ip和runid還有對這個master的監控配置

每個哨兵也會去監聽自己監控的每個master+slaves對應的__sentinel__:hello channel,然后去感知到同樣在監聽這個master+slaves的其他哨兵的存在

每個哨兵還會跟其他哨兵交換對master的監控配置,互相進行監控配置的同步

slave配置的自動糾正

哨兵會負責自動糾正slave的一些配置,比如slave如果要成為潛在的master候選人,哨兵會確保slave在復制現有master的數據; 如果slave連接到了一個錯誤的master上,比如故障轉移之后,那么哨兵會確保它們連接到正確的master上

slave->master選舉算法

如果一個master被認為odown了,而且majority哨兵都允許了主備切換,那么某個哨兵就會執行主備切換操作,此時首先要選舉一個slave來

會考慮slave的一些信息

(1)跟master斷開連接的時長
(2)slave優先級
(3)復制offset
(4)run id

如果一個slave跟master斷開連接已經超過了down-after-milliseconds的10倍,外加master宕機的時長,那么slave就被認為不適合選舉為master

(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state

接下來會對slave進行排序

(1)按照slave優先級進行排序,slave priority越低,優先級就越高
(2)如果slave priority相同,那么看replica offset,哪個slave復制了越多的數據,offset越靠后,優先級就越高
(3)如果上面兩個條件都相同,那么選擇一個run id比較小的那個slave

quorum和majority

每次一個哨兵要做主備切換,首先需要quorum數量的哨兵認為odown,然后選舉出一個哨兵來做切換,這個哨兵還得得到majority哨兵的授權,才能正式執行切換

如果quorum < majority,比如5個哨兵,majority就是3,quorum設置為2,那么就3個哨兵授權就可以執行切換

但是如果quorum >= majority,那么必須quorum數量的哨兵都授權,比如5個哨兵,quorum是5,那么必須5個哨兵都同意授權,才能執行切換

configuration epoch

哨兵會對一套redis master+slave進行監控,有相應的監控的配置

執行切換的那個哨兵,會從要切換到的新master(salve->master)那里得到一個configuration epoch,這就是一個version號,每次切換的version號都必須是唯一的

如果第一個選舉出的哨兵切換失敗了,那么其他哨兵,會等待failover-timeout時間,然后接替繼續執行切換,此時會重新獲取一個新的configuration epoch,作為新的version號

configuraiton傳播

哨兵完成切換之后,會在自己本地更新生成最新的master配置,然后同步給其他的哨兵,就是通過之前說的pub/sub消息機制

這里之前的version號就很重要了,因為各種消息都是通過一個channel去發布和監聽的,所以一個哨兵完成一次新的切換之后,新的master配置是跟着新的version號的

其他的哨兵都是根據版本號的大小來更新自己的master配置的

 

 

redis高並發:主從架構,一主多從,一般來說,很多項目其實就足夠了,單主用來寫入數據,單機幾萬QPS,多從用來查詢數據,多個從實例可以提供每秒10萬的QPS。

redis高並發的同時,還需要容納大量的數據:一主多從,每個實例都容納了完整的數據,比如redis主就10G的內存量,其實你就最對只能容納10g的數據量。如果你的緩存要容納的數據量很大,達到了幾十g,甚至幾百g,或者是幾t,那你就需要redis集群,而且用redis集群之后,可以提供可能每秒幾十萬的讀寫並發。

redis高可用:如果你做主從架構部署,其實就是加上哨兵就可以了,就可以實現,任何一個實例宕機,自動會進行主備切換。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM