1. 程式人生 > >Redis之高可用、叢集、雲平臺搭建

Redis之高可用、叢集、雲平臺搭建

文章大綱

一、基礎知識學習
二、Redis常見的幾種架構及優缺點總結
三、Redis之Redis Sentinel(哨兵)實戰
四、Redis之Redis Cluster(分散式叢集)實戰
五、Java之Jedis連線Redis(Redis Cluster版本)
六、Redis之雲平臺介紹
七、專案原始碼與資料下載
八、參考文章

一、基礎知識學習

  Redis的基礎包括以下內容,可參考文章https://www.cnblogs.com/WUXIAOCHANG/p/10832330.html進行學習
(1)安裝並設定開機自動啟動
(2)Redis檔案結構
(3)Redis啟動方式
(4)Redis持久化

(5)Redis配置檔案詳解
(7)Redis圖形化工具
(8)Java之Jedis連線Redis單機

二、Redis常見的幾種架構及優缺點總結

1. Redis單副本

Redis單副本,採用單個Redis節點部署架構,沒有備用節點實時同步資料,不提供資料持久化和備份策略,適用於資料可靠性要求不高的純快取業務場景。

 

優點
架構簡單,部署方便;
高性價比:快取使用時無需備用節點(單例項可用性可以用supervisor或crontab保證),當然為了滿足業務的高可用性,也可以犧牲一個備用節點,但同時刻只有一個例項對外提供服務;
高效能。

缺點
不保證資料的可靠性;

在快取使用,程序重啟後,資料丟失,即使有備用的節點解決高可用性,但是仍然不能解決快取預熱問題,因此不適用於資料可靠性要求高的業務;
高效能受限於單核CPU的處理能力(Redis是單執行緒機制),CPU為主要瓶頸,所以適合操作命令簡單,排序、計算較少的場景。也可以考慮用Memcached替代。

2. Redis多副本(主從)

Redis多副本,採用主從(replication)部署結構,相較於單副本而言最大的特點就是主從例項間資料實時同步,並且提供資料持久化和備份策略。主從例項部署在不同的物理伺服器上,根據公司的基礎環境配置,可以實現同時對外提供服務和讀寫分離策略。

 

優點
高可靠性:一方面,採用雙機主備架構,能夠在主庫出現故障時自動進行主備切換,從庫提升為主庫提供服務,保證服務平穩執行;另一方面,開啟資料持久化功能和配置合理的備份策略,能有效的解決資料誤操作和資料異常丟失的問題;
讀寫分離策略:從節點可以擴充套件主庫節點的讀能力,有效應對大併發量的讀操作。

缺點
故障恢復複雜,如果沒有RedisHA系統(需要開發),當主庫節點出現故障時,需要手動將一個從節點晉升為主節點,同時需要通知業務方變更配置,並且需要讓其它從庫節點去複製新主庫節點,整個過程需要人為干預,比較繁瑣;
主庫的寫能力受到單機的限制,可以考慮分片;
主庫的儲存能力受到單機的限制,可以考慮Pika;
原生複製的弊端在早期的版本中也會比較突出,如:Redis複製中斷後,Slave會發起psync,此時如果同步不成功,則會進行全量同步,主庫執行全量備份的同時可能會造成毫秒或秒級的卡頓;又由於COW機制,導致極端情況下的主庫記憶體溢位,程式異常退出或宕機;主庫節點生成備份檔案導致伺服器磁碟IO和CPU(壓縮)資源消耗;傳送數GB大小的備份檔案導致伺服器出口頻寬暴增,阻塞請求,建議升級到最新版本。

3. Redis Sentinel(哨兵)

  Redis Sentinel是社群版本推出的原生高可用解決方案,其部署架構主要包括兩部分:Redis Sentinel叢集和Redis資料叢集。
  其中Redis Sentinel叢集是由若干Sentinel節點組成的分散式叢集,可以實現故障發現、故障自動轉移、配置中心和客戶端通知。Redis Sentinel的節點數量要滿足2n+1(n>=1)的奇數個。

   

優點
Redis Sentinel叢集部署簡單;
能夠解決Redis主從模式下的高可用切換問題;
很方便實現Redis資料節點的線形擴充套件,輕鬆突破Redis自身單執行緒瓶頸,可極大滿足Redis大容量或高效能的業務需求;
可以實現一套Sentinel監控一組Redis資料節點或多組資料節點。

