Redis高級內容學習

卑微小吳勵志寫博客第18天。
本片博文較長,如果沒有耐性看完的可以先收藏,以後有時間再慢慢學習。

目錄:

  • Redis性能測試
  • Redis讀寫分離搭建
  • Redis高可用Sentinel搭建
  • Sentinel整合SpringBoot
  • Redis內置集羣搭建和維護
  • 內置集羣整合SpringBoot
  • twemProxy搭建Redis分片式集羣

1. Redis讀寫分離

​ 單機Redis的讀寫速度非常快,能夠支持大量用戶的訪問。雖然Redis的性能很高,但是對於大型網站來說,每秒需要獲取的數據遠遠超過單臺redis服務所能承受的壓力,所以我們迫切需要一種方案能夠解決單臺Redis服務性能不足的問題。

1.1 Redis性能測試

1.1.1 redis-benchmark

​ redis-benchmark是官方自帶的Redis性能測試工具,用來測試Redis在當前環境下的讀寫性能。我們在使用Redis的時候,服務器的硬件配置、網絡狀況、測試環境都會對Redis的性能有所影響,我們需要對Redis實時測試以確定Redis的實際性能。

使用語法:

redis-benchmark [參數] [參數值]

參數說明:

選項 描述 默認值
-h 指定服務器主機名 127.0.0.1
-p 指定服務器端口 6379
-s 指定服務器 socket
-c 指定併發連接數 50
-n 指定請求數 10000
-d 以字節的形式指定 SET/GET 值的數據大小 2
-k 1=keep alive 0=reconnect 1
-r SET/GET/INCR 使用隨機 key, SADD 使用隨機值
-P 通過管道傳輸 請求 1
-q 強制退出 redis。僅顯示 query/sec 值
–csv 以 CSV 格式輸出
-l 生成循環,永久執行測試
-t 僅運行以逗號分隔的測試命令列表。
-I Idle 模式。僅打開 N 個 idle 連接並等待。

安裝redis

在虛擬機中安裝c++環境:

yum install gcc-c++

安裝Redis,依次執行以下命令:

# 解壓
tar -zxf redis-4.0.14.tar.gz
# 進入解壓目錄
cd redis-4.0.14
# 編譯
make
# 安裝
make install PREFIX=/usr/local/redis
# 進入安裝好的redis目錄
cd /usr/local/redis/bin
# 複製配置文件
cp /root/redis-4.0.14/redis.conf ./

# 修改配置文件
vi redis.conf
# Redis後臺啓動
修改 daemonize 爲 yes
# Redis服務器可以跨網絡訪問
修改 bind 爲 0.0.0.0
# 開啓aof持久化
appendonly yes

# 啓動redis
./redis-server redis.conf

執行以下命令,測試性能:

# 執行測試性能命令
./redis-benchmark -t set,get -n 100000

執行結果如下:

====== SET ======
  100000 requests completed in 1.97 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

95.32% <= 1 milliseconds
99.46% <= 2 milliseconds
99.67% <= 3 milliseconds
99.72% <= 4 milliseconds
99.84% <= 5 milliseconds
99.88% <= 6 milliseconds
99.90% <= 10 milliseconds
99.95% <= 18 milliseconds
99.97% <= 19 milliseconds
100.00% <= 19 milliseconds
50761.42 requests per second

====== GET ======
  100000 requests completed in 1.92 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

97.49% <= 1 milliseconds
99.95% <= 16 milliseconds
100.00% <= 16 milliseconds
52110.47 requests per second

​ 在上面的測試結果中,我們關注GET結果最後一行 52110.47 requests per second ,即每秒GET命令處理52110.47個請求,即QPS5.2萬。但這裏的數據都只是理想的測試數據,測出來的QPS不能代表實際生產的處理能力。

1.1.2 TPS、QPS、RT

​ 在描述系統的高併發能力時,吞吐量(TPS)、QPS、響應時間(RT)經常提到,我們先了解這些概念:

  • 響應時間RT
  • 吞吐量TPS
  • 每秒查詢率QPS

**響應時間(RT) **

​ 響應時間是指系統對請求作出響應的時間。

​ 直觀上看,這個指標與人對軟件性能的主觀感受是非常一致的,因爲它完整地記錄了整個計算機系統處理請求的時間。由於一個系統通常會提供許多功能,而不同功能的業務邏輯也千差萬別,因而不同功能的響應時間也不盡相同。

​ 在討論一個系統的響應時間時,通常是指該系統所有功能的平均時間或者所有功能的最大響應時間

吞吐量TPS

​ 吞吐量是指系統在單位時間內處理請求的數量。

​ 對於一個多用戶的系統,如果只有一個用戶使用時系統的平均響應時間是t,當有你n個用戶使用時,每個用戶看到的響應時間通常並不是n×t,而往往比n×t小很多。這是因爲在處理單個請求時,在每個時間點都可能有許多資源被閒置,當處理多個請求時,如果資源配置合理,每個用戶看到的平均響應時間並不隨用戶數的增加而線性增加。

​ 實際上,不同系統的平均響應時間隨用戶數增加而增長的速度也不大相同,這也是採用吞吐量來度量併發系統的性能的主要原因。一般而言,吞吐量是一個比較通用的指標,兩個具有不同用戶數和用戶使用模式的系統,如果其最大吞吐量基本一致,則可以判斷兩個系統的處理能力基本一致。

每秒查詢率QPS

​ 每秒查詢率QPS是對一個特定的查詢服務器在規定時間內所處理流量多少的衡量標準,在互聯網中,經常用每秒查詢率來衡量服務器的性能。對應fetches/sec,即每秒的響應請求數,也即是最大吞吐能力。

1.1.3 測算Redis性能

​ 在實際生產中,我們需要關心在應用場景中,redis能夠處理的QPS是多少。我們需要估計生產的報文大小,使用benchmark工具指定-d數據塊大小來模擬:

./redis-benchmark -t get -n 100000 -c 100 -d 2048

測試結果:

====== GET ======
  100000 requests completed in 2.33 seconds
  100 parallel clients
  2048 bytes payload
  keep alive: 1

0.00% <= 1 milliseconds
51.74% <= 2 milliseconds
99.16% <= 3 milliseconds
99.57% <= 4 milliseconds
99.71% <= 5 milliseconds
99.83% <= 7 milliseconds
99.83% <= 8 milliseconds
99.86% <= 15 milliseconds
99.86% <= 16 milliseconds
99.90% <= 20 milliseconds
99.93% <= 21 milliseconds
99.94% <= 26 milliseconds
99.96% <= 29 milliseconds
99.97% <= 36 milliseconds
99.99% <= 37 milliseconds
100.00% <= 37 milliseconds
42955.32 requests per second

