天天看點

Redis分片(分布式緩存)1 分片何用2 分片基礎3 分片實作(理論)4 分片缺點5 存儲 OR 緩存6 預分片7 分片實作(實踐)聯系我

分片(partitioning)就是将你的資料拆分到多個 Redis 執行個體的過程,這樣每個執行個體将隻包含所有鍵的子集.

1 分片何用

Redis 的分片承擔着兩個主要目标:

  • 允許使用很多電腦的記憶體總和來支援更大的資料庫。沒有分片,你就被局限于單機能支援的記憶體容量。
  • 允許伸縮計算能力到多核或多伺服器,伸縮網絡帶寬到多伺服器或多網絡擴充卡。

2 分片基礎

有很多不同的分片标準(criteria).

假想我們有 4 個 Redis 執行個體 R0,R1,R2,R3,還有很多表示使用者的鍵,像 user:1,user:2,… 等等,我們能找到不同的方式來選擇一個指定的鍵存儲在哪個執行個體中。換句話說,有許多不同的辦法來映射一個鍵到一個指定的 Redis 伺服器。

最簡單的執行分片的方式之一是範圍分片(range partitioning),通過映射對象的範圍到指定的 Redis 執行個體來完成分片。例如,我可以假設使用者從 ID 0 到 ID 10000 進入執行個體 R0,使用者從 ID 10001 到 ID 20000 進入執行個體 R1.

這套辦法行得通,并且事實上在實踐中被采用,然而,這有一個缺點,就是需要一個映射範圍到執行個體的表格.

這張表需要管理,不同類型的對象都需要一個表,是以範圍分片在 Redis 中常常并不可取,因為這要比其他分片可選方案低效得多。

一種範圍分片的替代方案是

哈希分片(hash partitioning)

.

這種模式适用于任何鍵,不需要鍵像 object_name: 這樣的餓形式,就像這樣簡單

  • 使用一個哈希函數(例如,crc32 哈希函數) 将鍵名轉換為一個數字。例如,如果鍵是 foobar,crc32(foobar)将會輸出類似于 93024922 的東西。
  • 對這個資料進行取模運算,以将其轉換為一個 0 到 3 之間的數字,這樣這個數字就可以映射到我的 4 台 Redis 執行個體之一。93024922 模 4 等于 2,是以我知道我的鍵 foobar 應當存儲到 R2 執行個體。注意:取模操作傳回除法操作的餘數,在許多程式設計語言總實作為%操作符。

有許多其他的方式可以分片,從這兩個例子中你就可以知道了。一種哈希分片的進階形式稱為一緻性哈希(consistent hashing),被一些 Redis 用戶端和代理實作。

3 分片實作(理論)

分片可由軟體棧中的不同部分來承擔。

  • 用戶端分片(Client side partitioning)

    用戶端直接選擇正确的節點來寫入和讀取指定鍵,許多 Redis 用戶端實作了用戶端分片.

  • 代理協助分片(Proxy assisted partitioning)

    我們的用戶端發送請求到一個可以了解 Redis 協定的代理上.而不是直接發送請求到 Redis 執行個體上.

代理會根據配置好的分片模式,來保證轉發我們的請求到正确的 Redis 執行個體,并傳回響應給用戶端.

Redis 和 Memcached 的代理 Twemproxy 實作了代理協助的分片.

  • 查詢路由(Query routing)

    你可以發送你的查詢到一個随機執行個體,這個執行個體會保證轉發你的查詢到正确的節點.

Redis 叢集在用戶端的幫助下,實作了查詢路由的一種混合形式 (請求不是直接從 Redis 執行個體轉發到另一個,而是用戶端收到重定向到正确的節點).

4 分片缺點

Redis 的一些特性與分片在一起時玩的不是很好

  • 涉及多個鍵的操作通常不支援。例如,你不能對映射在兩個不同 Redis 執行個體上的鍵執行交集(事實上有辦法做到,但不是直接這麼幹).
  • 涉及多個鍵的事務不能使用
  • 分片的粒度(granularity)是鍵,是以不能使用一個很大的鍵來分片資料集,例如一個很大的有序集合
  • 當使用了分片,資料處理變得更複雜,例如,你需要處理多個 RDB/AOF 檔案,備份資料時你需要聚合多個執行個體和主機的持久化檔案
  • 添加和删除容量也很複雜。例如,Redis 叢集具有運作時動态添加和删除節點的能力來支援透明地再均衡資料,但是其他方式,像用戶端分片和代理都不支援這個特性。但是,有一種稱為預分片(Presharding)的技術在這一點上能幫上忙。

