Ubuntu 22.04 Redis Sentinel 高可用架構

Ubuntu 22.04 Redis Sentinel High Availability Setup

Redis Sentinel 概述

Redis Sentinel 是 Redis 官方提供的高可用性解決方案。它可以自動監控 Redis 主從節點的運作狀態,並在主節點發生故障時,自動將其中一個從節點提升為新的主節點,確保服務持續運作。

Sentinel 主要功能

  • 監控(Monitoring):持續檢查主節點和從節點是否正常運作
  • 通知(Notification):當被監控的 Redis 實例發生問題時,可透過 API 通知系統管理員
  • 自動故障轉移(Automatic Failover):當主節點失效時,自動將從節點提升為主節點
  • 設定提供者(Configuration Provider):客戶端可透過 Sentinel 取得目前主節點的位址

適用場景

  • 需要高可用性的生產環境
  • 讀取流量較大,需要讀寫分離的場景
  • 對服務中斷時間有嚴格要求的應用

架構說明

本文將建置 1 Master + 2 Slaves + 3 Sentinels 的高可用架構。

伺服器規劃

角色IP 位址連接埠
Redis Master192.168.1.106379
Redis Slave 1192.168.1.116379
Redis Slave 2192.168.1.126379
Sentinel 1192.168.1.1026379
Sentinel 2192.168.1.1126379
Sentinel 3192.168.1.1226379

架構圖

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
                    +----------------+
                    |   Application  |
                    +-------+--------+
                            |
                    +-------v--------+
                    |   Sentinels    |
                    | (監控與故障轉移) |
                    +-------+--------+
                            |
        +-------------------+-------------------+
        |                   |                   |
+-------v-------+   +-------v-------+   +-------v-------+
| Redis Master  |   | Redis Slave 1 |   | Redis Slave 2 |
| 192.168.1.10  |   | 192.168.1.11  |   | 192.168.1.12  |
+---------------+   +---------------+   +---------------+

環境準備

在所有節點上安裝 Redis

首先在三台伺服器上安裝 Redis:

1
2
sudo apt update
sudo apt install redis-server -y

設定防火牆

開放必要的連接埠:

1
2
3
4
5
6
7
8
# 開放 Redis 連接埠
sudo ufw allow 6379/tcp

# 開放 Sentinel 連接埠
sudo ufw allow 26379/tcp

# 重新載入防火牆規則
sudo ufw reload

Redis Master 設定

編輯主節點的設定檔 /etc/redis/redis.conf

1
sudo nano /etc/redis/redis.conf

修改以下設定:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 綁定所有網路介面
bind 0.0.0.0

# 設定連接埠
port 6379

# 關閉保護模式(因為有密碼保護)
protected-mode no

# 設定密碼
requirepass your_redis_password

# 設定主從複製密碼(從節點連接時使用)
masterauth your_redis_password

# 啟用 AOF 持久化
appendonly yes

# 設定 RDB 持久化
save 900 1
save 300 10
save 60 10000

重新啟動 Redis:

1
2
sudo systemctl restart redis-server
sudo systemctl status redis-server

Redis Slave 設定

在兩台從節點(192.168.1.11 和 192.168.1.12)上編輯設定檔:

1
sudo nano /etc/redis/redis.conf

修改以下設定:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 綁定所有網路介面
bind 0.0.0.0

# 設定連接埠
port 6379

# 關閉保護模式
protected-mode no

# 設定密碼
requirepass your_redis_password

# 設定主從複製密碼
masterauth your_redis_password

# 設定主節點位址(關鍵設定)
replicaof 192.168.1.10 6379

# 啟用 AOF 持久化
appendonly yes

# 從節點設定為唯讀
replica-read-only yes

重新啟動 Redis:

1
2
sudo systemctl restart redis-server
sudo systemctl status redis-server

驗證主從複製

在主節點上檢查複製狀態:

1
redis-cli -a your_redis_password INFO replication

應該看到類似以下輸出:

1
2
3
4
5
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.1.11,port=6379,state=online,offset=xxx,lag=0
slave1:ip=192.168.1.12,port=6379,state=online,offset=xxx,lag=0

Sentinel 設定檔

在三台伺服器上建立 Sentinel 設定檔:

1
sudo nano /etc/redis/sentinel.conf

Sentinel 設定檔內容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# Sentinel 連接埠
port 26379

# 綁定所有網路介面
bind 0.0.0.0

# 關閉保護模式
protected-mode no

# 以背景程序執行
daemonize yes

# PID 檔案位置
pidfile /var/run/redis/redis-sentinel.pid

# Log 檔案位置
logfile /var/log/redis/redis-sentinel.log

# 工作目錄
dir /var/lib/redis