測得的QPS是4.2萬

我們也可以使用redis客戶端登陸到redis服務中,執行info命令查看redis的其他信息,執行命令:

# 使用Redis客戶端
./redis-cli
# 在客戶端中執行info命令
127.0.0.1:6379> info

查看結果(摘取部分結果):

connected_clients:101 #redis連接數

used_memory:8367424	# Redis 分配的內存總量 
used_memory_human:7.98M
used_memory_rss:11595776 # Redis 分配的內存總量(包括內存碎片) 
used_memory_rss_human:11.06M
used_memory_peak:8367424
used_memory_peak_human:7.98M #Redis所用內存的高峯值
used_memory_peak_perc:100.48%

1.2 Redis讀寫分離

​ 在前面我們已經測試過,如果只有一臺服務器,QPS是4.2萬,而在大型網站中,可能要求更高的QPS,很明顯,一臺服務器就不能滿足需要了。

Redis在知乎的規模:
機器內存總量約 70TB,實際使用內存約 40TB。
平均每秒處理約 1500 萬次請求,峯值每秒約 2000 萬次請求。 #QPS 2000萬
每天處理約 1 萬億餘次請求。
單集羣每秒處理最高每秒約 400 萬次請求。

​ 我們可以對讀寫能力擴展,採用讀寫分離的方式解決性能瓶頸。運行新的服務器(稱爲從服務器),讓從服務器與主服務器進行連接,然後主服務器發送數據副本,從服務器通過網絡根據主服務器的數據副本進行準實時更新(具體的更新速度取決於網絡帶寬)。

​ 這樣我們就有額外的從服務器處理讀請求,通過將讀請求分散到不同的服務器上面進行處理, 用戶可以從新添加的從服務器上獲得額外的讀查詢處理能力。

​ redis已經發現了這個讀寫分離場景特別普遍,自身集成了讀寫分離供用戶使用。我們只需在redis的配置文件里面加上一條,slaveof host port語句配置即可,我們現在開始配置主從環境。

執行命令:

# 複製redis
cd /usr/local/redis/bin
  	#  cp bin redis01 -R   這個語句寫錯了
cp -R bin/redis01
# 修改配置
vi redis.conf
修改 port 爲 6380
添加 slaveof 192.168.200.129 6379
# 清空持久化文件
rm -rf dump.rdb
rm -rf appendonly.aof
# 啓動
./redis-server redis.conf 

​ 分別連接主庫(6379)和從庫(6380),測試發現主庫的寫操作,從庫立刻就能看到相同的數據。但是在從庫進行寫操作,提示 READONLY You can't write against a read only slave 不能寫數據到從庫。

​ 現在我們就可以通過這種方式配置多個從庫讀操作,主庫進行寫操作,實現讀寫分離,以提高redis的QPS。

1.3 Redis同步原理

​ 通過上面的例子,我們知道redis的主從複製,主服務器執行寫操作命令,從服務器會通過主服務器的數據的變化,同步數據到從服務器。但是如果主服務器下線,從服務器無法連接主服務器,那麼數據同步該如何拿到不能連接主服務器這段時間的命令呢?

​ 主從複製中的主從服務器雙方的數據庫將保存相同的數據,概念上將這種現象稱作數據庫狀態一致

​ Redis數據庫持久化有兩種方式:RDB全量持久化和AOF增量持久化。

數據同步步驟:

  1. redis2.8版本之前使用舊版複製功能SYNC,這是一個非常耗費資源的操作

    • 主服務器需要執行BGSAVE命令來生成RDB文件,這個生成操作會耗費主服務器大量量的的CPU、內存和磁盤讀寫資源。
    • 主服務器將RDB文件發送給從服務器,這個發送操作會耗費主從服務器大量的網絡帶寬和流量,並對主服務器響應命令
    • 請求的時間產生影響:接收到RDB文件的從服務器在載入文件的過程是阻塞的,無法處理命令請求
  2. 2.8之後使用PSYNC,具有完整重同步和部分重同步兩種模式部分重同步兩種模式。

第一種完整重同步:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-219PtX0g-1591364920210)(assets/1560235618330.png)]

​ 第二種部分重同步:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-DX9ttGsu-1591364920215)(assets/1560236056210.png)]

​ 功能由以下三個部分構成:

​ 1) 主服務的複製偏移量(replication offset)和從服務器的複製偏移量量。

​ 2) 主服務器的複製積壓緩衝區(replication backlog),默認大小爲1M。

​ 3) 服務器的運行ID,用於存儲服務器標識:

​ 如果從服務器斷線重新連接,獲取主服務器的運行ID與重接後的主服務器運行ID進行對比,

​ 判斷是不是原來的主服務器,從而決定是執行部分重同步,還是執行完整重同步。

2. Redis高可用Sentinel

2.1 高可用介紹

​ 高可用是分佈式系統架構設計中必須考慮的因素之一,它是通過架構設計減少系統不能提供服務的時間。保證高可用通常遵循下面幾點:

  1. 單點是系統高可用的大敵,應該儘量在系統設計的過程中避免單點。
  2. 通過架構設計而保證系統高可用的,其核心準則是:冗餘。
  3. 每次出現故障需要人工介入恢復,會增加系統不可用的時間,實現自動故障轉移。

我們現在已經給Redis實現了主從複製,可將主節點數據同步給從節點,從節點此時有兩個作用:

  1. 從節點擴展主節點的讀能力,分擔主節點讀壓力。
  2. 一旦主節點宕機,從節點作爲主節點的備份可以隨時頂上來。(高可用)

2.2 手動主從切換

2.2.1 環境準備

​ 一旦主節點宕機,就需要把從節點晉升成主節點,同時需要修改應用方的主節點地址,還需要命令所有從節點去複製新的主節點,整個過程需要人工操作。我們再準備一個從服務,依次執行以下命令:

cd /usr/local/redis/

cp redis01/ redis02 -R

vi redis.conf
修改 port 爲 6381

./redis-server redis.conf 

分別進入一主兩從服務,執行info命令,看到服務的狀態:

主服務器:

