天天看點

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

以前的redis是單線程模型,其實就是多路複用機制,知道多路複用的來一波6,我們在架構師課程中講過,那麼netty也有,看過老師相關課程的也應該知道。這裡不多說了。

Redis6開始有了IO讀寫多線程,隻不過執行使用者的指令和早期版本也是一樣的,都是單線程執行,是以線程安全。

我們先來看一下老版本的單線程:

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

首先讀取用戶端的指令,讀取後執行指令,然後回寫給用戶端,這個就是一組指令的執行,由于單線程安全,他們會一組一組的去進行執行。

他們的讀寫指令以及執行指令都是在一個線程中執行的,這個線程在redis6中稱之為主線程。

在這裡我們可以回顧一下netty的reactor的線程模型,也就是多路複用。

你可以把這個單線程了解為是一個人,他是酒吧會所的接待員,在門口接待了以後,然後還要領到裡面去一個一個的招待他們。

我們可以打開redis.conf配置檔案,看一下:

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

預設情況下,是按照老版本的樣子,如果要使用多線程,那麼開啟即可,這裡的<code>io-threads</code>就是設定多線程的數量,開啟多線程後,整體的性能要比單線程要更高。

<code>io-threads</code>設定的數量最大不建議超過8,提升的空間不大。另外線程數和伺服器的硬體配置也是有關系的。比如4核8g,那麼建議設定2或者3,如果8核建議設定6或者7,因為一定要預留,萬事兜底萬事保底,這一點和nginx的配置也是同樣的道理。

假設現在<code>io-threads</code>設定為4,那麼他的模型就如下:

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

那麼在這裡,讀使用者的指令以及執行指令都是在一個線程中執行的,然後寫操作是多線程執行。在這裡如果比作是一個銀行的話,那麼<code>讀操作</code>相當于是門口的保安,給你測個體溫,<code>執行</code>就是店裡的大堂經理,會帶你去取号,多個<code>寫操作</code>就是視窗的辦事人員。

可以參考一下圖:

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

剛剛我們舉例是隻有一個人在接待和招待,這個時候接待隻有一個人,他隻在門口把客人帶進裡面,裡面會有專門的多個招待員來處理這些客人的請求。

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

如果想要讀操作也變成多線程讀的話,那麼<code>io-threads-do-reads</code>可以開啟,設定為yes就行。這個時候他的模型就是下面這張圖:

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

隻不過官方說明,這個多線程讀開啟的意義不大,不會幫助很多的。

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

這個時候,還是引入剛剛的例子,客人多了,生意好了,門口的接待員增加了,那麼兩邊接待和招待都是多個員工在處理客人了。

那麼在這裡說明一點,多線程隻針對資料的讀寫以及協定的解析。真正使用者端的指令執行還是單線程,是以是線程安全的。

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

其實隻要涉及到中間件,那麼必定會有叢集的概念,一方面為了高可用,一方面為了達到水準擴容,那麼這次來講一下redis的叢集。

其實在很早以前,早期的redis版本是沒有叢集這個概念的,你需要實作叢集得依靠一些中間件,比如codis,還有twemproxy。redis叢集概念是在3.0開始引入的,它是自帶的分布式存儲方案,是一個去中心化的叢集,叫做Redis Cluster,是由多個主從節點共同存在的一個模式,一般以3主3從為比較經典的模式,當然多主多從也可以。其中master負責讀寫請求以及整個叢集資訊的維護,slave隻做他所對應的主節點資料和狀态資訊的複制。

關于叢集,有兩點需要注意

之前我們聊過主從模式,可以做讀寫分離,redis叢集雖然是3主3從,也有主從的概念,但是我們并不會做讀寫分離,讀寫都是交給master去處理,資料會同步給slave,如果叢集做讀寫分離一方面沒有意義一方面slave就沒有容錯機制了,這一點是需要注意。

此外還有一點,單節點的redis預設有16個db,但是在叢集模式下,這些db都融合了,沒有db庫的概念,他是一片汪洋大海。

