Redis集羣

隨着大型網站數據量和對系統可用性要求的提高,單機版的Redis愈來愈難以知足須要,所以咱們須要使用Redis集羣來提供服務。html

目前主流的Redis集羣解決方案有三類,它們都是經過將key分散到不一樣的redis實例上來提升總體能力, 這種方法稱爲分片(sharding):java

  • 服務端分片: 客戶端與集羣中任意的節點通訊,服務端計算key在哪個節點上,若再也不當前節點上則通知客戶端應訪問的節點。 典型表明爲官方推出的Redis Cluster
  • 客戶端分片: 客戶端計算key應在集羣中的哪個節點上,並與該節點通訊。典型表明爲ShardedJedis
  • 代理分片: 客戶端與集羣中的代理(proxy)通訊,代理與節點通訊進行操做。典型表明爲Codis

單機版的Redis中單條指令的執行老是原子性的,在集羣中則難以保證這一性質,某些指令可能沒法在集羣中使用或者受到限制。git

若須要使用這些指令或須要它們保持原子性,能夠採用單機版Redis和集羣搭配使用的方法。將主要業務部署在集羣上,將須要較多支持的服務部署在單機版Redis上。github

三種集羣實現方式各有有缺,本文分別進行簡單介紹它們的特性。本文不會詳細介紹三種方式的使用方式,只對其架構和特性進行對比,幫助讀者選擇合適的解決方案。redis

基本概念

哈希槽

哈希槽(hash slot)是來自Redis Cluster的概念, 但在各類集羣方案都有使用。算法

哈希槽是一個key的集合,Redis集羣共有16384個哈希槽,每一個key經過CRC16散列而後對16384進行取模來決定該key應當被放到哪一個槽中,集羣中的每一個節點負責一部分哈希槽。docker

以有三個節點的集羣爲例:bash

  • 節點A包含0到5500號哈希槽
  • 節點B包含5501到11000號哈希槽
  • 節點C包含11001到16384號哈希槽

這樣的設計有利於對集羣進行橫向伸縮,若要添加或移除節點只須要將該節點上的槽轉移到其它節點便可。架構

在某些集羣方案中,涉及多個key的操做會被限制在一個slot中,如Redis Cluster中的mget/mset操做。網站

HashTag

HashTag機制能夠影響key被分配到的slot,從而可使用那些被限制在slot中操做。

HashTag便是用{}包裹key的一個子串,如{user:}1, {user:}2

在設置了HashTag的狀況下,集羣會根據HashTag決定key分配到的slot, 兩個key擁有相同的HashTag:{user:}, 它們會被分配到同一個slot,容許咱們使用MGET命令。

一般狀況下,HashTag不支持嵌套,即將第一個{和第一個}中間的內容做爲HashTag。若花括號中不包含任何內容則會對整個key進行散列,如{}user:

HashTag可能會使過多的key分配到同一個slot中,形成數據傾斜影響系統的吞吐量,務必謹慎使用。

主從模型

幾種流行的Redis集羣解決方案都沒有將一個key寫到多個節點中,若某個節點故障則沒法訪問訪問其上的key這顯然是不知足集羣的分區容錯性的。

Redis集羣使用主從模型(master-slave)來提升可靠性。每一個master節點上綁定若干個slave節點,當master節點故障時集羣會推舉它的某個slave節點代替master節點。

體驗Redis集羣

Redis Cluster

爲了便於部署本文使用docker部署了一個簡單集羣:

docker run -i -t -p 7000:7000 -p 7001:7001 -p 7002:7002 -p 7003:7003 -p 7004:7004 -p 7005:7005 -p 7006:7006 -p 7007:7007 grokzen/redis-cluster

打開另外一個終端窗口, 啓動redis客戶端:

redis-cli -c -p 7000

在redis客戶端中嘗試進行操做:

127.0.0.1:7000> set a 1
-> Redirected to slot [15495] located at 127.0.0.1:7002
OK
127.0.0.1:7002> get a
"1"
127.0.0.1:7002> mset ab 2 ac 3
(error) CROSSSLOT Keys in request don't hash to the same slot
127.0.0.1:7002> mset {a}b 2 {a}c 3
OK

上述示例中, 執行set a命令時客戶端被重定向到了其它節點。

mset ab 2 ac 3命令由於key被分配到不一樣的slot中致使CROSSSLOT錯誤,而使用HashTag機制mset {a}b 2 {a}c 3就能夠解決這個問題。

更多的內容能夠參考Redis Cluster中文文檔

ShardedJedis

Jedis是一個流行的Java語言Redis客戶端,在Redis官方提供Redis Cluster以前便實現了客戶端集羣功能。

ShardedJedis使用一致性哈希算法進行數據分片,不支持涉及多個key的命令, 其不支持的命令能夠參考MultiKeyCommands

JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(2);
poolConfig.setMaxIdle(1);
poolConfig.setMaxWaitMillis(2000);

final String HOST = "127.0.0.1";
JedisShardInfo shardInfo1 = new JedisShardInfo(HOST, 6379);
JedisShardInfo shardInfo2 = new JedisShardInfo(HOST, 6380);
JedisShardInfo shardInfo3 = new JedisShardInfo(HOST, 6381);

ShardedJedisPool jedisPool = new ShardedJedisPool(poolConfig, Arrays.asList(shardInfo1, shardInfo2, shardInfo3));

try(ShardedJedis jedis = jedisPool.getResource()) {
    jedis.set("a", "1");
    jedis.set("b", "2");
    System.out.println(jedis.get("a"));
}

在初始化ShardedJedisPool時設置keyTagPattern,匹配keyTagPattern的key會被分配到同一個實例中。

Codis

Codis是豌豆莢開源的代理式Redis集羣解決方案,由於Twemproxy缺少對彈性伸縮的支持,不少企業選擇了通過生產環境檢驗的Codis。

Codis的安裝和使用方法能夠參考官方文檔, 爲了方便起見咱們使用ReleaseBinary文件安裝Codis-Server和Codis-Proxy。

或者使用第三方開發者製做的Docker鏡像:

docker run -d --name="codis" -h "codis" -p 18087:18087 -p 11000:11000 -p 19000:19000 ruo91/codis
docker exec codis /bin/bash codis-start all start

使用redis客戶端鏈接19000端口,嘗試進行操做:

127.0.0.1:19000> set a  1
OK
127.0.0.1:19000> get a
"1"
127.0.0.1:19000> mset ab 2 ac 3
OK
127.0.0.1:19000> mset {a}b 2 {a}c 3
OK

Codis也支持HashTag, 不過Codis已經解決了大多數命令的slot限制。

集羣方案對比

協議支持

命令 Redis Cluster ShardedJedis Codis
mget/mset 僅限同一個slot 不支持 失去原子性
keys 僅限同一個slot 不支持 不支持
scan 僅限同一個slot 不支持 僅限同一個slot(SLOTSSCAN命令)
rename 僅限同一個slot 不支持 不支持
pipeline 不支持 不支持 支持
事務 支持相同slot 不支持 不支持
發佈/訂閱 支持 不支持 不支持
eval 僅限同一slot 不支持 支持
相關文章
相關標籤/搜索