# Replication
role:master
connected_slaves:2
slave0:ip=192.168.200.129,port=6380,state=online,offset=14414,lag=1
slave1:ip=192.168.200.129,port=6381,state=online,offset=14414,lag=1

從服務器:

# Replication
role:slave
master_host:192.168.200.129
master_port:6379
master_link_status:up

2.2.2 主從切換

主服務下線

​ 登錄6379端口號的主服務,並執行shutdown命令,關閉這個主redis,進入6381從服務執行info命令,我們可以看到從服務的信息變爲:

# Replication
role:slave
master_host:192.168.200.129
master_port:6379
master_link_status:down

可以看到主的狀態由原來的up變爲down,說明主服務下線了。

主從切換

現在可以把6380升級爲主服務,執行命令:

slaveof no one

修改6381對應的主服務器,執行命令:

slaveof 192.168.200.129 6380

再次執行info命令,可以看到主從服務器都切換成功。現在變成了一主一從,對外是正常的。

2.3 Sentinel實現高可用

2.3.1 Sentinel介紹

​ 在前面的例子中,主節點宕機,需要把從節點晉升成主節點,同時需要修改應用方的主節點地址,還需要命令所有從節點去複製新的主節點。

​ 這整個過程都是人工,費事費力,還會造成一段時間內服務不可用,而且需要人一直都在。這不是一種好的方式,更多時候,我們優先考慮Sentinel(哨兵)。

Sentinel工作模式:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-WxGkVV4b-1591364920221)(assets/1560267330173.png)]

2.3.2 Sentinel使用

2.3.2.1 安裝

Sentinel在redis的安裝包中有,我們直接使用就可以了,但是先需要修改配置文件,執行命令:

cd /usr/local/redis/

# 複製sentinel配置文件
cp /root/redis-4.0.14/sentinel.conf sentinel01.conf

# 修改配置文件:
vi sentinel01.conf

在sentinel01.conf配置文件中添加:

# 外部可以訪問
bind 0.0.0.0
sentinel monitor mymaster 192.168.200.128 6379 1
sentinel down-after-milliseconds mymaster 10000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1

注意:如果有sentinel monitor mymaster 192.168.200.129 6379 2配置,則註釋掉。

參數說明:

  • sentinel monitor mymaster 192.168.200.129 6379 1

    mymaster 主節點名,可以任意起名,但必須和後面的配置保持一致。

    192.168.200.129 6379 主節點連接地址。

    1 將主服務器判斷爲失效需要投票,這裏設置至少需要 1個 Sentinel 同意。

  • sentinel down-after-milliseconds mymaster 10000

    設置Sentinel認爲服務器已經斷線所需的毫秒數。

  • sentinel failover-timeout mymaster 60000

    設置failover(故障轉移)的過期時間。當failover開始後,在此時間內仍然沒有觸發任何failoer操作,當前
    sentinel 會認爲此次failoer失敗。

  • sentinel parallel-syncs mymaster 1

    設置在執行故障轉移時, 最多可以有多少個從服務器同時對新的主服務器進行同步, 這個數字越小,表示同時進行同步的從服務器越少,那麼完成故障轉移所需的時間就越長。

    如果從服務器允許使用過期數據集, 那麼我們可能不希望所有從服務器都在同一時間向新的主服務器發送同步請求, 因爲從服務器在載入主服務器發來的RDB文件時, 會造成從服務器在一段時間內不能處理命令請求。如果全部從服務器一起對新的主服務器進行同步, 那麼就可能會造成所有從服務器在短時間內全部不可用的情況出現。

配置文件修改後,執行以下命令,啓動sentinel:

/root/redis-4.0.14/src/redis-sentinel sentinel01.conf

效果如下:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Rk2cdJlI-1591364920226)(assets/1560273574184.png)]

可以看到,6379是主服務,6380和6381是從服務。

2.3.2.2 測試

我們在6379執行shutdown,關閉主服務,Sentinel提示如下:

+sdown master mymaster 192.168.200.129 6379	#主節點宕機
+odown master mymaster 192.168.200.129 6379 #quorum 1/1 
+new-epoch 1
+try-failover master mymaster 192.168.200.129 6379 #嘗試故障轉移
+vote-for-leader 00a6933e0cfa2b1bf0c3aab0d6b7a1a6455832ec 1 #選舉領導
+elected-leader master mymaster 192.168.200.129 6379
+failover-state-select-slave master mymaster 192.168.200.129 6379 #故障轉移選擇從服務
+selected-slave slave 192.168.200.129:6380 192.168.200.129 6380 @ mymaster 192.168.200.129 6379
#故障轉移狀態發送 發送到6380
+failover-state-send-slaveof-noone slave 192.168.200.129:6380 192.168.200.129 6380 @ mymaster 192.168.200.129 6379
+failover-state-wait-promotion slave 192.168.200.129:6380 192.168.200.129 6380 @ mymaster 192.168.200.129 6379
+promoted-slave slave 192.168.200.129:6380 192.168.200.129 6380 @ mymaster 192.168.200.129 6379
+failover-state-reconf-slaves master mymaster 192.168.200.129 6379
+slave-reconf-sent slave 192.168.200.129:6381 192.168.200.129 6381 @ mymaster 192.168.200.129 6379
+slave-reconf-inprog slave 192.168.200.129:6381 192.168.200.129 6381 @ mymaster 192.168.200.129 6379
+slave-reconf-done slave 192.168.200.129:6381 192.168.200.129 6381 @ mymaster 192.168.200.129 6379
+failover-end master mymaster 192.168.200.129 6379 #故障轉移結束,原來的主服務是6379
+switch-master mymaster 192.168.200.129 6379 192.168.200.129 6380 #轉換主服務,由原來的6379轉爲現在的6380
+slave slave 192.168.200.129:6381 192.168.200.129 6381 @ mymaster 192.168.200.129 6380
+slave slave 192.168.200.129:6379 192.168.200.129 6379 @ mymaster 192.168.200.129 6380
+sdown slave 192.168.200.129:6379 192.168.200.129 6379 @ mymaster 192.168.200.129 6380

根據提示信息,我們可以看到,6379故障轉移到了6380,通過投票選擇6380爲新的主服務器。

在6380執行info

# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=80531,lag=1

在6381執行info

# Replication
role:slave
master_host:127.0.0.1
master_port:6380
master_link_status:up

故障轉移如下圖:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-PnDO2xEE-1591364920233)(assets/1560267675340.png)]

2.3.3.3 原理