按照單節點,主從,哨兵來說的話,redis始終都可以說是單庫,資料存儲量是有上限的,你的伺服器節點記憶體有多大,那麼這個就是存儲上限。一旦到達存儲上限,redis就會進行緩存key的自我淘汰機制。很明顯,這種方式面對海量資料的時候并不太好,哪怕你買1個t記憶體的,也總有一天會到達存儲瓶頸,是以任何分布式系統我們都要考慮一個水準擴容機制,這個redis叢集就可以做到。擴容的同時也滿足高可用機制。

同時,使用叢集之後,資料其實進行了分片,多個master節點都能夠提供讀寫服務,這樣整體叢集的響應能力就要比原先單節點來的更好。并且,在叢集模式下,任意節點發生故障時,叢集還是可以繼續對外提供服務,主節點有故障轉移的功能。

傳統早期的redis擴容方案其實是基于業務層的,在業務層進行redis的分割,可以擴容,可以叢集隔離。

我們之前講過redis主從,以這個為例,當然用哨兵也可以,我們可以手動來實作redis的擴容,先看下圖:

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

上圖中的3主3從其實是由3個主從redis構成的,使用者在進行set或者get的時候,首先需要對key做哈希,哈希後的值對節點數求模,取模的值就是資料路由到某個主從庫裡,就針對這個主從庫去做set和get的操作,這個哈希原理其實和nginx的ip_hash道理是一樣的,資料庫分庫也是這個道理。目的就是根據key哈希後的結果去尋址找到最終他的存儲位置去存值或取值。這個其實就是<code>哈希取模</code>。

那麼哈希以及尋址的這個過程需要自己在業務層去封裝實作,但是本質目的就已經達到了橫向擴容,假設每個主從容量是8g,那麼目前總容量就是24g,想怎麼擴容直接加機器就行。

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

這這樣的情況之下,那麼擴容會帶來一個弊端,這個弊端也就是哈希取模帶來的,一旦有節點當機或者增加節點,那麼就需要重新哈希和求模運算,這麼一來會影響所有的緩存資料,這個時候所有資料會重新路由,影響會很大,怎麼解決呢?可以使用一緻性雜湊演算法,就是小部分資料受影響,這個我們在架構班裡有提到過的吧。

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

首先他會有一個域,這個域很長,有2的32次方減1,哈希不僅針對key,也會針對伺服器節點,我們這裡是redis,如果是伺服器叢集那麼道理也是一樣。

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

上面的傳統方式是很古老的,我曾經也見識過一次,我們了解一下就行了。現在都使用redis cluster,這種模式下,redis可以有多個master節點,每個master節點下又可以對應1~n個slave節點,這樣會形成一個多主多從的叢集模式,這種模式下不再需要向上面講過的那樣需要在業務層去處理,redis自身幫我們做好了存取的過程,我們可以不用過多關注業務過程就可以直接使用和應用了。他自身是基于hash slot的算法來存值的,不論是哪種算法,其實本質為了解決的就是資料分布的問題。

redis叢集其實是把資料分片了,由于他有多個master共同構成,他會分資料,他有一個hash slot算法,也可以稱之為哈希槽,每個槽上存放了一些資料,slot的範圍是0~16384,redis對key的存取會有一個CRC16的算法,得到的值,在對16384做取模,最終判斷該key應該在哪個slot中進行存取,本質和伺服器節點數取模是一樣的,隻不過redis cluster的slot算法更精妙,成本更低廉。

以三主三從為例,這個時候的slot總數會平均等份,使得每個master節點中都會有slot,目前3個的話那就是{0..5461}{5462..10922}{10923..16383},這個取值區間在搭建好叢集之後是可以看到的。

如果這個時候,叢集環境增加或者減少節點,slot可以重新遷移或者合并,那麼slot中的緩存key其實還是存在的,如此一來,節點當機或者新增就不會造成緩存丢失了。這就相當于家裡房子拆遷,我到新家裡以後,會把我的私人物品家具啊電器啊一起攜帶過去,東西跟着人走,東西就是緩存key,人就slot,伺服器節點是redis執行個體,比較靈活。并不是說你房子沒了,家裡的東西就沒了。

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

