3 種Redis 集群化的 方案對(duì)比

來源:kaito-kidd.com/2020/07/07/redis-cluster-codis-twemproxy
之前我們提到,為了保證Redis的高可用,主要需要以下幾個(gè)方面:
數(shù)據(jù)持久化 主從復(fù)制 自動(dòng)故障恢復(fù) 集群化
我們簡單理一下這幾個(gè)方案的特點(diǎn),以及它們之間的聯(lián)系。
數(shù)據(jù)持久化本質(zhì)上是為了做數(shù)據(jù)備份,有了數(shù)據(jù)持久化,當(dāng)Redis宕機(jī)時(shí),我們可以把數(shù)據(jù)從磁盤上恢復(fù)回來,但在數(shù)據(jù)恢復(fù)之前,服務(wù)是不可用的,而且數(shù)據(jù)恢復(fù)的時(shí)間取決于實(shí)例的大小,數(shù)據(jù)量越大,恢復(fù)起來越慢。
而主從復(fù)制則是部署多個(gè)副本節(jié)點(diǎn),多個(gè)副本節(jié)點(diǎn)實(shí)時(shí)復(fù)制主節(jié)點(diǎn)的數(shù)據(jù),當(dāng)主節(jié)點(diǎn)宕機(jī)時(shí),我們有完整的副本節(jié)點(diǎn)可以使用。另一方面,如果我們業(yè)務(wù)的讀請(qǐng)求量很大,主節(jié)點(diǎn)無法承受所有的讀請(qǐng)求,多個(gè)副本節(jié)點(diǎn)可以分擔(dān)讀請(qǐng)求,實(shí)現(xiàn)讀寫分離,這樣可以提高Redis的訪問性能。
但有個(gè)問題是,當(dāng)主節(jié)點(diǎn)宕機(jī)時(shí),我們雖然有完整的副本節(jié)點(diǎn),但需要手動(dòng)操作把從節(jié)點(diǎn)提升為主節(jié)點(diǎn)繼續(xù)提供服務(wù),如果每次主節(jié)點(diǎn)故障,都需要人工操作,這個(gè)過程既耗時(shí)耗力,也無法保證及時(shí)性,高可用的程度將大打折扣。如何優(yōu)化呢?
有了數(shù)據(jù)持久化、主從復(fù)制、故障自動(dòng)恢復(fù)這些功能,我們?cè)谑褂肦edis時(shí)是不是就可以高枕無憂了?
答案是否定的,如果我們的業(yè)務(wù)大部分都是讀請(qǐng)求,可以使用讀寫分離提升性能。但如果寫請(qǐng)求量也很大呢?現(xiàn)在是大數(shù)據(jù)時(shí)代,像阿里、騰訊這些大體量的公司,每時(shí)每刻都擁有非常大的寫入量,此時(shí)如果只有一個(gè)主節(jié)點(diǎn)是無法承受的,那如何處理呢?
這就需要集群化!簡單來說實(shí)現(xiàn)方式就是,多個(gè)主從節(jié)點(diǎn)構(gòu)成一個(gè)集群,每個(gè)節(jié)點(diǎn)存儲(chǔ)一部分?jǐn)?shù)據(jù),這樣寫請(qǐng)求也可以分散到多個(gè)主節(jié)點(diǎn)上,解決寫壓力大的問題。同時(shí),集群化可以在節(jié)點(diǎn)容量不足和性能不夠時(shí),動(dòng)態(tài)增加新的節(jié)點(diǎn),對(duì)進(jìn)群進(jìn)行擴(kuò)容,提升性能。
從這篇文章開始,我們就開始介紹Redis的集群化方案。當(dāng)然,集群化也意味著Redis部署架構(gòu)更復(fù)雜,管理和維護(hù)起來成本也更高。而且在使用過程中,也會(huì)遇到很多問題,這也衍生出了不同的集群化解決方案,它們的側(cè)重點(diǎn)各不相同。
這篇文章我們先來整體介紹一下Redis集群化比較流行的幾個(gè)解決方案,先對(duì)它們有整體的認(rèn)識(shí),后面我會(huì)專門針對(duì)我比較熟悉的集群方案進(jìn)行詳細(xì)的分析。
集群化方案
要想實(shí)現(xiàn)集群化,就必須部署多個(gè)主節(jié)點(diǎn),每個(gè)主節(jié)點(diǎn)還有可能有多個(gè)從節(jié)點(diǎn),以這樣的部署結(jié)構(gòu)組成的集群,才能更好地承擔(dān)更大的流量請(qǐng)求和存儲(chǔ)更多的數(shù)據(jù)。
可以承擔(dān)更大的流量是集群最基礎(chǔ)的功能,一般集群化方案還包括了上面提到了數(shù)據(jù)持久化、數(shù)據(jù)復(fù)制、故障自動(dòng)恢復(fù)功能,利用這些技術(shù),來保證集群的高性能和高可用。
另外,優(yōu)秀的集群化方案還實(shí)現(xiàn)了在線水平擴(kuò)容功能,當(dāng)節(jié)點(diǎn)數(shù)量不夠時(shí),可以動(dòng)態(tài)增加新的節(jié)點(diǎn)來提升整個(gè)集群的性能,而且這個(gè)過程是在線完成的,業(yè)務(wù)無感知。
業(yè)界主流的Redis集群化方案主要包括以下幾個(gè):
客戶端分片
Codis
Twemproxy
Redis Cluster
它們還可以用是否中心化來劃分,其中客戶端分片、Redis Cluster屬于無中心化的集群方案,Codis、Tweproxy屬于中心化的集群方案。
是否中心化是指客戶端訪問多個(gè)Redis節(jié)點(diǎn)時(shí),是直接訪問還是通過一個(gè)中間層Proxy來進(jìn)行操作,直接訪問的就屬于無中心化的方案,通過中間層Proxy訪問的就屬于中心化的方案,它們有各自的優(yōu)劣,下面分別來介紹。
客戶端分片
客戶端分片主要是說,我們只需要部署多個(gè)Redis節(jié)點(diǎn),具體如何使用這些節(jié)點(diǎn),主要工作在客戶端。
客戶端通過固定的Hash算法,針對(duì)不同的key計(jì)算對(duì)應(yīng)的Hash值,然后對(duì)不同的Redis節(jié)點(diǎn)進(jìn)行讀寫。

