天天看點

Redis之分布式搭建及使用快速入門

文章目錄

        • 1、為什麼需要用redis叢集
        • 2、主從複制
          • a、主從複制配置
        • 3、可用性保證之哨兵機制(Sentinel)
        • 4、redis分布式方案
          • a、用戶端Sharding
          • b、代理Proxy之Twemproxy
          • c、代理Proxy之Codis
          • d、Redis Cluster
          • e、分片方案總結

1、為什麼需要用redis叢集

老套路,性能、擴充、可用性。下面幾個說法就當故事聽聽了。

性能

  • 第一個是因為Redis 本身的QPS已經很高了,但是如果在一些缤紛咖喱昂非常高的情況下,性能還是會受到影響。這個時候我們希望有更多的redis服務來完成工作。

擴充

  • 第二個是出于存儲的考慮。因為redis所有的資料都放在記憶體中,如果資料量大,很容易受到硬體的限制。更新硬體收效和成本比太低,是以我們需要有一種橫向擴充的方法。

可用性

  • 第三個是可用性和安全的問題了。如果隻有一個redis服務,一旦服務當機,那麼所有的用戶端都無法通路,會對業務造成很大的影響。另一個,如果硬體發生故障,而單機的資料無法恢複的話,帶來的影響也是災難性的。

可用性、資料安全、性能…。。。。是在編寫不下去了。。。其實就幾句話

  • 一台性能有限、是以隻能擴充多台,擴充多台,就涉及到分布式叢集問題,自然就延伸出cap理論了。就這麼簡單。真的是個人都喜歡去改個詞 弄的千奇百怪。。哎。。

2、主從複制

a、主從複制配置

隻是針對主從模式下,例如加入了sentinel 的主從關系。沒有這樣的中間件幫忙。自身切換很麻煩。

redis -cluster 叢集模式不能使用主從複制相關指令

  • 會報錯:(error) ERR REPLICAOF not allowed in cluster mode.

配置方法

  • 一種:在每個slave節點的redis.conf配置檔案增加一行
    • slaveof 192.168.20.202 6379

  • 二種:啟動時候通過啟動參數指定master節點
    • redis-server --slaveof 192.168.20.202 6379

切換變化

  • 主從切換
    • slaveof xx xx

      這樣自己就變成從了
  • 主從切換的時候,這個配置會被重寫成
    • # slaveof 192.168.20.202 6379
      # Generated by CONFIG REWRITE
      replicaof 192.168.20.202 6379
                 
  • 檢視叢集狀态
    • info replication

  • 斷開主從複制
    • slaveof no one

      此刻就斷開聯系了。不再複制資料

3、可用性保證之哨兵機制(Sentinel)

就是在主庫故障了。重新選舉主節點 ; 分别是斷開連接配接時長、優先級排序、複制數量、程序id 來決定選舉結果。Sentinel是沒有主從隻分,但是當redis叢集master挂了,會采用Ratf算法選擇一個Sentinel臨時主節點去做主從切換

《快速搭建一主二從Sentinel監控配置》

功能描述:

  • 監控:Sentinel 會不斷檢查主伺服器和從伺服器是否正常運作
  • 通知:如果某一個被監控的執行個體出現問題,Sentinel可以通過API發出通知
  • 自動故障轉移(failover):如果主伺服器發生故障,Sentinel可以啟動故障轉移過程。把某台伺服器更新為主伺服器,并發出通知
  • 配置管理:用戶端連接配接到Sentinel,擷取目前的Redis主伺服器的位址

4、redis分布式方案

所有用戶端連接配接一個proxy或者用分區架構來實作資料分片(存儲在不同redis伺服器)
a、用戶端Sharding

采用2個獨立的redis 然後用Sharding來操作測試

​ 使用 ShardedJedis 之類的用戶端分片代碼的優勢是配置簡單,不依賴于其他中間

件,分區的邏輯可以自定義,比較靈活。但是基于用戶端的方案,不能實作動态的服務

增減,每個用戶端需要自行維護分片政策,存在重複代碼。

​ 第二種思路就是把分片的代碼抽取出來,做成一個公共服務,所有的用戶端都連接配接

到這個代理層。由代理層來實作請求和轉發。

示例:

package org.example;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;

import java.util.ArrayList;
import java.util.List;

@RunWith(JUnit4.class)
public class ShardingTest {

