深入瞭解Redis中的Codis

2022-01-06 10:00:09
本篇文章帶大家瞭解一下Redis中的Codis,介紹一下Codis原理,希望對大家有所幫助!

場景

在巨量資料高並行場景下,使用單個redis範例,即使redis的效能再高,也會變的非常吃力,

首先,資料量越大,redis佔用記憶體就越大,進一步導致rdb檔案過大,這種情況會使的主從全量同步時間過長,同時範例重新啟動時,載入過大的rdb也會讓啟動時間變長。【相關推薦:Redis視訊教學

其次在CPU的使用上,單個範例的Redis只能使用一個CPU核心,一個核心應多過多的資料,也會顯得力不從心,

因此需要一個叢集方案,將巨大的資料量由一臺範例分散到多臺範例上,從Redis流行到官方支援自己的Cluster方案之間,第三方也在自己開發支援叢集的元件,Codis就是其中之一,

Codis使用Go語言開發,在Redis與使用者端中間充當代理的角色,使用Redis協定,所以使用者端直接連線Codis,向其傳送指令即可,Codis負責轉發指令給Redis,最後接收返回結果再返回給使用者端,

1.png

Codis代理的Redis範例構成一個Redis叢集,當叢集空間也不足以使用時,可以動態擴容,繼續增加Redis範例,與此同時,使用者端使用的sdk不需要做任何改動,只需由原來的連線redis改成連線codis即可,

Codis自身也可以採取一個叢集,來保證自身的高可用,由於其本身就是無狀態的,只負責轉發內容,增加多個Codis沒有副作用還可以保證QPS的提高,當其中一個Codis掛掉時,還可以使用別的。

2.png

原理

Codis將特定的Key轉發到特定的Redis範例,叢集中每個範例都儲存一部分Key,降低其他範例的壓力,同時所有範例的資料加起來,就是一份完整的資訊。

Codis預設劃分了1024個槽位(slot),叢集中的每個Redis範例對應一部分槽位,Codis會在記憶體中維護槽位與Redis範例的對應關係,

槽位的數量預設是1024,可以更改,如果叢集節點比較多,可以將數位調大。

3.png

當接收到使用者端傳送過來的key時,Codis對該key進行 crc32 運算得出一個 hash 值,

再將 hash 後的整數值對 1024(槽位數量) 進行取模得到一個餘數,該餘數就是Key將被儲存到的槽位,有了槽位就可以找到這個key該發到哪個redis範例上了。

虛擬碼:

hash = crc32(command.key) # 計算hash值
slot = hash % 1024 # 取模得到槽位
redisInstance = slots[slot].redis # 得到redis範例
redis.do(command) # 執行命令複製程式碼

叢集槽位同步

Redis與槽位的對映關係存在Codis的記憶體當中,因此Codis叢集需要考慮保證每個節點中的槽位對映關係同步,所以Codis採用 Zookeeper、Etcd 分散式設定儲存中介軟體來持久化槽位對映關係,保證Codis叢集之間的資料同步,

如下圖,Codis將槽位關係存在Zookeeper中,並提供了一個Dashboard 觀察與修改槽位關係,當發生改變時,Codis Proxy 監聽到變化並重新同步槽位關係。

4.png

拓容

當現有叢集也不滿足業務需求時,就需要新增範例加入到的叢集中,此時槽位對映關係需要進行重新分配,需要分配一部分的槽位給新節點。

Codis新增了一個 SLOTSSCAN 指令,可以遍歷指定slot下的所有key,通過該指令掃描出待遷移槽位的所有key,然後挨個遍歷每個key遷移到新節點中,

遷移過程中,Codis繼續對外提供服務,此時來了一個請求打在了正在遷移的槽位上,由於該槽位現在對應新老兩個節點,此時 Codis 無法判斷該 key 有沒有從舊節點中遷移到新節點上,

因此這種情況 Codis 會立即強制對當前的 key 進行單個遷移,遷移完成後,將請求轉發給新的Redis範例上。

虛擬碼:

slot_index = crc32(command.key) % 1024
if slot_index in migrating_slots:
    doMigratingKey(command.key)
    redis = slots[slot_index].new_redis
else:
    redis = slots[slot_index].redis複製程式碼

SLOTSSCAN 與 Redis自身的Scan指令一樣,無法避免掃描出來的資料重複,但這不會影響到遷移的正確性,因為單個key遷移之後,就立刻從舊範例中刪除了,無法再被掃描出來。

自動均衡槽位

每次新增範例,如果都需要人工維護slot的對映關係太麻煩,Codis提供自動均衡,該功能會在系統比較空閒的時候觀察每個Redis範例對應的slot數量,如果不平衡,就進行自動均衡,遷移資料的操作。

缺點

Codis給Redis帶來擴容好處,但也造成了一些副作用。

不支援事務

一個事務可能對多個key做了操作,但事務只能在單個範例中完成,但是由於key分散在不同的範例中,因此Codis無法支援事務操作。

不支援rename

rename將一個key命名成另一個key,但是這兩個key可能hash出來的槽位並不是同一個,而是在不同範例的槽位上,因此rename也不被支援。

官方提供的不支援的指令列表:https://github.com/CodisLabs/codis/blob/master/doc/unsupported_cmds.md

擴容卡頓

Codis在擴容過程中,對資料的遷移是將整個key直接遷移過去的,例如一個hash結構,Codis會直接 hgetall 拉取所有的內容,使用 hmset 放到 新節點中,

如果該hash的內容過大,將會引起卡頓,官方建議單個集合結構的總大小不超過1MB,在業務上可以通過分桶儲存等,將大型資料拆成多個小的,做一個折中。

網路開銷

由於 Codis 在 使用者端與Redis範例之間充當網路Proxy,多了一層,網路開銷自然多一些,比直接連線Redis的效能要稍低一些。

中介軟體運維開銷

Codis叢集設定需要使用Zk或Etcd,這意味著引入Codis叢集又要引入其他中介軟體,增加運維機器資源成本。

優點

Codis將分散式一致性的問題交給了第三方(ZK或Etcd)負責,省去了這方面的維護工作,降低實現程式碼的複雜性,

Redis官方的Cluster為了實現去中心化,引入了Raft與Gossip協定,以及大量需要調優的設定引數,複雜度驟增。

批次獲取

對於批次操作,例如使用 mget 獲取多個key的值,這些key可能分散在多個範例中,Codis將key按照所在的範例進行分組,然後對每個範例挨個呼叫 mget,最後彙總返回給使用者端。

5.png

其他功能

Codis 提供 Dashboard 介面化,以及 Codis-fe 對叢集進行管理,還可以進行增加分組、節點、執行自動均衡等操作,檢視 slot 狀態以及 slot 對應的 redis 範例,這些功能使的運維更加方便輕鬆。

6.png

7.png

8.png

9.png

走向歷史

Codis是為了彌補Redis官方沒有提供叢集這一概念時出現的,現在Redis官方提供Cluster功能,官方的支援自然比第三方的更有優勢,

同時第三方軟體還需要實時關注官方釋出的新特性各種,而Cluster肯定是實時相容新特性,因此更推薦使用官方的Cluster,Codis作為曾經的一個知識點了解,某些思想與Cluster是有重合的。

更多程式設計相關知識,請存取:!!

以上就是深入瞭解Redis中的Codis的詳細內容,更多請關注TW511.COM其它相關文章!