02_redis如何在保持讀寫分離+高可用的架構下,還能橫向擴容支撐1T+海量資料1、單機redis在海量資料面前的瓶頸
2、怎麼才能夠突破單機瓶頸,讓redis支撐海量資料?
3、redis的叢集架構
redis cluster
支撐N個redis master node,每個master node都可以挂載多個slave node
讀寫分離的架構,對于每個master來說,寫就寫到master,然後讀就從mater對應的slave去讀
高可用,因為每個master都有salve節點,那麼如果mater挂掉,redis cluster這套機制,就會自動将某個slave切換成master
redis cluster(多master + 讀寫分離 + 高可用)
我們隻要基于redis cluster去搭建redis叢集即可,不需要手工去搭建replication複制+主從架構+讀寫分離+哨兵叢集+高可用
4、redis cluster vs. replication + sentinal
如果你的資料量很少,主要是承載高并發高性能的場景,比如你的緩存一般就幾個G,單機足夠了
replication,一個mater,多個slave,要幾個slave跟你的要求的讀吞吐量有關系,然後自己搭建一個sentinal叢集,去保證redis主從架構的高可用性,就可以了
redis cluster,主要是針對海量資料+高并發+高可用的場景,海量資料,如果你的資料量很大,那麼建議就用redis cluster
1 面試題
- redis 叢集模式的工作原理能說一下麼?
- 在叢集模式下,redis 的 key 是如何尋址的?
- 分布式尋址都有哪些算法?
- 了解一緻性 hash 算法嗎?
2 考點分析
在前幾年,redis 如果要搞幾個節點,每個節點存儲一部分的資料,得借助一些中間件來實作,比如說有 codis,或者 twemproxy,都有。有一些 redis 中間件,你讀寫 redis 中間件,redis 中間件負責将你的資料分布式存儲在多台機器上的 redis 執行個體中。
這兩年,redis 不斷在發展,redis 也不斷有新的版本,現在的 redis 叢集模式,可以做到在多台機器上,部署多個 redis 執行個體,每個執行個體存儲一部分的資料,同時每個 redis 主執行個體可以挂 redis 從執行個體,自動確定說,如果 redis 主執行個體挂了,會自動切換到 redis 從執行個體上來。
現在 redis 的新版本,大家都是用 redis cluster 的,也就是 redis 原生支援的 redis 叢集模式,那麼面試官肯定會就 redis cluster 對你來個幾連炮。要是你沒用過 redis cluster,正常,以前很多人用 codis 之類的用戶端來支援叢集,但是起碼你得研究一下 redis cluster 吧。
如果你的資料量很少,主要是承載高并發高性能的場景,比如你的緩存一般就幾個 G,單機就足夠了,可以使用 replication,一個 master 多個 slaves,要幾個 slave 跟你要求的讀吞吐量有關,然後自己搭建一個 sentinel 叢集去保證 redis 主從架構的高可用性。
redis cluster,主要是針對海量資料+高并發+高可用的場景。redis cluster 支撐 N 個 redis master node,每個 master node 都可以挂載多個 slave node。這樣整個 redis 就可以橫向擴容了。如果你要支撐更大資料量的緩存,那就橫向擴容更多的 master 節點,每個 master 節點就能存放更多的資料了。
面試題剖析
redis cluster 介紹
- 自動将資料進行分片,每個 master 上放一部分資料
- 提供内置的高可用支援,部分 master 不可用時,還是可以繼續工作的
在 redis cluster 架構下,每個 redis 要放開兩個端口号,比如一個是 6379,另外一個就是 加1w 的端口号,比如 16379。
16379 端口号是用來進行節點間通信的,也就是 cluster bus 的東西,cluster bus 的通信,用來進行故障檢測、配置更新、故障轉移授權。cluster bus 用了另外一種二進制的協定,gossip 協定,用于節點間進行高效的資料交換,占用更少的網絡帶寬和處理時間。
節點間的内部通信機制
基本通信原理
叢集中繼資料的維護有兩種方式:集中式、Gossip 協定。redis cluster 節點間采用 gossip 協定進行通信。
集中式是将叢集中繼資料(節點資訊、故障等等)幾種存儲在某個節點上。集中式中繼資料集中存儲的一個典型代表,就是大資料領域的 storm。它是分布式的大資料實時計算引擎,是集中式的中繼資料存儲的結構,底層基于 zookeeper(分布式協調的中間件)對所有中繼資料進行存儲維護。
redis 維護叢集中繼資料采用另一個方式,
gossip
協定,所有節點都持有一份中繼資料,不同的節點如果出現了中繼資料的變更,就不斷将中繼資料發送給其它的節點,讓其它節點也進行中繼資料的變更。
集中式的好處在于,中繼資料的讀取和更新,時效性非常好,一旦中繼資料出現了變更,就立即更新到集中式的存儲中,其它節點讀取的時候就可以感覺到;不好在于,所有的中繼資料的更新壓力全部集中在一個地方,可能會導緻中繼資料的存儲有壓力。
gossip 好處在于,中繼資料的更新比較分散,不是集中在一個地方,更新請求會陸陸續續打到所有節點上去更新,降低了壓力;不好在于,中繼資料的更新有延時,可能導緻叢集中的一些操作會有一些滞後。
- 10000 端口:每個節點都有一個專門用于節點間通信的端口,就是自己提供服務的端口号+10000,比如 7001,那麼用于節點間通信的就是 17001 端口。每個節點每隔一段時間都會往另外幾個節點發送
消息,同時其它幾個節點接收到ping
之後傳回ping
。pong
- 交換的資訊:資訊包括故障資訊,節點的增加和删除,hash slot 資訊等等。
gossip 協定
gossip 協定包含多種消息,包含
ping
,
pong
meet
fail
等等。
- meet:某個節點發送 meet 給新加入的節點,讓新節點加入叢集中,然後新節點就會開始與其它節點進行通信。
redis-trib.rb add-node
其實内部就是發送了一個 gossip meet 消息給新加入的節點,通知那個節點去加入我們的叢集。
ping:每個節點都會頻繁給其它節點發送 ping,其中包含自己的狀态還有自己維護的叢集中繼資料,互相通過 ping 交換中繼資料。
pong:傳回 ping 和 meeet,包含自己的狀态和其它資訊,也用于資訊廣播和更新。
fail:某個節點判斷另一個節點 fail 之後,就發送 fail 給其它節點,通知其它節點說,某個節點當機啦。
ping 消息深入
ping 時要攜帶一些中繼資料,如果很頻繁,可能會加重網絡負擔。
每個節點每秒會執行 10 次 ping,每次會選擇 5 個最久沒有通信的其它節點。當然如果發現某個節點通信延時達到了 cluster_node_timeout / 2,那麼立即發送 ping,避免資料交換延時過長,落後的時間太長了。比如說,兩個節點之間都 10 分鐘沒有交換資料了,那麼整個叢集處于嚴重的中繼資料不一緻的情況,就會有問題。是以 cluster_node_timeout 可以調節,如果調得比較大,那麼會降低 ping 的頻率。
每次 ping,會帶上自己節點的資訊,還有就是帶上 1/10 其它節點的資訊,發送出去,進行交換。至少包含 3 個其它節點的資訊,最多包含 總節點數減 2 個其它節點的資訊。
分布式尋址算法
- hash 算法(大量緩存重建)
- 一緻性 hash 算法(自動緩存遷移)+ 虛拟節點(自動負載均衡)
- redis cluster 的 hash slot 算法
hash 算法
來了一個 key,首先計算 hash 值,然後對節點數取模。然後打在不同的 master 節點上。一旦某一個 master 節點當機,所有請求過來,都會基于最新的剩餘 master 節點數去取模,嘗試去取資料。這會導緻大部分的請求過來,全部無法拿到有效的緩存,導緻大量的流量湧入資料庫。
一緻性 hash 算法
一緻性 hash 算法将整個 hash 值空間組織成一個虛拟的圓環,整個空間按順時針方向組織,下一步将各個 master 節點(使用伺服器的 ip 或主機名)進行 hash。這樣就能确定每個節點在其哈希環上的位置。
來了一個 key,首先計算 hash 值,并确定此資料在環上的位置,從此位置沿環順時針“行走”,遇到的第一個 master 節點就是 key 所在位置。
在一緻性雜湊演算法中,如果一個節點挂了,受影響的資料僅僅是此節點到環空間前一個節點(沿着逆時針方向行走遇到的第一個節點)之間的資料,其它不受影響。增加一個節點也同理。
燃鵝,一緻性雜湊演算法在節點太少時,容易因為節點分布不均勻而造成緩存熱點的問題。為了解決這種熱點問題,一緻性 hash 算法引入了虛拟節點機制,即對每一個節點計算多個 hash,每個計算結果位置都放置一個虛拟節點。這樣就實作了資料的均勻分布,負載均衡。
redis cluster 有固定的 16384 個 hash slot,對每個 key 計算 CRC16 值,然後對 16384 取模,可以擷取 key 對應的 hash slot。
redis cluster 中每個 master 都會持有部分 slot,比如有 3 個 master,那麼可能每個 master 持有 5000 多個 hash slot。hash slot 讓 node 的增加和移除很簡單,增加一個 master,就将其他 master 的 hash slot 移動部分過去,減少一個 master,就将它的 hash slot 移動到其他 master 上去。移動 hash slot 的成本是非常低的。用戶端的 api,可以對指定的資料,讓他們走同一個 hash slot,通過 hash tag 來實作。
任何一台機器當機,另外兩個節點,不影響的。因為 key 找的是 hash slot,不是機器。
redis cluster 的高可用與主備切換原理
redis cluster 的高可用的原理,幾乎跟哨兵是類似的。
判斷節點當機
如果一個節點認為另外一個節點當機,那麼就是 pfail,主觀當機。如果多個節點都認為另外一個節點當機了,那麼就是 fail,客觀當機,跟哨兵的原理幾乎一樣,sdown,odown。
在 cluster-node-timeout 内,某個節點一直沒有傳回 pong,那麼就被認為 pfail。
如果一個節點認為某個節點 pfail 了,那麼會在 gossip ping 消息中,ping 給其他節點,如果超過半數的節點都認為 pfail 了,那麼就會變成 fail。
從節點過濾
對當機的 master node,從其所有的 slave node 中,選擇一個切換成 master node。
檢查每個 slave node 與 master node 斷開連接配接的時間,如果超過了 cluster-node-timeout * cluster-slave-validity-factor,那麼就沒有資格切換成 master。
從節點選舉
每個從節點,都根據自己對 master 複制資料的 offset,來設定一個選舉時間,offset 越大(複制資料越多)的從節點,選舉時間越靠前,優先進行選舉。
所有的 master node 開始 slave 選舉投票,給要進行選舉的 slave 進行投票,如果大部分 master node(N/2 + 1)都投票給了某個從節點,那麼選舉通過,那個從節點可以切換成 master。
從節點執行主備切換,從節點切換為主節點。
與哨兵比較
整個流程跟哨兵相比,非常類似,是以說,redis cluster 功能強大,直接內建了 replication 和 sentinel 的功能。