    @Test
    public void test() {
        JedisPoolConfig poolConfig = new JedisPoolConfig();

        // redis伺服器
        JedisShardInfo shardInfo1 = new JedisShardInfo("192.168.170.3", 1000);
        JedisShardInfo shardInfo2 = new JedisShardInfo("192.168.170.3", 1001);

        // 連接配接池
        List<JedisShardInfo> infoList = new ArrayList<>(2);
        infoList.add(shardInfo1);
        infoList.add(shardInfo2);

        ShardedJedisPool jedisPool = new ShardedJedisPool(poolConfig, infoList);

        try (ShardedJedis shardedJedis = jedisPool.getResource()) {
            for (int i = 0; i < 10000; i++) {
                shardedJedis.set("k" + i, "" + i);
            }

            for (int i = 0; i < 10000; i++) {
                shardedJedis.get("k" + i);
            }

        } catch (Exception e) {
            throw e;
        }

    }

}
           
b、代理Proxy之Twemproxy

twitter 開源的。two-em-proxy

比較穩定,成本效益高

出現故障不能自動轉移,架構複雜,需要借助其他元件(LVS/HAproxy+Keepalived)實作HA

擴縮容需要修改配置,不能實作平滑地擴縮容(需要重新分布資料)。

c、代理Proxy之Codis

國内豌豆莢開源的Codis,是一個代理中間件,由Go語言開發

codis不支援的指令:https://github.com/CodisLabs/codis/blob/release3.2/doc/unsupported_cmds.md

分片原理:Codis把所有的key分成了N個槽(例如1024),每個槽對應一個分組,一個分組對應于一個或者一組 Redis 執行個體。Codis 對 key 進行 CRC32 運算,得到一個32位的數字,然後模以N(槽的個數),得到餘數,這個就是key對應的槽,槽後面就是Redis的執行個體。比如4個槽:

Codis的槽位映射關系是儲存在 Proxy中的,如果要解決單點的問題,Codis 也要做叢集部署, 多個Codis節點怎麼同步槽和執行個體的關系呢?需要運作一個Zookeeper (或者etcd/本地檔案)

d、Redis Cluster

3.0開始正式推出的,同時也可以實作高可用,跟Codis不一樣,它是去中心化的。用戶端可以連接配接到任意一個可用節點。

Redis既沒有用哈希取模,也沒有用一緻性哈希,而是用虛拟槽來實作的。

Redis建立了16384個槽(slot),每個節點負責一定區間的slot。比如Node1負

責0-5460,Node2負責5461-10922,Node3負責10923-16383

注意:key與slot的關系是永遠不會變的,會變的隻有slot和Redis節點的關系。

《1 秒搭建Redis-Cluster叢集》

  • 檢視key屬于那個slot
    cluster keyslot lilei
               
  • 多key操作的hash tags{}
    multi key 操作是不能跨節點的,是以要讓資料分布到一個節點,就可以如下:
    # 這樣{} 的标志,讓他們都會落在桶一個slot裡面
    set a{qs}a 1 
    set a{qs}b 1 
    set a{qs}c 1 
    set a{qs}d 1 
    set a{qs}e 1 
               
  • 用戶端重定向
    在使用redis-cli時,可以加上-c參數,這樣redis會自動幫我們連接配接到正确的節點執行指令。
    redis-cli -p 7292 -c
               
  • 資料遷移
    因為key 和slot的關系是永遠不會變的,當新增了節點的時候,需要把原有的slot 配置設定給新的節點服務,并且把相關的資料遷移過來。
    添加新節點(新增一個7297)
    redis-cli--cluster add-node 127.0.0.1:7291 127.0.0.1:7297
               
    新增的節點沒有哈希槽,不能分布資料,在原來的任意一個節點上執行:
    redis-cli--cluster reshard 127.0.0.1:7291
               
  • 高可用和主從切換原理

    當slave 發現自己的master 變為fail狀态時,便嘗試進行failover,以期成為新的master。由于挂掉的master可能會有多個slave進而存在多個slave競争成為master節點的過程。

    自動實作主從角色配置設定,主從自動切換

    過程如下:

    1、slave發現自己的master 變為fail

    2、将自己記錄的叢集currentEpoch 加1,并廣播FAILOVER_AUTH_REQUEST 資訊

    3、其他節點收到該資訊,隻有master響應,判斷請求者的合法性,并發送FAILOVER_AUTH_ACK,對每個epoch隻發送一次ack

    4、嘗試failover的slave手機FAILOVER_AUTH_ACK

    5、超過半數後變成新Master

    6、廣播Pong通知其他叢集節點

e、分片方案總結
功能 Codis Tewmporyx Redis Cluster
重新分片不需要重新開機 Yes NO Yes
pipeline Yes Yes

多key操作的hash tags{}

讓指令落在同一節點

Yes Yes Yes
重新分片時的多key操作 Yes - NO
用戶端支援 所有 所有 支援cluster協定的用戶端

繼續閱讀