缺點
部署相對Redis主從模式要複雜一些,原理理解更繁瑣;
資源浪費,Redis資料節點中slave節點作為備份節點不提供服務;
Redis Sentinel主要是針對Redis資料節點中的主節點的高可用切換,對Redis的資料節點做失敗判定分為主觀下線和客觀下線兩種,對於Redis的從節點有對節點做主觀下線操作,並不執行故障轉移。
不能解決讀寫分離問題,實現起來相對複雜。

建議
如果監控同一業務,可以選擇一套Sentinel叢集監控多組Redis資料節點的方案,反之選擇一套Sentinel監控一組Redis資料節點的方案。
sentinel monitor <master-name> <ip> <port> <quorum> 配置中的<quorum>建議設定成Sentinel節點的一半加1,當Sentinel部署在多個IDC的時候,單個IDC部署的Sentinel數量不建議超過(Sentinel數量 – quorum)。
合理設定引數,防止誤切,控制切換靈敏度控制:
a. quorum
b. down-after-milliseconds 30000
c. failover-timeout 180000
d. maxclient
e. timeout

部署的各個節點伺服器時間儘量要同步,否則日誌的時序性會混亂。
Redis建議使用pipeline和multi-keys操作,減少RTT次數,提高請求效率。
自行搞定配置中心(zookeeper),方便客戶端對例項的連結訪問。

4. Redis Cluster

  Redis Cluster是社群版推出的Redis分散式叢集解決方案,主要解決Redis分散式方面的需求,比如,當遇到單機記憶體,併發和流量等瓶頸的時候,Redis Cluster能起到很好的負載均衡的目的。
  Redis Cluster叢集節點最小配置6個節點以上(3主3從),其中主節點提供讀寫操作,從節點作為備用節點,不提供請求,只作為故障轉移使用。
  Redis Cluster採用虛擬槽分割槽,所有的鍵根據雜湊函式對映到0~16383個整數槽內,每個節點負責維護一部分槽以及槽所印對映的鍵值資料。

 

優點
無中心架構;
資料按照slot儲存分佈在多個節點,節點間資料共享,可動態調整資料分佈;
可擴充套件性:可線性擴充套件到1000多個節點,節點可動態新增或刪除;
高可用性:部分節點不可用時,叢集仍可用。通過增加Slave做standby資料副本,能夠實現故障自動failover,節點之間通過gossip協議交換狀態資訊,用投票機制完成Slave到Master的角色提升;
降低運維成本,提高系統的擴充套件性和可用性。

缺點
Client實現複雜,驅動要求實現Smart Client,快取slots mapping資訊並及時更新,提高了開發難度,客戶端的不成熟影響業務的穩定性。目前僅JedisCluster相對成熟,異常處理部分還不完善,比如常見的“max redirect exception”。
節點會因為某些原因發生阻塞(阻塞時間大於clutser-node-timeout),被判斷下線,這種failover是沒有必要的。
資料通過非同步複製,不保證資料的強一致性。
多個業務使用同一套叢集時,無法根據統計區分冷熱資料,資源隔離性較差,容易出現相互影響的情況。
Slave在叢集中充當“冷備”,不能緩解讀壓力,當然可以通過SDK的合理設計來提高Slave資源的利用率。
Key批量操作限制,如使用mset、mget目前只支援具有相同slot值的Key執行批量操作。對於對映為不同slot值的Key由於Keys不支援跨slot查詢,所以執行mset、mget、sunion等操作支援不友好。
Key事務操作支援有限,只支援多key在同一節點上的事務操作,當多個Key分佈於不同的節點上時無法使用事務功能。
Key作為資料分割槽的最小粒度,不能將一個很大的鍵值物件如hash、list等對映到不同的節點。
不支援多資料庫空間,單機下的redis可以支援到16個數據庫,叢集模式下只能使用1個數據庫空間,即db 0。
複製結構只支援一層,從節點只能複製主節點,不支援巢狀樹狀複製結構。
避免產生hot-key,導致主庫節點成為系統的短板。
避免產生big-key,導致網絡卡撐爆、慢查詢等。
重試時間應該大於cluster-node-time時間。
Redis Cluster不建議使用pipeline和multi-keys操作,減少max redirect產生的場景。