客戶端分片需要業(yè)務(wù)開發(fā)人員事先評(píng)估業(yè)務(wù)的請(qǐng)求量和數(shù)據(jù)量,然后讓DBA部署足夠的節(jié)點(diǎn)交給開發(fā)人員使用即可。
這個(gè)方案的優(yōu)點(diǎn)是部署非常方便,業(yè)務(wù)需要多少個(gè)節(jié)點(diǎn)DBA直接部署交付即可,剩下的事情就需要業(yè)務(wù)開發(fā)人員根據(jù)節(jié)點(diǎn)數(shù)量來編寫key的請(qǐng)求路由邏輯,制定一個(gè)規(guī)則,一般采用固定的Hash算法,把不同的key寫入到不同的節(jié)點(diǎn)上,然后再根據(jù)這個(gè)規(guī)則進(jìn)行數(shù)據(jù)讀取。
可見,它的缺點(diǎn)是業(yè)務(wù)開發(fā)人員使用Redis的成本較高,需要編寫路由規(guī)則的代碼來使用多個(gè)節(jié)點(diǎn),而且如果事先對(duì)業(yè)務(wù)的數(shù)據(jù)量評(píng)估不準(zhǔn)確,后期的擴(kuò)容和遷移成本非常高,因?yàn)楣?jié)點(diǎn)數(shù)量發(fā)生變更后,Hash算法對(duì)應(yīng)的節(jié)點(diǎn)也就不再是之前的節(jié)點(diǎn)了。
所以后來又衍生出了一致性哈希算法,就是為了解決當(dāng)節(jié)點(diǎn)數(shù)量變更時(shí),盡量減少數(shù)據(jù)的遷移和性能問題。
這種客戶端分片的方案一般用于業(yè)務(wù)數(shù)據(jù)量比較穩(wěn)定,后期不會(huì)有大幅度增長的業(yè)務(wù)場(chǎng)景下使用,只需要前期評(píng)估好業(yè)務(wù)數(shù)據(jù)量即可。
Codis
隨著業(yè)務(wù)和技術(shù)的發(fā)展,人們?cè)桨l(fā)覺得,當(dāng)我需要使用Redis時(shí),我們不想關(guān)心集群后面有多少個(gè)節(jié)點(diǎn),我們希望我們使用的Redis是一個(gè)大集群,當(dāng)我們的業(yè)務(wù)量增加時(shí),這個(gè)大集群可以增加新的節(jié)點(diǎn)來解決容量不夠用和性能問題。
這種方式就是服務(wù)端分片方案,客戶端不需要關(guān)心集群后面有多少個(gè)Redis節(jié)點(diǎn),只需要像使用一個(gè)Redis的方式去操作這個(gè)集群,這種方案將大大降低開發(fā)人員的使用成本,開發(fā)人員可以只需要關(guān)注業(yè)務(wù)邏輯即可,不需要關(guān)心Redis的資源問題。
多個(gè)節(jié)點(diǎn)組成的集群,如何讓開發(fā)人員像操作一個(gè)Redis時(shí)那樣來使用呢?這就涉及到多個(gè)節(jié)點(diǎn)是如何組織起來提供服務(wù)的,一般我們會(huì)在客戶端和服務(wù)端中間增加一個(gè)代理層,客戶端只需要操作這個(gè)代理層,代理層實(shí)現(xiàn)了具體的請(qǐng)求轉(zhuǎn)發(fā)規(guī)則,然后轉(zhuǎn)發(fā)請(qǐng)求到后面的多個(gè)節(jié)點(diǎn)上,因此這種方式也叫做中心化方式的集群方案,Codis就是以這種方式實(shí)現(xiàn)的集群化方案。