5 存儲 OR 緩存

盡管無論是将 Redis 作為資料存儲還是緩存,Redis 的分片概念上都是一樣的,但是作為資料存儲時有一個重要的局限。當 Redis 作為資料存儲時,一個給定的鍵總是映射到相同的 Redis 執行個體。當 Redis 作為緩存時,如果一個節點不可用而使用另一個節點,這并不是一個什麼大問題,按照我們的願望來改變鍵和執行個體的映射來改進系統的可用性(就是系統回複我們查詢的能力)。

一緻性哈希實作常常能夠在指定鍵的首選節點不可用時切換到其他節點。類似的,如果你添加一個新節點,部分資料就會開始被存儲到這個新節點上。

這裡的主要概念如下:

  • 如果 Redis 用作緩存,使用一緻性哈希來來實作伸縮擴充(scaling up and down)是很容易的。
  • 如果 Redis 用作存儲,使用固定的鍵到節點的映射,是以節點的數量必須固定不能改變。否則,當增删節點時,就需要一個支援再平衡節點間鍵的系統,目前隻有 Redis 叢集可以做到這一點.

6 預分片

我們已經知道分片存在的一個問題,除非我們使用 Redis 作為緩存,增加和删除節點是一件很棘手的事情,使用固定的鍵和執行個體映射要簡單得多。

然而,資料存儲的需求可能一直在變化。今天我可以接受 10 個 Redis 節點(執行個體),但是明天我可能就需要 50 個節點。

因為 Redis 隻有相當少的記憶體占用且輕量級(一個空閑的執行個體隻是用 1MB 記憶體),一個簡單的解決辦法是一開始就開啟很多的執行個體。即使你一開始隻有一台伺服器,你也可以在第一天就決定生活在分布式的世界裡,使用分片來運作多個 Redis 執行個體在一台伺服器上。

你一開始就可以選擇很多數量的執行個體。例如,32 或者 64 個執行個體能滿足大多數的使用者,并且為未來的增長提供足夠的空間。

這樣,當你的資料存儲需要增長,你需要更多的 Redis 伺服器,你要做的就是簡單地将執行個體從一台伺服器移動到另外一台。當你新添加了第一台伺服器,你就需要把一半的 Redis 執行個體從第一台伺服器搬到第二台,如此等等。

使用 Redis 複制,你就可以在很小或者根本不需要停機時間内完成移動資料:

  • 在你的新伺服器上啟動一個空執行個體。
  • 移動資料,配置新執行個體為源執行個體的從服務。
  • 停止你的用戶端。
  • 更新被移動執行個體的伺服器 IP 位址配置。
  • 向新伺服器上的從節點發送 SLAVEOF NO ONE 指令。
  • 以新的更新配置啟動你的用戶端。
  • 最後關閉掉舊伺服器上不再使用的執行個體。

7 分片實作(實踐)

到目前為止,我們從理論上讨論了 Redis 分片,但是實踐情況如何呢?你應該使用什麼系統呢?

7.1 Redis 叢集

Redis 叢集是自動分片和高可用的首選方式.

一旦 Redis 叢集可用,以及支援 Redis 叢集的用戶端可用,Redis 叢集将會成為 Redis 分片的事實标準。

Redis 叢集是查詢路由和用戶端分片的混合模式。

7.2 Twemproxy

Twemproxy 是 Twitter 開發的一個支援 Memcached ASCII 和 Redis 協定的代理。它是單線程的,由 C 語言編寫,運作非常的快。基于 Apache 2.0 許可的開源項目。

Twemproxy 支援自動在多個 Redis 執行個體間分片,如果節點不可用時,還有可選的節點排除支援(這會改變鍵和執行個體的映射,是以你應該隻在将 Redis 作為緩存是才使用這個特性)。

這并不是單點故障(single point of failure),因為你可以啟動多個代理,并且讓你的用戶端連接配接到第一個接受連接配接的代理。

從根本上說,Twemproxy 是介于用戶端和 Redis 執行個體之間的中間層,這就可以在最下的額外複雜性下可靠地處理我們的分片。這是目前建議的處理 Redis 分片的方式.

7.3 支援一緻性哈希的用戶端

Twemproxy 之外的可選方案,是使用實作了用戶端分片的用戶端,通過一緻性哈希或者别的類似算法。有多個支援一緻性哈希的 Redis 用戶端,例如 Redis-rb 和 Predis。

請檢視完整的 Redis 用戶端清單,看看是不是有支援你的程式設計語言的,并實作了一緻性哈希的成熟用戶端。

聯系我

gayhub

繼續閱讀