5. Redis自研

Redis自研的高可用解決方案,主要體現在配置中心、故障探測和failover的處理機制上,通常需要根據企業業務的實際線上環境來定製化。

   

優點
高可靠性、高可用性;
自主可控性高;
貼切業務實際需求,可縮性好,相容性好。

缺點
實現複雜,開發成本高;
需要建立配套的周邊設施,如監控,域名服務,儲存元資料資訊的資料庫等;
維護成本高。

三、Redis之Redis Sentinel(哨兵)實戰

1. 實戰的專案架構

  採用一主(MASTER)二從(SLAVE)三哨兵(SENTINEL)的架構

2. 將下載的Redis複製3分,分別命名如下:

 

3. 修改三個Reids的配置檔案

3.1 配置主從

(1)master_6379資料夾中redis.windows.conf檔案配置

    port 6379

(2)slave_6380資料夾中redis.windows.conf檔案配置

                 port 6380
                 slaveof 127.0.0.1 6379

(3)slave_6381資料夾中redis.windows.conf檔案配置

                 port 6381
                 slaveof 127.0.0.1 6379

3.2 哨兵配置
每一個redis目錄中都建立一個文sentinel.conf檔案
master_6379的sentinel.conf檔案配置如下

#當前Sentinel服務執行的埠
port 26379
#master
#Sentinel去監視一個名為mymaster的主redis例項,這個主例項的IP地址為本機地址127.0.0.1,埠號為6379,
#而將這個主例項判斷為失效至少需要2個 Sentinel程序的同意,只要同意Sentinel的數量不達標,自動failover就不會執行
sentinel monitor mymaster 127.0.0.1 6379 1
#指定了Sentinel認為Redis例項已經失效所需的毫秒數。當 例項超過該時間沒有返回PING,或者直接返回錯誤,那麼Sentinel將這個例項標記為主觀下線。
#只有一個 Sentinel程序將例項標記為主觀下線並不一定會引起例項的自動故障遷移:只有在足夠數量的Sentinel都將一個例項標記為主觀下線之後,例項才會被標記為客觀下線,這時自動故障遷移才會執行
sentinel down-after-milliseconds mymaster 5000
#指定了在執行故障轉移時,最多可以有多少個從Redis例項在同步新的主例項,在從Redis例項較多的情況下這個數字越小,同步的時間越長,完成故障轉移所需的時間就越長
sentinel config-epoch mymaster 12
#如果在該時間(ms)內未能完成failover操作,則認為該failover失敗
sentinel leader-epoch mymaster 13

slave_6380中的sentinel.conf檔案配置

#當前Sentine2服務執行的埠
port 26479
#slave1
sentinel monitor mymaster 127.0.0.1 6379 1
sentinel down-after-milliseconds mymaster 5000
sentinel config-epoch mymaster 12
sentinel leader-epoch mymaster 13

slave_6381中的sentinel.conf檔案配置

#當前Sentine3服務執行的埠
port 26579
#slave2
sentinel monitor mymaster 127.0.0.1 6379 1
sentinel down-after-milliseconds mymaster 5000
sentinel config-epoch mymaster 12
sentinel leader-epoch mymaster 13

4. 啟動服務

編寫啟動redis指令碼
編寫一個 bat 來啟動 redis,在每個節點目錄下建立 startup.bat,內容如下:

title master_6379
redis-server.exe redis.windows.conf

溫馨提示:
(1)title後名稱需與Reids資料夾名稱一致
(2)可以直接執行startup.bat來啟動redis,也可以在redis安裝目錄下用命令redis-server.exe redis.windows.conf直接啟動

編寫sentinel啟動指令碼
編寫一個 bat 來啟動 sentinel,在每個節點目錄下建立 startup_sentinel.bat,內容如下:

 title master_6379
 redis-server.exe sentinel.conf --sentinel

溫馨提示:
(1) title命名規則 redis資料夾名, 注意“--sentinel”不是註釋,必須存在
(2) 另外啟動sentinel還可以在redis安裝目錄下用命令redis-sentinel sentinel.conf 來啟動

5. Redis服務啟動成功

master 6379

 

slave 6380

 

slave 6381

 

6. sentinel服務啟動成功

sentinel 26379

 

sentinel 26479

 

sentinel 26579

 