提問:搬家的過程,新家能住人嗎?

當然,你搬家并不是馬上就能完成的,搬家需要耗時,需要等待,是以等待期間你的家具啊電器啊不可用。redis slot也是這樣,當機的時候,那部分需要遷移的slot是不可用,會有一個短暫的遷移的過程,等待遷移完成之後,才能為使用者提供讀寫服務。

hash slot 圖示:

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

如下圖:中間的master當機了,slot會遷移到slave

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

如果,新增master節點,重新配置設定,那麼會把一些slot遷移過去,緩存資料不變,跟着slot走,雖然slot會變動到其他的master節點,但是資料key哈希的時候,還是會到跟着固定的slot。

如果還不能了解,那就再舉個栗子,格子鋪,每個格子歸屬一個賣家,這個賣家把各自托管給某些商鋪,由他們代營運,如果商鋪倒閉,格子還是存在的,他可以把各自帶着走,各自裡的商品就是redis叢集中的資料呀,它是不會發生更改的,隻是外殼換了一家商鋪而已。

時間關系,我們在這裡就隻講原理了,操作部分,我們提供了慕課網的手記文檔,很簡單,大家可以去看一下就行。

連結位址:https://www.imooc.com/article/313301

隻不過在叢集中有一些注意點,我們大緻總結了如下:

讀寫都是在master,slave加入叢集,會進行資料同步,連接配接叢集中的任意主或從節點去讀寫資料,都會根據key哈希取模後路由到某個master節點去處理。slave不提供讀寫服務,隻會同步資料。

關閉任意一主,會導緻部分寫操作失敗,是由于從節點不能執行寫操作,在Slave更新為Master期間可能會有少量的失敗。

關閉從節點對于整個叢集沒有影響

某個主節點和他麾下的所有從節點全部挂掉,我們叢集就進入faill狀态,不可用。因為slot不完整。

如果叢集超過半數以上master挂掉,無論他們是否有對應slave,叢集進入fail狀态,因為無法選舉。

如果叢集中的任意master當機,且此master沒有slave。叢集不可用。(同3)

投票選舉過程是叢集中所有master參與,如果半數以上master節點與master節點通信逾時(cluster-node-timeout),認為目前master節點挂掉。

選舉隻會針對某個master下的所有slave選舉,而不是對所有全量的slave選舉。

原先的master重新恢複連接配接後,他會成為新master的從伺服器。由于主從同步,用戶端的寫入指令,有可能會丢失。redis并非強一緻性,由于主從特性,是以最後一部分資料會丢失。這也符合CAP理論。

叢集隻實作了主節點的故障轉移;從節點故障時隻會被下線,不會進行故障轉移。是以,使用叢集時,一般不會使用讀寫分離技術,因為從節點故障會導緻讀服務不可用,可用性變差了。是以不要在叢集裡做讀寫分離。

需要注意,為了保證叢集的完整性,隻有當16384個槽slot完全的全部配置設定完畢,叢集才可以上線。而且,如果主節點發生故障轉移,并且處于故障轉移過程中還未完成時,原主節點的槽slot不會在任何節點中,叢集會處于下線狀态,用戶端無法調用。CAP原理。

搭建叢集的時候,包清除節點中現有的aof以及rdb檔案,那麼如果現在本來就是單節點,那麼如何擴充為叢集呢?并且要保證資料不丢失。其實原理就是把rdb或者aof檔案儲存以後,再導入,然後通過slot來配置設定。具體步驟如下:

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

如上圖,其原理就是slot遷移。整個過程阻塞,網站服務不對外提供服務。如果使用自建叢集,那麼運維成本很高,一般采用雲redis的話會更好。哪怕阿裡雲,也會在配置變更的時候出現網絡中斷的情況。

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)

官網itzixi.com

微信公衆号:BeJavaGod

新浪微網誌

知乎

簡書

cnblogs

今日頭條

豆瓣

--&gt; 同步更新

慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)
慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)
慕課網2021-01-29 Redis6直播筆記 - 下(多線程/哈希slot/叢集)