1. 程式人生 > 資料庫 >Redis叢集方案

Redis叢集方案

前段時間搞了搞Redis叢集,想用做推薦系統的線上儲存,說來挺有趣,這邊基礎架構不太完善,因此需要我們做推薦系統的自己來搭這個儲存環境,就自己折騰了折騰。公司所給機器的單機效能其實挺給力,已經可以滿足目前的業務需求,想做redis叢集主要有以下幾點考慮:

1、擴充套件性,scale-out,以後資料量變得很大之後,不至於推到重來,redis雖然可以開啟虛擬記憶體功能,單機也能提供超過實體記憶體上限的容量,但頻繁在記憶體和硬碟間swap頁會大大降低其效能,有點兒違背redis的設計初衷。

2、redis是一個單執行緒io複用的結構,無法有效利用伺服器的多核結構,如果能在一臺多核機器起多個redis程序,共同提供服務,效率會更高一些。

3、主從,資料備份和容災。。

因此計劃做的redis叢集希望可以實現以下功能:

1、data sharding,支援資料切片。

2、主從備份,主節點寫資料,主和從都提供讀請求服務,並且支援主從自動切換。

3、讀請求做負載均衡。

4、更好地,支援節點failover,資料自動遷移。

下面是前後經歷的一個過程:

【第一步】嘗試官方方案

肯定想去檢視一下redis的官方叢集方案,但是很遺憾,官方對cluster的宣告如下:

Unfortunately Redis Cluster is currently not production ready,however you can get more information about it reading the specification or checking the partial implementation in theunstablebranch of the Redis GitHub repositoriy.

Once Redis Cluster will be available,and if a Redis Cluster complaint client is available for your language,Redis Cluster will be the de facto standard for Redis partitioning.

Redis Cluster is a mix betweenquery routingandclient side partitioning.

由於這邊想做生產環境部署,unstable branch目前還是不敢用,在官方目前的版本上做提前開發又沒有資源和時間,因此就放棄了。

【第二步】初步設想的方案

捨棄了官方的方案後,就想能不能自己搭一個,當時初步的想法是:用lvs做讀請求的負載均衡,在客戶端程式碼裡自己寫一個一致性hash演算法做資料切片,配置redis主從,並且配置keepalived做主從自動切換。這個方案應該可以施行的,但當時自己遇到一些細節方面的問題,就在stackoverflow上問了一下,問題如下:

Since the redis cluster is still a work in progress,I want to build a simplied one by myselfin the current stage. The system should support data sharding,load balance and master-slave backup. A preliminary plan is as follows:

  1. Master-slave: use multiple master-slave pairs in different locations to enhance the data security. Matsters are responsible for the write operation,while both masters and slaves can provide the read service. Datas are sent to all the masters during one write operation. Use Keepalived between the master and the slave to detect failures and switch master-slave automatically.

  2. Data sharding: write a consistant hash on the client side to support data sharding during write/read in case the memory is not enougth in single machine.

  3. Load balance: use LVS to redirect the read request to the corresponding server for the load balance.

My question is how to combine the LVS and the data sharding together?

For example,because of data sharding,all keys are splited and stored in server A,B and C without overlap. Considering the slave backup and other master-slave pairs,the system will contain 1(A,B,C),2(A,3(A,C) and so on,where each one has three servers. How to configure the LVS to support the redirection in such a situation when a read request comes? Or is there other approachs in redis to achieve the same goal?

Thanks:)

有個網友給了兩個建議:

You can really close to what you need by using:

twemproxyshard data across multiple redis nodes (it also supports node ejection and connection pooling)

redis slave master/slave replication

redis sentinelto handle master failover

depending on your needs you probably need some script listening to fail overs (see sentinel docs) and clean things up when a master goes down

這位網友的兩個建議挺啟發的,我在看redis的官方doc的時候,對twemproxy有一些印象,但當時沒有太在意,至於後者用redis sentinel做master failover,redis sentinel也是一個redis正在開發中的模組,我不太敢用。

另外,我捨棄自己的這個初步方案還有兩個原因:

1、自己在寫客戶端data sharding和均衡服務的時候,發現實際需要考慮的問題比開始想的要複雜一些,如果寫完,其實相當於將twemproxy的功能做了一遍,造輪子的事情還是少幹。

2、功能做得有些冗餘,一次讀請求要經過客戶端的sharding、然後還有經過lvs再到實際的伺服器,不做優化的話,會增加不少延遲。

【第三步】最終的方案,如下圖所示

Redis叢集方案

圖中畫的挺明白了,就不再多解釋了。

twemproxy是twitter開源的一個數據庫代理服務,可以用於memcached和redis的sharding,相容二者的標準介面,但是對於redis的keys,dbsize等命令不支援,這個其實想一下也就明白了,這種pool內跨機做統計的命令proxy一般不會支援的。另外,twemproxy在自身與後臺redis之間使用pipeline傳送命令,因此效能損失比較小。但是,twemproxy對於每一個客戶端連線開啟的mbuf有限,最大可以設定為64k,如果在客戶端代理層與twemproxy之間也使用pipeline,這個pipeline不能太深,而且不支援pipeline的原子性(transaction),其實,這個時候,相當於客戶端連線與redis資料庫之間存在兩層pipeline,分別是客戶端到twemproxy的pipeline,和twemproy到後臺redis伺服器的pipeline,由於二者buffer深度不一致,因此不支援pipeline的transaction也就好理解了。。在引入了twemproxy,插入大規模資料的時候,有時候確實挺耗時,而且pipeline不保證原子性,丟資料時的恢復問題在客戶端需要進行額外關注。對於非transaction的pipeline總丟資料,或者對於資料量比較大的key一次性取資料失敗等問題,後來經查是twemproxy端timeou值設定過小,按照官方示例設定400ms,會在一次性操作大資料量的時候返回timeout失敗,這個數值需要慎重根據業務(具體的,就是客戶端單次命令操作的資料量)進行設定,一般2000ms差不多就夠用了(可以支援一次操作接近百萬的資料)。

上面的結構,將讀操作的負載均衡放到了客戶端程式碼來做,寫操作控制也在客戶端層的程式碼裡,另外,對於twemproy單點、主從之間可以引入keepalived來消除單點和故障恢復。