​ Sentinel主要是監控服務器的狀態,並決定是否進行故障轉移。如何進行故障轉移在前面的部分已經給大家演示過人工的操作,那麼Sentinel是如何判斷服務是否下線呢,主要分爲主觀下線和客觀下線:

  • 主觀下線:

    • 概念:

      主觀下線(Subjectively Down, 簡稱 SDOWN)指的是單個 Sentinel 實例對服務器做出的下線判斷

    • 特點:

      如果一個服務器沒有在 master-down-after-milliseconds 選項所指定的時間內, 對向它發送 PING 命令的 Sentinel 返回一個有效回覆, 那麼 Sentinel 就會將這個服務器標記爲主觀下線

  • 客觀下線

    • 概念:

      多個 Sentinel 實例在對同一個服務器做出 SDOWN 判斷, 並且通過 SENTINEL is-master-down-by-addr 命令互相交流之後, 得出的服務器下線判斷ODOWN。 (一個Sentinel 可以通過向另一個 Sentinel 發送命令來詢問對方是否認爲給定的服務器已下線)

    • 特點:

      從主觀下線狀態切換到客觀下線狀態並沒有使用嚴格的法定人數算法(strong quorum algorithm),而是使用了流言傳播(Gossip): 如果Sentinel在給定的時間範圍內, 從其他Sentinel那里接收到了足夠數量的主服務器下線報告, 那麼 Sentinel 就會將主服務器的狀態從主觀下線改變爲客觀下線。

    • 注意點:

      客觀下線條件只適用於主服務器,對於其他類型的 Redis 實例, Sentinel 在將它們判斷爲下線前不不需要進行協商, 所以從服務器或者其他 Sentinel 不會達到客觀下線條件。 只要一個 Sentinel 發現某個主服務器進入了客觀下線狀態, 這個Sentinel就可能會被其他 Sentinel 推選出,並對失效的主服務器執行自動故障遷移操作。

2.3.3.4 小結

Sentinel三大工作任務

  • 監控(Monitoring): Sentinel 會不斷地檢查你的主服務器和從服務器是否運作正常。

  • 提醒(Notification): 當被監控的某個 Redis 服務器出現問題時, Sentinel 可以通過API向管理員或者其他應用程序發送通知。

  • 自動故障遷移(Automatic failover): 當一個主服務器不能正常工作時,Sentinel會開始一次自動故障轉移操作, 它會將失效主服務器的其中一個從服務器升級爲新的主服務器, 並讓失效主服務器的其他從服務器改爲複製新的主服務器。

    當客戶端試圖連接失效的主服務器時, 集羣也會向客戶端返回新主服務器的地址,使得集羣可以使用新主服務器代替失效服務器。

互聯網冷備和熱備

  • 冷備

    • 概念:

      冷備發生在數據庫已經正常關閉的情況下,當正常關閉時會提供給我們一個完整的數據庫

    • 優點:

      • 非常快速的備份方法(只需拷文件)
      • 低度維護,高度安全
    • 缺點:

      • 單獨使用時,只能提供“某一時間點上”的恢復
      • 在實施備份的全過程中,數據庫必須要作備份而不能作其他工作。也就是說,在冷備份過程中,數據庫必須是關閉狀態
  • 熱備

    • 概念:

      熱備份是在數據庫運行的情況下,採用歸檔模式(archivelog mode)方式備份數據庫的方法

    • 優點:

      • 備份的時間短
      • 備份時數據庫仍可使用
      • 可達到秒級恢復
    • 缺點:

      • 若熱備份不成功,所得結果不可用於時間點的恢復
      • 難於維護,要非常仔細小心

2.3.3 Sentinel整合SpringBoot

設置Redis密碼

​ Redis 4.0.14默認開啓保護模式protected-mode yes,我們要正常訪問需要先設置redis的訪問密碼,然後纔可以進行測試,在所有的redis配置文件redis.conf中,添加如下配置:

# 設置密碼
requirepass 123456

# 設置訪問主服務器密碼
masterauth 123456

在Sentinel哨兵的配置文件sentinel01.conf中添加以下設置:

sentinel auth-pass mymaster 123456

Redis命令行登錄:

./redis-cli -h 192.168.200.129 -p 6381 -a 123456

其中-a 就是設置訪問密碼

整合SpringBoot

創建maven工程並在pom.xml添加以下依賴:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-parent</artifactId>
    <version>2.0.1.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
</dependencies>

編寫application.yml配置文件:

spring:
  redis:
    password: 123456
    sentinel:
      master: mymaster
      nodes: 192.168.200.129:26379

編寫啓動類:

@SpringBootApplication
public class RedisApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisApplication.class, args);
    }
}

編寫測試類:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = RedisApplication.class)
public class RedisTest {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Test
    public void test() {
        redisTemplate.opsForValue().set("test", "redis");
        redisTemplate.opsForValue().get("test");
    }
}

3. Redis內置集羣

3.1 搭建集羣

3.1.1 準備redis節點

爲了保證可以進行投票,需要至少3個主節點。

每個主節點都需要至少一個從節點,所以需要至少3個從節點。

一共需要6臺redis服務器,我們這裏使用6個redis實例,端口號爲7001~7006

先準備一個乾淨的redis環境,複製原來的bin文件夾,清理後作爲第一個redis節點,具體命令如下:

# 進入redis安裝目錄
cd /usr/local/redis
# 複製redis
mkdir cluster
cp -R bin/ cluster/node1
# 刪除持久化文件
cd cluster/node1
rm -rf dump.rdb
rm -rf appendonly.aof
# 刪除原來的配置文件
rm -rf redis.conf
# 複製新的配置文件
cp /root/redis-4.0.14/redis.conf ./
# 修改配置文件
vi redis.conf

集羣環境redis節點的配置文件如下:

# 不能設置密碼,否則集羣啓動時會連接不上
# Redis服務器可以跨網絡訪問
bind 0.0.0.0
# 修改端口號
port 7001
# Redis後臺啓動
daemonize yes
# 開啓aof持久化
appendonly yes
# 開啓集羣
cluster-enabled yes
# 集羣的配置 配置文件首次啓動自動生成
cluster-config-file nodes.conf
# 請求超時
cluster-node-timeout 5000

第一個redis節點node1準備好之後,再複製5份,

cp -R node1/ node2

修改六個節點的端口號爲7001~7006,修改redis.conf配置文件即可

編寫啓動節點的腳本:

vi start-all.sh