Codis是由國人前豌豆莢大神開發(fā)的,采用中心化方式的集群方案。因?yàn)樾枰韺覲roxy來進(jìn)行所有請(qǐng)求的轉(zhuǎn)發(fā),所以對(duì)Proxy的性能要求很高,Codis采用Go語言開發(fā),兼容了開發(fā)效率和性能。
Codis包含了多個(gè)組件:
codis-proxy:主要負(fù)責(zé)對(duì)請(qǐng)求的讀寫進(jìn)行轉(zhuǎn)發(fā) codis-dashbaord:統(tǒng)一的控制中心,整合了數(shù)據(jù)轉(zhuǎn)發(fā)規(guī)則、故障自動(dòng)恢復(fù)、數(shù)據(jù)在線遷移、節(jié)點(diǎn)擴(kuò)容縮容、自動(dòng)化運(yùn)維API等功能 codis-group:基于Redis 3.2.8版本二次開發(fā)的Redis Server,增加了異步數(shù)據(jù)遷移功能 codis-fe:管理多個(gè)集群的UI界面
可見Codis的組件還是挺多的,它的功能非常全,除了請(qǐng)求轉(zhuǎn)發(fā)功能之外,還實(shí)現(xiàn)了在線數(shù)據(jù)遷移、節(jié)點(diǎn)擴(kuò)容縮容、故障自動(dòng)恢復(fù)等功能。
Codis的Proxy就是負(fù)責(zé)請(qǐng)求轉(zhuǎn)發(fā)的組件,它內(nèi)部維護(hù)了請(qǐng)求轉(zhuǎn)發(fā)的具體規(guī)則,Codis把整個(gè)集群劃分為1024個(gè)槽位,在處理讀寫請(qǐng)求時(shí),采用crc32Hash算法計(jì)算key的Hash值,然后再根據(jù)Hash值對(duì)1024個(gè)槽位取模,最終找到具體的Redis節(jié)點(diǎn)。
Codis最大的特點(diǎn)就是可以在線擴(kuò)容,在擴(kuò)容期間不影響客戶端的訪問,也就是不需要停機(jī)。這對(duì)業(yè)務(wù)使用方是極大的便利,當(dāng)集群性能不夠時(shí),就可以動(dòng)態(tài)增加節(jié)點(diǎn)來提升集群的性能。
為了實(shí)現(xiàn)在線擴(kuò)容,保證數(shù)據(jù)在遷移過程中還有可靠的性能,Codis針對(duì)Redis進(jìn)行了修改,增加了針對(duì)異步遷移數(shù)據(jù)相關(guān)命令,它基于Redis 3.2.8進(jìn)行開發(fā),上層配合Dashboard和Proxy組件,完成對(duì)業(yè)務(wù)無損的數(shù)據(jù)遷移和擴(kuò)容功能。
因此,要想使用Codis,必須使用它內(nèi)置的Redis,這也就意味著Codis中的Redis是否能跟上官方最新版的功能特性,可能無法得到保障,這取決于Codis的維護(hù)方,目前Codis已經(jīng)不再維護(hù),所以使用Codis時(shí)只能使用3.2.8版的Redis,這是一個(gè)痛點(diǎn)。
另外,由于集群化都需要部署多個(gè)節(jié)點(diǎn),因此操作集群并不能完全像操作單個(gè)Redis一樣實(shí)現(xiàn)所有功能,主要是對(duì)于操作多個(gè)節(jié)點(diǎn)可能產(chǎn)生問題的命令進(jìn)行了禁用或限制,具體可參考Codis不支持的命令列表。
但這不影響它是一個(gè)優(yōu)秀的集群化方案,由于我司使用Redis集群方案較早,那時(shí)Redis Cluster還不夠成熟,所以我司使用的Redis集群方案就是Codis。
目前我的工作主要是圍繞Codis展開的,我們公司對(duì)Codis進(jìn)行了定制開發(fā),還對(duì)Redis進(jìn)行了一些改造,讓Codis支持了跨多個(gè)數(shù)據(jù)中心的數(shù)據(jù)同步,因此我對(duì)Codis的代碼比較熟悉,后面會(huì)專門寫一些文章來剖析Codis的實(shí)現(xiàn)原理,學(xué)習(xí)它的原理,這對(duì)我們理解分布式存儲(chǔ)有很大的幫助!
Twemproxy
Twemproxy是由Twitter開源的集群化方案,它既可以做Redis Proxy,還可以做Memcached Proxy。
它的功能比較單一,只實(shí)現(xiàn)了請(qǐng)求路由轉(zhuǎn)發(fā),沒有像Codis那么全面有在線擴(kuò)容的功能,它解決的重點(diǎn)就是把客戶端分片的邏輯統(tǒng)一放到了Proxy層而已,其他功能沒有做任何處理。