7. 服務檢視

7.1 檢視redis服務狀態,命令: info replication
master 6379

 

slave 6380

 

slave 6381

 

7.2 檢視sentinel的狀態,命令: info sentinel

 

8. redis主從自動failover測試

停止master伺服器,檢視剩餘伺服器的狀態
slave 6380

 

slave 6381

 

從上圖中可以看出來,master的伺服器埠從6379變成了6380,也就是說redis自動的實現了主從切換,
我們可以在檢視下sentinel的狀態,如下:

 

我們發現sentinel監控到127.0.0.1:6379已經無法ping通了,切換master伺服器為127.0.0.1:6380

溫馨提示:在實際操作中,不一定master為6380,可能是6381,具體看當時執行策略。

四、Redis之Redis Cluster(分散式叢集)實戰

1. 實戰的專案架構

(1)3個主節點,建議配置3個從節點,其餘3個作為各個主節點的從節點(也是官網推薦的模式),所以需要6臺虛擬機器。主節點崩潰,從節點的Redis就會提升為主節點,代替原來的主節點工作,崩潰的主Redis恢復工作後,會再成為從節點
(2)叢集
(3)主從複製
(4)哨兵模式
(5)分片

2. 所需軟體

(1)Redis
(2)Ruby語言執行環境
(3)Redis的Ruby驅動redis-xxxx.gem
(4)建立Redis叢集的工具redis-trib.rb

3. 下載Redis並建立相應叢集目錄

  把 redis 解壓後,再複製出 5 份,配置 三主三從叢集。 由於 redis 預設埠號為 6379,那麼其它5份的埠可以為6380,6381,6382,6383,6384。 並且把目錄使用埠號命名

 

4. 修改配置檔案

開啟每個Redis目錄下的檔案 redis.windows.conf,修改裡面的埠號分別對應相對應的資料夾名:6379、6380、6381、6382、6383、6384,再修改叢集支援配置,將以下配置前面的#去掉。

 
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 15000
appendonly yes

cluster-config-file nodes-6379.conf 是為該節點的配置資訊,這裡使用 nodes-埠.conf命名方法。服務啟動後會在目錄生成該檔案(為cluster-config-file nodes-資料夾名字.conf)

編寫啟動指令碼,或者進入每個埠命名的資料夾下啟動服務,具體可以參考第三的內容
編寫一個 bat 來啟動 redis,在每個節點目錄下建立 startup.bat,內容如下:

title redis-6379
redis-server.exe redis.windows.conf

溫馨提示:title後面為資料夾名稱

5. 安裝Ruby

redis的叢集使用 ruby指令碼編寫,所以系統需要有 Ruby 環境 ,下載地址
https://rubyinstaller.org/downloads/

   

安裝時3個選項都勾選。

6. 安裝Redis的Ruby驅動redis-xxxx.gem

下載地址 :https://rubygems.org/pages/download

 

  下載後解壓,當前目錄切換到解壓目錄中,如 D:\Program Files\Redis_cluster\rubygems-2.7.7 然後命令列執行 ruby setup.rb
  再用 GEM 安裝 Redis :切換到redis安裝目錄,需要在命令列中,執行 gem install redis

 

7. 安裝叢集指令碼redis-trib

  下載地址 https://raw.githubusercontent.com/antirez/redis/unstable/src/redis-trib.rb
   開啟該連結把裡面的指令碼儲存為redis-trib.rb,建議儲存到一個Redis的目錄下(不用每個都放),例如放到6379目錄下。

溫馨提示:現在開啟這個連結中的程式碼已不支援redis 5.0以下的版本了,因為redis5.0以上不再需要redis-trib.rb了,而是使用自帶的redis-cli作為建立叢集的命令了,老版本的redis-trib.rb可在文章的專案原始碼與參考資料中進行下載

8. 啟動每個節點並且執行叢集構建指令碼

把每個節點下的 start.bat雙擊啟動, 在切換到存放了redis-trib.rb的redis目錄在命令列中執行以下內容:

redis-trib.rb create --replicas 1 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384

溫馨提示:
(1)--replicas 1 表示每個主資料庫擁有從資料庫個數為1。master節點不能少於3個,所以我們用了6個redis
(2)三個主從之間的對應關係由策略進行決定,不一定是6379是主,6380是它的從,但是分配完之後,會有三主三從
(3)如果出現 redis-trib.rb is not longer available! 如果redis版本是5.0以上,則使用如下命令:

redis-cli --cluster create 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 --cluster-replicas 1

(4) 叢集命令建立一次後,以後都不需要再次執行,就算伺服器重啟都不需要,叢集伸縮應該需要

在出現 Can I set the above configuration? (type 'yes' to accept): 請確定並輸入 yes 。成功後的結果如下:

   

9. 連線叢集進行測試

使用Redis客戶端Redis-cli.exe來檢視資料記錄數,以及叢集相關資訊
命令:redis-cli –c –h ”地址” –p "埠號" ; c 表示叢集

 

檢視叢集的資訊,命令:cluster info

 

檢視主從關係,命令: info replication

 

主庫顯示資訊:

 

從庫顯示資訊:

 

檢視各個節點分配slot,命令 cluster nodes

 

可以看到有3個master,3個slave
以及可以看到master各自的slot分佈情況

10. Redis叢集資料分配策略

採用一種叫做雜湊槽 (hash slot)的方式來分配資料,redis cluster 預設分配了 16384 個slot,當我們set一個key 時,會用CRC16演算法來取模得到所屬的slot,然後將這個key分到雜湊槽區間的節點上,具體演算法就是:CRC16(key) % 16384
注意的是:必須要3個以上的主節點,否則在建立叢集時會失敗,三個節點分別承擔的slot 區間是:
節點A覆蓋0-5460;
節點B覆蓋5461-10922;
節點C覆蓋10923-16383.

五、Java之Jedis連線Redis(Redis Cluster版本)

1. 使用idea新建maven專案

       

建立後的專案結構如下:

 

2. pom.xml檔案新增jar包依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.wxc</groupId>
    <artifactId>com-redis2</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>

        <!--新增測試依賴-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <!--新增redis依賴-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.7.2</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.3.2</version>
        </dependency>

    </dependencies>


</project>

3. 新建JedisclusterTest.java進行叢集連線測試

package com.wxc.redis;

import org.junit.Test;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

public class JedisclusterTest {

    //連線redis叢集
    @Test
    public void testJedisCluster() throws Exception {
        //建立一個JedisCluster物件
        Set<HostAndPort> nodes = new HashSet<HostAndPort>();
        nodes.add(new HostAndPort("127.0.0.1", 6379));
        nodes.add(new HostAndPort("127.0.0.1", 6380));
        nodes.add(new HostAndPort("127.0.0.1", 6381));
        nodes.add(new HostAndPort("127.0.0.1", 6382));
        nodes.add(new HostAndPort("127.0.0.1", 6383));
        nodes.add(new HostAndPort("127.0.0.1", 6384));
        System.out.println("開始連線redis叢集");

        //在nodes中指定每個節點的地址
        //jedisCluster在系統中是單例的。
        JedisCluster jedisCluster = new JedisCluster(nodes);

        System.out.println("初始化資料");

        jedisCluster.set("name2", "zhangsan");
        jedisCluster.set("value2", "100");
        String name = jedisCluster.get("name");
        String value = jedisCluster.get("value");
        System.out.println(name);
        System.out.println(value);
        //系統關閉時關閉jedisCluster
        jedisCluster.close();
    }
}

4. 執行專案

 

5. 測試叢集故障轉移與主從備份

5.1 檢視主從關係

 

從圖中我們可以看出,6379,6381,6383是主節點,其他是從節點

5.2 測試故障自動轉移
現在我們將6381的服務斷開,之後再檢視一次服務

 

我們可以看到這兩個服務已經掛了,之後我們再次執行java專案,這次我們把key改為name3、value3

 

再次執行java專案

 

可以看到叢集資料操作成功

5.3 檢視叢集自動主從備份
現在我們用Redis客戶端工具開啟連線,進行資料檢視,我們可以看到name3和value3都插入成功了

 

剛剛我們的6381服務是關閉的,我們現在重新開啟,再看看6381資料是否會自動同步

 

開啟之後,我們發現其資料已經自動同步

七、參考文章

    1. http://database.ctocio.com.cn/239/14564239.shtml
    2. https://blog.csdn.net/weixin_41846320/article/details/83654766
    3. https://blog.csdn.net/weixin_41846320/article/details/83753182