內容爲:

cd node1
./redis-server redis.conf
cd ..
cd node2
./redis-server redis.conf
cd ..
cd node3
./redis-server redis.conf
cd ..
cd node4
./redis-server redis.conf
cd ..
cd node5
./redis-server redis.conf
cd ..
cd node6
./redis-server redis.conf
cd ..

設置腳本的權限,並啓動:

chmod 744 start-all.sh
./start-all.sh

使用命令 ps -ef | grep redis 查看效果如下:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-CJtA3Vy6-1591364920237)(assets/1560310365027.png)]

3.1.2 啓動redis集羣

redis集羣的管理工具使用的是ruby腳本語言,安裝集羣需要ruby環境,先安裝ruby環境:

# 安裝ruby
yum -y install ruby ruby-devel rubygems rpm-build

# 升級ruby版本,redis4.0.14集羣環境需要2.2.2以上的ruby版本
yum install centos-release-scl-rh
yum install rh-ruby23  -y
scl enable rh-ruby23 bash

# 查看ruby版本
ruby -v

下載符合環境要求的gem,下載地址如下:

https://rubygems.org/gems/redis/versions/4.1.0

課程資料中已經提供了redis-4.1.0.gem,直接上傳安裝即可,安裝命令:

gem install redis-4.1.0.gem

進入redis安裝目錄,使用redis自帶的集羣管理腳本,執行命令:

# 進入redis安裝包
cd /root/redis-4.0.14/src/
# 查看集羣管理腳本
ll *.rb
# 使用集羣管理腳本啓動集羣
./redis-trib.rb create --replicas 1 192.168.200.129:7001 192.168.200.129:7002 \
192.168.200.129:7003 192.168.200.129:7004 192.168.200.129:7005 192.168.200.129:7006

效果如下:

>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
192.168.200.129:7001
192.168.200.129:7002
192.168.200.129:7003
Adding replica 192.168.200.129:7005 to 192.168.200.129:7001
Adding replica 192.168.200.129:7006 to 192.168.200.129:7002
Adding replica 192.168.200.129:7004 to 192.168.200.129:7003
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: f0094f14b59c023acd38098336e2adcd3d434497 192.168.200.129:7001
   slots:0-5460 (5461 slots) master
M: 0eba44418d7e88f4d819f89f90da2e6e0be9c680 192.168.200.129:7002
   slots:5461-10922 (5462 slots) master
M: ac16c5545d9b099348085ad8b3253145912ee985 192.168.200.129:7003
   slots:10923-16383 (5461 slots) master
S: edc7a799e1cfd75e4d80767958930d86516ffc9b 192.168.200.129:7004
   replicates ac16c5545d9b099348085ad8b3253145912ee985
S: cbd415973b3e85d6f3ad967441f6bcb5b7da506a 192.168.200.129:7005
   replicates f0094f14b59c023acd38098336e2adcd3d434497
S: 40fdde45b16e1ac85c8a4c84db75b43978d1e4d2 192.168.200.129:7006
   replicates 0eba44418d7e88f4d819f89f90da2e6e0be9c680
Can I set the above configuration? (type 'yes' to accept): yes #注意選擇爲yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join..
>>> Performing Cluster Check (using node 192.168.200.129:7001)
M: f0094f14b59c023acd38098336e2adcd3d434497 192.168.200.129:7001
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
M: ac16c5545d9b099348085ad8b3253145912ee985 192.168.200.129:7003
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: cbd415973b3e85d6f3ad967441f6bcb5b7da506a 192.168.200.129:7005
   slots: (0 slots) slave
   replicates f0094f14b59c023acd38098336e2adcd3d434497
S: 40fdde45b16e1ac85c8a4c84db75b43978d1e4d2 192.168.200.129:7006
   slots: (0 slots) slave
   replicates 0eba44418d7e88f4d819f89f90da2e6e0be9c680
M: 0eba44418d7e88f4d819f89f90da2e6e0be9c680 192.168.200.129:7002
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
S: edc7a799e1cfd75e4d80767958930d86516ffc9b 192.168.200.129:7004
   slots: (0 slots) slave
   replicates ac16c5545d9b099348085ad8b3253145912ee985
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

3.1.3 使用redis集羣

命令行使用

使用redis的客戶端連接redis集羣,命令如下:

./redis-cli -h 192.168.200.129 -p 7001 -c

其中-c 一定要加,這個是redis集羣連接時,進行節點跳轉的參數

3.2 集羣原理

3.2.1 集羣架構圖

在這裏插入圖片描述

架構特點:

  1. 所有的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬。
  2. 節點的fail是通過集羣中超過半數的master節點檢測失效時才生效。
  3. 客戶端與redis節點直連,不需要連接集羣所有節點,只需要連接集羣中任意可用節點即可。
  4. 集羣把所有的物理節點映射到[0-16383]slot上,cluster 負責維護node<>slot<>key關係

####3.2.2 集羣的數據分配

​ 在前面的特點中,最後一個node<>slot<>key關係是什麼意思呢?這裏是說數據是如何放到集羣的節點中。

​ Redis 集羣有16384個哈希槽,每個key通過CRC16校驗後對16384取模來決定放置哪個槽.集羣的每個節點負責一部分哈希槽。可以使用命令查看集羣信息:

./redis-cli -p 7001 cluster nodes | grep master

結果:

192.168.200.129:7003@17003 master - 0 1560315648000 3 connected 10923-16383
192.168.200.129:7001@17001 myself,master - 0 1560315647000 1 connected 0-5460
192.168.200.129:7002@17002 master - 0 1560315648324 2 connected 5461-10922

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Hd0DhCwK-1591364920246)(assets/1560317522125.png)]

哈希槽的使用:

  1. 集羣搭建的時候分配哈希槽到節點上
  2. 使用集羣的時候,先對數據key進行CRC16的計算
  3. 對計算的結果求16384的餘數,得到的數字範圍是0~16383
  4. 根據餘數找到對應的節點(餘數對應的哈希槽在哪個節點)
  5. 跳轉到對應的節點,執行命令

​ 這種結構很容易添加或者刪除節點。比如果我想新添加節點node4, 我需要從節點 node1, node2, node3中得部分槽到node4上. 如果我想移除節點node1,需要將node1中的槽移到node2和node3節點上,然後將沒有任何槽的node1節點從集羣中移除即可。

