redis切片集群


以下內存參考蔣德鈞老師講義

如何保存更多的數據

為了保存更多的數據,通常使用大內存雲主機和切片集群兩種方法。實際上,這兩種方法分別對應着redis應對數據量增多的兩種方法:縱向擴展和橫向擴展。

  • 縱向擴展:升級單個redis實例的資源配置,包括增加內存容量、增加磁盤容量、使用更高配置的cpu。就像下圖中,原來的實例內存是8GB,硬盤是50GB,縱向擴展后,內存增加到24GB,磁盤增加到150GB。
  • 橫向擴展:橫向增加當前redis實例個數,就像下圖中,原來使用1個8GB內存、50GB磁盤的實例,現在使用三個相同配置的實例。

    那么,這兩種方式的優缺點分別是什么呢?
    首先,縱向擴展的好處是,實施起來簡單、直接。不過該方案會面臨兩個潛在的問題。

第一個問題是,當使用RDB對數據進行持久化時,如果數據量增加,需要的內存也會增加,主線程fork子進程時就可能阻塞。不過,如果你不要求持久化保存redis數據,那么縱向擴展是一個不錯的選擇。

不過,這時,你還要面臨第二個問題:縱向擴展會受到硬件和成本的限制。這很容易理解,畢竟,把內存從32G擴展到64GB還算容易,但是,要想擴展到1TB,就要面臨硬件容量個成本上的限制。

與縱向擴展相比,橫向擴展是一個擴展性更好的方案。這是因為,要想保存更多的數據,采用這種方案的話,只用增加redis的實例個數就行了,不用擔心單個實例的硬件成本限制。在面向百萬,千萬級別的用戶規模時,橫向擴展redis切片集群會是一個非常好的選擇。

不過在使用單個實例的時候,數據存放在哪兒,客戶端訪問哪兒,都是非常明確的,但是,切片集群不可避免地涉及到多個實例地分布式管理問題。要想把切片集群用起來,我們需要解決兩大問題:

  • 數據切片后,在多個實例之間如何分布?
  • 客戶端怎么確定想要訪問地數據在哪個實例上?
    接下來,一一解決。

數據切片和實例地對應分布關系

在切片集群中,數據需要分布在不同地實例上,那么數據和實例之間如何應對呢?這就和接下來將地redis cluster方案有關了。不過,我們首先要弄明白切片集群和redis cluster地聯系與區別。

實際上,切片集群是一種保存大量數據地通用機制,這個機制可以有不同地實現方案。在redis3.0之前,官方並沒有針對切片集群提供具體方案。從3.0開始,官方提供了一個名為redis cluster地方案,用於實現切片集群。redis cluster方案中就規定數據和實例地對應規則。

具體來說,redis cluster方案使用哈希槽(hash slot),來處理數據和實例之間的映射關系。在redis cluster方案中,一個切片集群共有16384個哈希槽,這些哈希槽類似於數據分區,每個鍵值對都會根據它的key,被映射到一個哈希槽中。

具體的映射過程分為兩大步:首先根據鍵值對的key,按照CRC16算法計算一個16bit的值;然后,再用這個16bit的值對16384取模,得到0~16383范圍內的模數,每個模數代表一個相應編號的哈希槽。

那么,這些哈希槽又是如何被映射到具體的redis實例上的呢?

我們在部署redis cluster方案時,可以使用cluster create命令創建集群,此時,redis會自動把這些槽平均分布到集群實例上。例如:如果集群有N個實例,那么,每個實例上的槽個數為16384/N

當然,我們也可以使用cluster meet 命令手動建立實例間的連接,形成集群,在使用 cluster addslots命令,指定每個實例上的哈希槽個數。

舉一個例子,假設集群中不同redis實例的內存大小配置不一,如果把哈希槽均分在各個實例上,在保存相同數量的鍵值對時,和內存大的實例相比,內存小的實例就會有更大的容量壓力。遇到這種情況時,可以根據不同實例的資源配置情況,使用cluster addslots命令手動分配哈希槽

示意圖中的切片集群一共有三個實例,同時假設有5個哈希槽,我們首先可以通過下面的命令手動分配哈希槽:實例1保存哈希槽0和1,實例2保存哈希槽2和3,實例3保存哈希槽4.

redis-cli -h 172.16.19.3 –p 6379 cluster addslots 0,1
redis-cli -h 172.16.19.4 –p 6379 cluster addslots 2,3
redis-cli -h 172.16.19.5 –p 6379 cluster addslots 4

在集群運行的過程中,key1和key2計算完CRC16值后,對哈希槽總個數5取模,再根據各自的模數結果,就可以被映射到對應的實例1和實例3上了。

另外,一個小提醒 在手動分配哈希槽時,需要把16384個槽都分配完,否則redis無法正常工作

客戶端如何數據定位

在定位鍵值對數據時,它所處的哈希槽是可以通過計算得到的,這個計算可以在客戶端發送請求時來執行。但是,要進一步定位到實例,還需要知道哈希槽分布在哪個實例上。

一般來說,客戶端和集群建立連接之后,實例就會把哈希槽的分配信息發送給客戶端。但是,在集群當當創建的時候,每個實例只知道自己被分配了哪些哈希槽,是不知道其他實例擁有哈希槽的信息的。

那么客戶端為什么可以在訪問任何一個實例時,都能獲得所有的哈希槽信息呢?這是因為redis實例會把自己的哈希槽信息發給和它相連的其他實例,來完成哈希槽分配信息的擴散。當實例之間相互連接后,每個實例就有所有哈希槽的映射關系了。

客戶端收到哈希槽信息后,會把哈希槽信息緩存在本地。當客戶端請求鍵值對時,會先計算鍵所對應的哈希槽,然后就可以給相應的實例發送請求了。

但是,集群中,實例和哈希槽的對應關系並不是一成不變的,最常見的變化有兩個:

  • 在集群中,實例有新增或者刪除,redis需要重新分配哈希槽
  • 為了負載均衡,redis需要把哈希槽在所有實例上重新分配一遍。

此時,實例之間還可以通過相互傳遞信息,獲得最新的哈希槽分配信息,但是,客戶端是無法主動感知這些變化的。這就會導致,它緩存的分配信息和最新的分配信息不一致了,那該怎么辦呢?

redis cluster方案提供了一個重定向機制,所謂重定向,就是指,客戶端給一個實例發送數據讀寫操作時,這個實例是並沒有相應的數據,客戶端要再給一個新實例發送操作命令。

那客戶端又是怎么知道重定向時的新實例的訪問地址呢?當客戶端把一個鍵值對的操作請求發送給一個實例時,如果這個實例並沒有這個鍵值對映射的哈希槽,那么這個實例就會給這個客戶端返回下面的move命令響應結果,這個結果中就包含了新實例的訪問地址。

GET hello:key
(error) MOVED 13320 172.16.19.5:6379

其中,moved命令表示,客戶端請求的鍵值對所在的哈希槽13320,實際是在172.16.19.5這個實例上。通過返回的moved命令,就相當於把哈希槽所在的新實例信息告訴給客戶端。這樣一來,客戶端就可以直接和172.16.19.5連接,並發操作請求了。


免責聲明!

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



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