Tweproxy推出的時(shí)間最久,在早期沒有好的服務(wù)端分片集群方案時(shí),應(yīng)用范圍很廣,而且性能也極其穩(wěn)定。
但它的痛點(diǎn)就是無法在線擴(kuò)容、縮容,這就導(dǎo)致運(yùn)維非常不方便,而且也沒有友好的運(yùn)維UI可以使用。Codis就是因?yàn)樵谶@種背景下才衍生出來的。
Redis Cluster
采用中間加一層Proxy的中心化模式時(shí),這就對(duì)Proxy的要求很高,因?yàn)樗坏┏霈F(xiàn)故障,那么操作這個(gè)Proxy的所有客戶端都無法處理,要想實(shí)現(xiàn)Proxy的高可用,還需要另外的機(jī)制來實(shí)現(xiàn),例如Keepalive。
而且增加一層Proxy進(jìn)行轉(zhuǎn)發(fā),必然會(huì)有一定的性能損耗,那么除了客戶端分片和上面提到的中心化的方案之外,還有比較好的解決方案么?
Redis官方推出的Redis Cluster另辟蹊徑,它沒有采用中心化模式的Proxy方案,而是把請(qǐng)求轉(zhuǎn)發(fā)邏輯一部分放在客戶端,一部分放在了服務(wù)端,它們之間互相配合完成請(qǐng)求的處理。
Redis Cluster是在Redis 3.0推出的,早起的Redis Cluster由于沒有經(jīng)過嚴(yán)格的測(cè)試和生產(chǎn)驗(yàn)證,所以并沒有廣泛推廣開來。也正是在這樣的背景下,業(yè)界衍生了出了上面所說的中心化集群方案:Codis和Tweproxy。
但隨著Redis的版本迭代,Redis官方的Cluster也越來越穩(wěn)定,更多人開始采用官方的集群化方案。也正是因?yàn)樗枪俜酵瞥龅?,所以它的持續(xù)維護(hù)性可以得到保障,這就比那些第三方的開源方案更有優(yōu)勢(shì)。
Redis Cluster沒有了中間的Proxy代理層,那么是如何進(jìn)行請(qǐng)求的轉(zhuǎn)發(fā)呢?
Redis把請(qǐng)求轉(zhuǎn)發(fā)的邏輯放在了Smart Client中,要想使用Redis Cluster,必須升級(jí)Client SDK,這個(gè)SDK中內(nèi)置了請(qǐng)求轉(zhuǎn)發(fā)的邏輯,所以業(yè)務(wù)開發(fā)人員同樣不需要自己編寫轉(zhuǎn)發(fā)規(guī)則,Redis Cluster采用16384個(gè)槽位進(jìn)行路由規(guī)則的轉(zhuǎn)發(fā)。

沒有了Proxy層進(jìn)行轉(zhuǎn)發(fā),客戶端可以直接操作對(duì)應(yīng)的Redis節(jié)點(diǎn),這樣就少了Proxy層轉(zhuǎn)發(fā)的性能損耗。
Redis Cluster也提供了在線數(shù)據(jù)遷移、節(jié)點(diǎn)擴(kuò)容縮容等功能,內(nèi)部還內(nèi)置了哨兵完成故障自動(dòng)恢復(fù)功能,可見它是一個(gè)集成所有功能于一體的Cluster。因此它在部署時(shí)非常簡單,不需要部署過多的組件,對(duì)于運(yùn)維極其友好。
Redis Cluster在節(jié)點(diǎn)數(shù)據(jù)遷移、擴(kuò)容縮容時(shí),對(duì)于客戶端的請(qǐng)求處理也做了相應(yīng)的處理。當(dāng)客戶端訪問的數(shù)據(jù)正好在遷移過程中時(shí),服務(wù)端與客戶端制定了一些協(xié)議,來告知客戶端去正確的節(jié)點(diǎn)上訪問,幫助客戶端訂正自己的路由規(guī)則。
雖然Redis Cluster提供了在線數(shù)據(jù)遷移的功能,但它的遷移性能并不高,遷移過程中遇到大key時(shí)還有可能長時(shí)間阻塞遷移的兩個(gè)節(jié)點(diǎn),這個(gè)功能相較于Codis來說,Codis數(shù)據(jù)遷移性能更好。這里先了解一個(gè)大概就好,后面我會(huì)專門針對(duì)Codis和Redis Cluster在線遷移功能的性能對(duì)比寫一些文章。
現(xiàn)在越來越多的公司開始采用Redis Cluster,有能力的公司還在它的基礎(chǔ)上進(jìn)行了二次開發(fā)和定制,來解決Redis Cluster存在的一些問題,我們期待Redis Cluster未來有更好的發(fā)展。
總結(jié)
比較完了這些集群化方案,下面我們來總結(jié)一下。

業(yè)界主流的集群化方案就是以上這些,并對(duì)它們的特點(diǎn)和區(qū)別做了簡單的介紹,我們?cè)陂_發(fā)過程中選擇自己合適的集群方案即可,但最好是理解它們的實(shí)現(xiàn)原理,在使用過程中遇到問題才可以更從容地去解決。