​ 由於從一個節點將哈希槽移動到另一個節點並不會停止服務,所以無論添加刪除或者改變某個節點的哈希槽的數量都不不會造成集羣不可用的狀態。

Redis 集羣的主從複製模型

​ 爲了使部分節點失敗或者大部分節點無法通信的情況下集羣仍然可用,所以集羣使用了主從複製模型,每個節點都會有一個或多個複製品。

​ 在我們例子中具有 node1, node2, node3三個節點的集羣,在沒有複製模型的情況下,如果節點node2失敗了,那麼整個集羣就會以爲缺少5461-10922這個範圍的槽而不可用。Redis集羣做主從備份解決了了這個問題。

Redis一致性保證

​ 主節點對命令的複製工作發生在返回命令回覆之後, 因爲如果主節點每次處理命令請求都需要等待複製操作完成的話, 那麼主節點處理命令請求的速度將極大地降低 。

​ 當然現在這種情況也是有問題的,當主節點執行完命令,返回命令回覆之後宕機了,並沒有完成複製操作,這個時候就有主從的數據不一致的問題。

​ redis這樣設計,就是在性能和一致性之間做出的權衡。

3.3 集羣維護

​ 很多時候,我們需要對集羣進行維護,調整數據的存儲,其實就是對slot哈希槽和節點的調整。Redis內置的集羣支持動態調整,可以在集羣不停機的情況下,改變slot、添加或刪除節點。

3.3.1 分片重哈希

Redis集羣節點分片重哈希,調整哈希槽和節點的關係,執行以下命令:

# 分片重哈希,可以連接任意節點
./redis-trib.rb reshard 192.168.200.129:7001

# 執行命令,提示需要移動多少個hash槽,直接輸入要移動的hash槽數量即可,例如我們移動1000個
How many slots do you want to move (from 1 to 16384)?1000

# 提示接受的節點id是多少,我們使用7002接受1000個hash槽,填寫對應節點的id
What is the receiving node ID? 0eba44418d7e88f4d819f89f90da2e6e0be9c680

# 提示移出hash槽的節點id,all表示所有節點都移出插槽,也可以填寫單獨節點id,最後鍵入done
# 我們測試填寫all
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1:all

# 最後,要我們確認是否確認這樣進行重哈希,填寫yes
Do you want to proceed with the proposed reshard plan (yes/no)? yes

查看結果:

# 執行命令,查看hash槽結果
./redis-cli -p 7001 cluster nodes
# 執行結果
ac16c5545d9b099348085ad8b3253145912ee985 192.168.200.129:7003@17003 slave edc7a799e1cfd75e4d80767958930d86516ffc9b 0 1560332491000 7 connected
f0094f14b59c023acd38098336e2adcd3d434497 192.168.200.129:7001@17001 myself,master - 0 1560332490000 1 connected 500-5460
cbd415973b3e85d6f3ad967441f6bcb5b7da506a 192.168.200.129:7005@17005 slave f0094f14b59c023acd38098336e2adcd3d434497 0 1560332491000 5 connected
40fdde45b16e1ac85c8a4c84db75b43978d1e4d2 192.168.200.129:7006@17006 slave 0eba44418d7e88f4d819f89f90da2e6e0be9c680 0 1560332491608 8 connected
0eba44418d7e88f4d819f89f90da2e6e0be9c680 192.168.200.129:7002@17002 master - 0 1560332491508 8 connected 0-499 5461-11422
edc7a799e1cfd75e4d80767958930d86516ffc9b 192.168.200.129:7004@17004 master - 0 1560332491000 7 connected 11423-16383

我們可以看到7001的哈希槽500-5460,而7004的哈希槽11423-16383,都少了500個哈希槽

而7002的哈希槽0-499 5461-11422,比原來增加了1000個哈希槽

3.3.2 移除節點

移除節點命令的第一個參數是任意節點的地址,第二個節點是想要移除的節點id:

./redis-trib.rb del-node 192.168.200.129:7001 cbd415973b3e85d6f3ad967441f6bcb5b7da506a
>>> Removing node cbd415973b3e85d6f3ad967441f6bcb5b7da506a from cluster 192.168.200.129:7001
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
  • 移除主節點:

    • 在移除主節點前,需要確保這個主節點是空的。如果不是空的,需要將這個節點的數據重新分片到其他主節點上
    • 替代移除主節點的方法是手動執行故障恢復,被移除的主節點會作爲一個從節點存在,不過這種情況下不會減少集羣節點的數量,也需要重新分片數據
  • 移除從節點,直接移除成功

3.3.3 添加節點

添加節點前需要保證新的節點是一個乾淨的,空的redis,主要就是要刪除持久化文件和節點配置文件:

rm -rf appendonly.aof 
rm -rf dump.rdb 
rm -rf nodes.conf 

添加新的主節點

./redis-trib.rb add-node 192.168.200.129:7005 192.168.200.129:7001

添加的新節點默認是沒有哈希槽的,需要手動分配哈希槽

添加新的從節點

./redis-trib.rb add-node --slave 192.168.200.129:7005 192.168.200.129:7001

添加的新的從節點,集羣默認自動分配對應的主節點。

3.4 整合SpringBoot

使用之前哨兵整合SpringBoot的例子,把配置文件修改爲如下內容:

spring:
  redis:
    cluster:
      nodes: 192.168.200.129:7001,192.168.200.129:7002,192.168.200.129:7003,192.168.200.129:7004,192.168.200.129:7005,192.168.200.129:7006

編寫測試方法:

@Test
public void test() {
    redisTemplate.opsForValue().set("test", "redis");
    String test = redisTemplate.opsForValue().get("test");
    System.out.println(test);
}

4. Redis集羣擴展

4.1 Redis集羣現狀

​ 我們已經學完了Redis內置集羣,是不是這一種方式就足夠我們使用了呢?在這裏,我們要對redis集羣現在使用的情況進行分析。

  1. 集羣使用現狀

    Redis Cluster內置集羣,在Redis3.0才推出的實現方案。在3.0之前是沒有這個內置集羣的。

    但是在3.0之前,有很多公司都有自己的一套Redis高可用集羣方案。雖然現在有內置集羣,但是因爲歷史原因,很多公司都沒有切換到內置集羣方案,而其原理就是集羣方案的核心,這也是很多大廠爲什麼要問原理的的原因。

  2. 網絡通信問題

    Redis Cluster是無中心節點的集羣架構,依靠Gossip協議(謠言傳播)協同自動化修復集羣的狀態。

    但Gossip有消息延時和消息冗餘的問題,在集羣節點數量過多的時候,節點之間需要不斷進行PING/PANG通訊,不必須要的流量佔用了大量的網絡資源。雖然Redis4.0對此進行了優化,但這個問題仍然存在。

  3. 數據遷移問題

    Redis Cluster可以進行節點的動態擴容縮容,在擴縮容的時候,就需要進行數據遷移。

    而Redis 爲了保證遷移的一致性, 遷移所有操作都是同步操作,執行遷移時,兩端的 Redis 均會進入時長不等的 阻塞狀態。對於小 Key,該時間可以忽略不計,但如果一旦 Key 的內存使用過大,嚴重的時候會接觸發集羣內的故障轉移,造成不必要的切換。

以上原因說明只是學習Redis Cluster並不夠,我們還需要學習新的集羣方案。

Gossip 的缺陷
- 消息的延遲
	由於 Gossip 協議中,節點只會隨機向少數幾個節點發送消息,消息最終是通過多個輪次的散播而到達全網的。
	因此使用 Gossip 協議會造成不可避免的消息延遲。不適合用在對實時性要求較高的場景下。
- 消息冗餘
	Gossip 協議規定,節點會定期隨機選擇周圍節點發送消息,而收到消息的節點也會重複該步驟。
	因此存在消息重複發送給同一節點的情況,造成了消息的冗餘,同時也增加了收到消息的節點的處理壓力。
	而且,由於是定期發送而且不反饋,因此即使節點收到了消息,還是會反覆收到重複消息,加重了消息的冗餘。

4.2 一致性哈希算法

4.2.1 分片介紹

​ 在前面我們講了內置的集羣因爲一些原因,在節點數量過多的時候,並不能滿足我們的要求,哪還有什麼新的集羣方案呢?我們在這裏講解使用twemproxy實現hash分片的Redis集羣方案,這個方案也是知乎2000萬QPS場景所使用的方案。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Np5vSP18-1591364920250)(assets/1560352858458.png)]

​ 上圖我們看到twemproxy主要的角色是代理服務器的作用,是對數據庫進行分片操作。twemproxy的分片保證需要存儲的數據散列存放在集羣的節點上,儘量做到平均分佈。如何實現呢,這裏就涉及到一致性哈希算法,這個算法是分佈式系統中常用的算法。

4.2.2 傳統哈希方案

​ 傳統方案是使用對象的哈希值,對節點個數取模,再映射到相應編號的節點,這種方案在節點個數變動時,絕大多數對象的映射關係會失效而需要遷移。

Hash,一般翻譯做散列、雜湊,或音譯爲哈希,是把任意長度的輸入,通過散列算法變換成固定長度的輸出,該輸出就是散列值。散列值的空間通常遠小於輸入的空間,不同的輸入可能會散列成相同的輸出,所以不可能從散列值來確定唯一的輸入值。
簡單的說就是一種將任意長度的消息壓縮到某一固定長度的消息摘要的函數。

正常有3個節點,取3的模,分配數據,效果如下圖:在這裏插入圖片描述

如果節點掛了一個,那麼久需要進行數據遷移,把數據分配到剩下的兩個節點上,如下圖:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-uAylFXpi-1591364920256)(assets/1560354377975.png)]

​ 可以看到原本存在Master1上的key3,需要遷移到Master3上,而Master1始終是正常的,這就造成了沒有必要的數據遷移,浪費資源,所以我們需要採取另一種方式,一致性哈希算法。

4.2.3 一致性哈希算法

​ 一致性哈希算法(Consistent Hashing Algorithm)是一種分佈式算法,常用於負載均衡。twemproxy也選擇這種算法,解決將key-value均勻分配到衆多 server上的問題。它可以取代傳統的取模操作,解決了取模操作應對增刪 Server的問題。

步驟

  1. 先用hash算法將對應的節點ip哈希到一個具有232次方個桶的空間中,即0~(232)-1的數字空間。現在我們可以將這些數字頭尾相連,連接成一個閉合的環形:

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-KXXNNFQp-1591364920260)(assets/1560354817421.png)]

  2. 當用戶在客戶端進行請求時候,首先根據key計算路由hash值,然後看hash值落到了hash環的哪個地方,根據hash值在hash環上的位置順時針找距離最近的節點:

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-v55fN2ow-1591364920263)(assets/1560355074779.png)]

  3. 當新增節點的時候,和之前的做法一樣,只需要把受到影響的數據遷移到新節點即可

    新增Master4節點:

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2LlsraBD-1591364920268)(assets/1560355317725.png)]

  4. 當移除節點的時候,和之前的做法一樣,把移除節點的數據,遷移到順時針距離最近的節點

    移除Master2節點:

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-KKz5zrRw-1591364920271)(assets/1560355443758.png)]

​ 從上面的步驟可以看出,當節點個數變動時,使用哈希一致性映射關係失效的對象非常少,遷移成本也非常小。那麼判斷一個哈希算法好壞的指標有哪些呢?以下列出了4個指標:

  • 平衡性(Balance):

    ​ 平衡性是指哈希的結果能夠儘可能分散到不同的緩存服務器上去,這樣可以使得所有的服務器得到利用。一致性hash可以做到每個服務器都進行處理理請求,但是不能保證每個服務器處理的請求的數量大致相同

  • 單調性(Monotonicity):

    ​ 單調性是指如果已經有一些請求通過哈希分派到了相應的服務器進行處理,又有新的服務器加入到系統中時候,哈希的結果應保證原有的請求可以被映射到原有的或者新的服務器中去,而不會被映射到原來的其它服務器上去。

  • 分散性(Spread):

    ​ 分佈式環境中,客戶端請求時候可能不知道所有服務器的存在,可能只知道其中一部分服務器,在客戶端看來他看到的部分服務器會形成一個完整的hash環。如果多個客戶端都把部分服務器作爲一個完整hash環,那麼可能會導致,同一個用戶的請求被路由到不同的服務器進行處理。這種情況顯然是應該避免的,因爲它不能保證同一個用戶的請求落到同一個服務器。所謂分散性是指上述情況發生的嚴重程度。好的哈希算法應儘量量避免盡量降低分散性。 而一致性hash具有很低的分散性。

4.2.4 虛擬節點

​ 一部分節點下線之後,雖然剩餘機器都在處理請求,但是明顯每個機器的負載不不均衡,這樣稱
爲一致性hash的傾斜,虛擬節點的出現就是爲了了解決這個問題。