# 監控的主節點設定
# sentinel monitor <master-name> <ip> <port> <quorum>
# quorum:需要多少個 Sentinel 同意才進行故障轉移
sentinel monitor mymaster 192.168.1.10 6379 2

# 主節點密碼
sentinel auth-pass mymaster your_redis_password

# 判定主節點下線的時間(毫秒)
sentinel down-after-milliseconds mymaster 5000

# 故障轉移超時時間(毫秒)
sentinel failover-timeout mymaster 60000

# 同時進行同步的從節點數量
sentinel parallel-syncs mymaster 1

設定檔案權限:

1
2
sudo chown redis:redis /etc/redis/sentinel.conf
sudo chmod 640 /etc/redis/sentinel.conf

啟動 Sentinel

建立 Systemd 服務

建立 Sentinel 的 systemd 服務檔案:

1
sudo nano /etc/systemd/system/redis-sentinel.service

內容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
[Unit]
Description=Redis Sentinel
After=network.target

[Service]
Type=forking
ExecStart=/usr/bin/redis-sentinel /etc/redis/sentinel.conf
ExecStop=/usr/bin/redis-cli -p 26379 shutdown
PIDFile=/var/run/redis/redis-sentinel.pid
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target

啟動服務

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 重新載入 systemd 設定
sudo systemctl daemon-reload

# 啟動 Sentinel
sudo systemctl start redis-sentinel

# 設定開機自動啟動
sudo systemctl enable redis-sentinel

# 檢查狀態
sudo systemctl status redis-sentinel

驗證 Sentinel 運作

檢查 Sentinel 狀態:

1
redis-cli -p 26379 INFO sentinel

應該看到類似輸出:

1
2
3
4
5
6
7
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.1.10:6379,slaves=2,sentinels=3

查詢目前主節點:

1
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster

故障轉移測試

模擬主節點故障

在主節點上停止 Redis 服務:

1
sudo systemctl stop redis-server

觀察 Sentinel 日誌

在任一 Sentinel 節點上查看日誌:

1
sudo tail -f /var/log/redis/redis-sentinel.log

您應該看到類似以下的故障轉移過程:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
+sdown master mymaster 192.168.1.10 6379
+odown master mymaster 192.168.1.10 6379 #quorum 2/2
+try-failover master mymaster 192.168.1.10 6379
+vote-for-leader xxx 1
+elected-leader master mymaster 192.168.1.10 6379
+failover-state-select-slave master mymaster 192.168.1.10 6379
+selected-slave slave 192.168.1.11:6379
+failover-state-send-slaveof-noone slave 192.168.1.11:6379
+failover-state-wait-promotion slave 192.168.1.11:6379
+promoted-slave slave 192.168.1.11:6379
+switch-master mymaster 192.168.1.10 6379 192.168.1.11 6379

確認新主節點

1
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster

恢復原主節點

重新啟動原主節點,它會自動成為新主節點的從節點:

1
sudo systemctl start redis-server

應用程式連線設定

Python 連線範例

使用 redis-py 套件連接 Sentinel:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
from redis.sentinel import Sentinel

# Sentinel 節點列表
sentinel = Sentinel([
    ('192.168.1.10', 26379),
    ('192.168.1.11', 26379),
    ('192.168.1.12', 26379)
], socket_timeout=0.5)

# 取得主節點連線(用於寫入)
master = sentinel.master_for('mymaster', socket_timeout=0.5, password='your_redis_password')

# 取得從節點連線(用於讀取)
slave = sentinel.slave_for('mymaster', socket_timeout=0.5, password='your_redis_password')

# 寫入資料
master.set('key', 'value')

# 讀取資料
value = slave.get('key')
print(value)

Node.js 連線範例

使用 ioredis 套件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
const Redis = require('ioredis');

const redis = new Redis({
  sentinels: [
    { host: '192.168.1.10', port: 26379 },
    { host: '192.168.1.11', port: 26379 },
    { host: '192.168.1.12', port: 26379 }
  ],
  name: 'mymaster',
  password: 'your_redis_password'
});

redis.set('key', 'value');
redis.get('key', (err, result) => {
  console.log(result);
});

維運建議

監控指標

建議監控以下指標:

  • Sentinel 連線狀態
  • 主從複製延遲(replication lag)
  • 記憶體使用量
  • 連線數量

日常維護

1
2
3
4
5
6
7
8
# 檢查 Sentinel 狀態
redis-cli -p 26379 SENTINEL masters

# 檢查從節點狀態
redis-cli -p 26379 SENTINEL slaves mymaster

# 手動故障轉移
redis-cli -p 26379 SENTINEL failover mymaster

參考資料

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy