Redis集羣方案

  前段時間搞了搞Redis集羣,想用作推薦系統的線上存儲,說來挺有趣,這邊基礎架構不太完善,所以須要咱們作推薦系統的本身來搭這個存儲環境,就本身折騰了折騰。公司所給機器的單機性能其實挺給力,已經能夠知足目前的業務需求,想作redis集羣主要有如下幾點考慮node

    一、擴展性,scale-out,之後數據量變得很大以後,不至於推到重來,redis雖然能夠開啓虛擬內存功能,單機也能提供超過物理內存上限的容量,但頻繁在內存和硬盤間swap頁會大大下降其性能,有點兒違背redis的設計初衷。git

    二、redis是一個單線程io複用的結構,沒法有效利用服務器的多核結構,若是能在一臺多核機器起多個redis進程,共同提供服務,效率會更高一些。github

    三、主從,數據備份和容災。。web

  所以計劃作的redis集羣但願能夠實現如下功能:redis

    一、data sharding,支持數據切片。算法

    二、主從備份,主節點寫數據,主和從都提供讀請求服務,而且支持主從自動切換。數據庫

    三、讀請求作負載均衡。服務器

    四、更好地,支持節點failover,數據自動遷移。架構

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

  【第一步】嘗試官方方案

   確定想去查看一下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 the unstable branch 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 between query routing and client 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,B,C) , 3(A,B,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:

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

redis slave master/slave replication

redis sentinel to 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正在開發中的模塊,我不太敢用。

  另外,我捨棄本身的這個初步方案還有兩個緣由:

    一、本身在寫客戶端data sharding和均衡服務的時候,發現實際須要考慮的問題比開始想的要複雜一些,若是寫完,其實至關於將twemproxy的功能作了一遍,造輪子的事情仍是少幹。

    二、功能作得有些冗餘,一次讀請求要通過客戶端的sharding、而後還有通過lvs再到實際的服務器,不作優化的話,會增長很多延遲。

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

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

    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來消除單點和故障恢復。

相關文章
相關標籤/搜索