在剛纔的例子當中,如果Master3節點也掛掉,那麼一致性hash傾斜就很明顯了:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-zZ370OCQ-1591364920275)(assets/1560356269287.png)]

可以看到,理論上Master1需要存儲25%的數據,而Master4要存儲75%的數據。

​ 上面這個例子中,我們可以對已有的兩個節點創建虛擬節點,每個節點創建兩個虛擬節點。那麼實際的Master1節點就變成了兩個虛擬節點Master1-1和Master1-2,而另一個實際的Master4節點就變成了兩個虛擬節點Master4-1和Master4-2,這個時候數據基本均衡了:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ifGNI7Fk-1591364920278)(assets/1560356902393.png)]

4.3 twemproxy實現hash分片

4.3.1 twemproxy介紹

​ Twemproxy由Twitter開源,是一個redis和memcache快速/輕量級代理服務器,利用中間件做分片的技術。twemproxy處於客戶端和服務器的中間,將客戶端發來的請求,進行一定的處理後(sharding),再轉發給後端真正的redis服務器。

​ 官方網址:https://github.com/twitter/twemproxy

作用:
Twemproxy通過引入一個代理層,可以將其後端的多臺Redis或Memcached實例進行統一管理與分配,使應用程序只需要在Twemproxy上進行操作,而不用關心後面具體有多少個真實的Redis或Memcached存儲
特性:

  • 支持失敗節點自動刪除

    ​ 可以設置重新連接該節點的時間

    ​ 可以設置連接多少次之後刪除該節點

  • 減少客戶端直接與服務器的連接數量

    ​ 自動分片到後端多個redis實例上

  • 多種哈希算法

    ​ md5,crc16,crc32,crc32a,fnv1_64,fnv1a_64,fnv1_32,fnv1a_32,hsieh,murmur,jenkins

  • 多種分片算法

    ​ ketama(一致性hash算法的一種實現),modula,random

4.3.2 準備redis實例

執行以下命令

# 準備一個redis實例
cd /usr/local/redis/
mkdir twemproxy-redis
cp bin twemproxy-redis/redis01 -R

# 清理redis
cd twemproxy-redis/redis01/
rm -rf dump.rdb 
rm -rf redis.conf 

# 複製配置文件
cp /root/redis-4.0.14/redis.conf ./

# 修改配置文件
vi redis.conf
# Redis服務器可以跨網絡訪問
修改 bind 爲 0.0.0.0
# 關閉保護模式
修改 protected-mode 爲 no
# 設置端口號
修改 port 爲 7601
# Redis後臺啓動
修改 daemonize 爲 yes
# 開啓aof持久化
修改 appendonly 爲 yes

再複製兩份,修改端口號爲7602,7603,啓動redis實例

這樣我們就準備好了三個redis實例 7601 、 7602和7603

4.3.2 twemproxy安裝

環境準備:

yum  -y install install autoconf automake libtool

上傳資料中的twemproxy.tar,並安裝,執行以下命令:

# 安裝包解包
cd root
tar -xf twemproxy.tar 

# 安裝twemproxy
cd twemproxy
autoreconf -fvi
./configure --enable-debug=full --prefix=/usr/local/twemproxy
make
make install

# 編寫配置文件
cd /usr/local/twemproxy/
mkdir conf run
vi conf/nutcracker.yml
# 配置文件內容如下
alpha:
  listen: 192.168.200.129:22121
  hash: fnv1a_64
  distribution: ketama
  auto_eject_hosts: true
  redis: true
  server_retry_timeout: 2000
  server_failure_limit: 1
  servers:
   - 192.168.200.129:7601:1
   - 192.168.200.129:7602:1
   - 192.168.200.129:7603:1
   
# 測試配置文件
./sbin/nutcracker -t
# 如下應該提示OK
nutcracker: configuration file 'conf/nutcracker.yml' syntax is ok

# 啓動twemproxy(注意這是一行命令)
./sbin/nutcracker -d -c /usr/local/twemproxy/conf/nutcracker.yml -p /usr/local/twemproxy/run/redisproxy.pid -o /usr/local/twemproxy/run/redisproxy.log

安裝完成後,可以執行以下命令查看安裝狀態

# 查看啓動信息
ps -ef | grep nutcracker
# 查看端口使用情況
netstat -nltp | grep nutcrac

4.3.3 twemproxy使用

命令行使用

使用twemproxy和單機版是一樣,對外就像是用單機版redis一樣。

但是有些命令不能用,例如info,因爲這個畢竟twemproxy只是一個代理。

cd /usr/local/redis/bin/
./redis-cli -h 192.168.200.129 -p 22121

可以測試get、set方法

SpringDataRedis

使用Java代碼操作twemproxy和操作redis也是一樣的

配置文件修改爲:

spring:
  redis:
    host: 192.168.200.129
    port: 22121

測試代碼:

    @Test
    public void test() {
        redisTemplate.opsForValue().set("test", "redis");
        String test = redisTemplate.opsForValue().get("test");
        System.out.println(test);

        Random r = new Random();
        for (int i = 0; i < 100; i++) {
            redisTemplate.opsForValue().set(r.nextInt(100000)+"test", "redis");
        }
    }

我們可以單獨連接redis實例,發現數據是分別進行存放的

5. 總結

​ 在這個章節,我們學習使用了Redis的單機版,主從複製,Sentinel,內置集羣,twemproxy集羣,那麼是不是掌握一種就足夠了呢。並不是的,我們需要根據具體的使用場景分別使用。

  • 單機版:數據量,QPS不大的情況使用
  • 主從複製:需要讀寫分離,高可用的時候使用
  • Sentinel哨兵:需要自動容錯容災的時候使用
  • 內置集羣:數據量比較大,QPS有一定要求的時候使用,但集羣節點不能過多
  • twemproxy集羣:數據量,QPS要求非常高,可以使用

​ 以上描述了這幾種模式的使用場景,但是其使用成本是從上往下遞增的,所以到底是用那種模式,還是要結合具體的使用場景,預算成本來進行選擇。

​ 另外,這些模式也不是完全獨立的,一般我們在使用twemproxy集羣的時候都是高併發,大數據,高可用的環境,可以結合主從複製+哨兵保證集羣的高可用,keepliaved保證代理服務器的高可用。其使用方式在本章節中都已經給大家介紹了,有興趣的學員可以嘗試自己整合一下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章