Thiết lập Redis Sentinel trên Docker: High Availability, Giám sát và Tự động Failover

Database tutorial - IT technology blog
Database tutorial - IT technology blog

Sự cố Cache lúc nửa đêm

Đó là 2 giờ sáng ngày thứ Sáu, và lưu lượng truy cập bất ngờ tăng vọt lên 15.000 requests mỗi giây. Instance Redis chính (primary) của bạn bị tràn bộ nhớ rồi gặp sự cố sập. Nếu chỉ vận hành một node Redis standalone duy nhất, mọi thứ sẽ sụp đổ rất nhanh. Session của người dùng biến mất, API rate limit ngừng hiệu lực, và 50.000 truy vấn cơ sở dữ liệu mỗi phút ồ ạt đổ dồn vào PostgreSQL hoặc MySQL cùng lúc. Hiệu ứng dây chuyền này chính là kịch bản cache stampede kinh điển.

Redis vượt trội về in-memory caching và quản lý session. Tuy nhiên, Redis standalone hoàn toàn không cung cấp cơ chế tự phục hồi. Mô hình replication master-replica tiêu chuẩn giúp giảm tải cho thao tác đọc, nhưng việc ghi dữ liệu sẽ bị gián đoạn hoàn toàn khi master chết. Nếu thiếu một tầng điều phối (orchestration), replica sẽ không bao giờ có thể tự thăng cấp. Kỹ sư sẽ phải thức dậy lúc nửa đêm, đăng nhập vào server, chạy lệnh REPLICAOF NO ONE và cập nhật lại chuỗi kết nối ứng dụng trên mọi container hoặc pod đang chạy.

Quy trình xử lý thủ công đó thường tiêu tốn từ 15 đến 30 phút downtime đầy căng thẳng. Sentinel giải quyết triệt để nút thắt cổ chai này bằng cách liên tục giám sát cluster và tự động thăng cấp một replica khỏe mạnh chỉ trong vài giây.

Cách Redis Sentinel xử lý Failover

Redis Sentinel hoạt động như một tiến trình giám sát (supervisory) gọn nhẹ chạy song song với các instance database của bạn. Nó đảm nhận bốn nhiệm vụ riêng biệt:

  • Giám sát trạng thái (Health Monitoring): Định kỳ gửi lệnh PING mỗi giây một lần tới master và các replica.
  • Cảnh báo (Alerting): Phát thông báo qua các kênh Pub/Sub khi trạng thái của node thay đổi.
  • Tự động Failover (Automated Failover): Thăng cấp replica có replication offset nhỏ nhất lên làm master nếu leader hiện tại ngừng phản hồi.
  • Cung cấp cấu hình (Configuration Provider): Đóng vai trò làm nguồn thông tin giúp client biết instance nào đang tiếp nhận ghi dữ liệu, nhờ đó ứng dụng không cần hardcode địa chỉ IP.

Quorum và Cơ chế chống Split-Brain

Môi trường production yêu cầu tối thiểu ba node Sentinel được đặt trên các failure domain độc lập. Sentinel dựa vào ngưỡng quorum để tuyên bố một instance đã thực sự chết khách quan (ODOWN). Nếu một Sentinel đơn lẻ mất kết nối với master lâu hơn khoảng thời gian down-after-milliseconds (ví dụ: 5.000 ms), nó sẽ đánh dấu node đó là chết chủ quan (SDOWN).

Khi có hai trên ba Sentinel đồng thuận về sự cố, chúng sẽ kích hoạt một cuộc bầu chọn thông qua giao thức đồng thuận tương tự Raft. Một Sentinel sẽ trở thành leader, ban hành lệnh thăng cấp và cấu hình lại các replica còn lại. Việc sử dụng ba node giúp ngăn chặn hiện tượng split-brain — tình trạng phân mảnh mạng khiến hệ thống vô tình tạo ra hai master cạnh tranh nhau.

Triển khai Redis Sentinel với Docker Compose

Hệ thống mạng container trong Docker tạo thêm một lớp trừu tượng. Do Sentinel sẽ tự động ghi đè file cấu hình của chính nó trong quá trình runtime, mỗi container Sentinel cần một file cấu hình độc lập và có quyền ghi (writable) thay vì dùng chung một volume mount từ máy host. Dưới đây là mô hình triển khai thực tế gồm một master, hai replica và ba Sentinel.

1. Cấu trúc thư mục

Thiết lập các thư mục riêng biệt và tạo ba bản sao cấu hình Sentinel độc lập:

mkdir -p redis-sentinel-docker/{sentinel,redis}
cd redis-sentinel-docker

2. Cấu hình Redis cho Master và Replica

Tạo file redis/redis.conf. Mật khẩu xác thực chung sẽ bảo vệ toàn bộ các node database:

# redis/redis.conf
protected-mode no
requirepass SecretAuth2026!
masterauth SecretAuth2026!
appendonly yes

3. Các file cấu hình Sentinel

Sentinel tự động sửa đổi cấu hình trực tiếp khi trạng thái thay đổi. Hãy tạo ba file riêng biệt—sentinel/sentinel-1.conf, sentinel/sentinel-2.conf và sentinel/sentinel-3.conf—với các tham số khởi tạo giống hệt nhau:

# sentinel/sentinel-1.conf (lặp lại cho 2 và 3)
port 26379
protected-mode no
dir /tmp

# monitor <tên-nhóm-master> <host> <port> <quorum>
sentinel monitor mymaster redis-master 6379 2
sentinel auth-pass mymaster SecretAuth2026!
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 10000
sentinel parallel-syncs mymaster 1

4. Thiết lập Docker Compose

Định nghĩa toàn bộ sáu node bên trong docker-compose.yml trên cùng một bridge network:

version: '3.8'

networks:
  redis-net:
    driver: bridge

services:
  redis-master:
    image: redis:7.2-alpine
    container_name: redis-master
    command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
    volumes:
      - ./redis/redis.conf:/usr/local/etc/redis/redis.conf
    ports:
      - "6379:6379"
    networks:
      - redis-net

  redis-replica-1:
    image: redis:7.2-alpine
    container_name: redis-replica-1
    command: ["redis-server", "/usr/local/etc/redis/redis.conf", "--replicaof", "redis-master", "6379"]
    volumes:
      - ./redis/redis.conf:/usr/local/etc/redis/redis.conf
    depends_on:
      - redis-master
    networks:
      - redis-net

  redis-replica-2:
    image: redis:7.2-alpine
    container_name: redis-replica-2
    command: ["redis-server", "/usr/local/etc/redis/redis.conf", "--replicaof", "redis-master", "6379"]
    volumes:
      - ./redis/redis.conf:/usr/local/etc/redis/redis.conf
    depends_on:
      - redis-master
    networks:
      - redis-net

  sentinel-1:
    image: redis:7.2-alpine
    container_name: sentinel-1
    command: ["redis-sentinel", "/etc/redis/sentinel.conf"]
    volumes:
      - ./sentinel/sentinel-1.conf:/etc/redis/sentinel.conf
    depends_on:
      - redis-master
      - redis-replica-1
      - redis-replica-2
    ports:
      - "26379:26379"
    networks:
      - redis-net

  sentinel-2:
    image: redis:7.2-alpine
    container_name: sentinel-2
    command: ["redis-sentinel", "/etc/redis/sentinel.conf"]
    volumes:
      - ./sentinel/sentinel-2.conf:/etc/redis/sentinel.conf
    depends_on:
      - redis-master
      - redis-replica-1
      - redis-replica-2
    ports:
      - "26380:26379"
    networks:
      - redis-net

  sentinel-3:
    image: redis:7.2-alpine
    container_name: sentinel-3
    command: ["redis-sentinel", "/etc/redis/sentinel.conf"]
    volumes:
      - ./sentinel/sentinel-3.conf:/etc/redis/sentinel.conf
    depends_on:
      - redis-master
      - redis-replica-1
      - redis-replica-2
    ports:
      - "26381:26379"
    networks:
      - redis-net

5. Kiểm tra Topology của Cluster

Khởi chạy môi trường ở chế độ chạy nền (detached mode):

docker compose up -d

Kiểm tra xem master đã nhận diện đủ cả hai replica hay chưa:

docker exec -it redis-master redis-cli -a SecretAuth2026! info replication

Lệnh này sẽ hiển thị kết quả role:master và xác nhận connected_replicas:2. Tiếp theo, truy vấn sentinel-1 để xác thực khả năng giám sát cluster:

docker exec -it sentinel-1 redis-cli -p 26379 sentinel master mymaster

Phản hồi trả về sẽ liệt kê IP container của master cùng với num-slaves: 2 và num-other-sentinels: 2.

6. Kiểm thử quy trình Failover

Mô phỏng tình huống master sập bất ngờ bằng cách dừng container:

docker stop redis-master

Theo dõi log trên sentinel-1 ngay lập tức để quan sát tiến trình chuyển giao:

docker logs -f sentinel-1

Chỉ trong vòng năm đến bảy giây, log sẽ hiển thị toàn bộ vòng đời của đợt bầu chọn:

  1. +sdown master mymaster 172.20.0.2 6379: Đạt ngưỡng ping timeout cục bộ sau 5.000 ms.
  2. +odown master mymaster 172.20.0.2 6379 #quorum 2/2: Quorum được xác nhận bởi các Sentinel ngang hàng.
  3. +vote-for-leader ...: Các Sentinel tiến hành bầu chọn điều phối viên failover.
  4. +promoted-slave ...: Replica 1 hoặc Replica 2 đảm nhận vai trò master mới.
  5. +switch-master mymaster ...: Sentinel điều hướng mục tiêu primary sang địa chỉ IP mới.

Kiểm tra master đang hoạt động hiện tại thông qua Sentinel:

docker exec -it sentinel-1 redis-cli -p 26379 sentinel get-master-addr-by-name mymaster

Sentinel sẽ trả về địa chỉ IP của container vừa được thăng cấp. Khởi động lại master ban đầu bằng lệnh docker start redis-master. Sentinel sẽ lập tức cấu hình lại node này thành một replica của master mới, đảm bảo trọn vẹn tính toàn vẹn của dữ liệu ghi.

Tích hợp vào Ứng dụng

Kết nối trực tiếp qua IP sẽ bị đứt đoạn hoàn toàn khi failover xảy ra. Do đó, các ứng dụng cần phải sử dụng thư viện client có hỗ trợ Sentinel (Sentinel-aware)—chẳng hạn như ioredis trong Node.js, redis-py đi kèm Sentinel helper, hoặc Spring Data Redis trong Java.

Các driver này sẽ kết nối đến các cổng Sentinel (26379, 26380, 26381) trước, tự động phân giải master hiện tại và đăng ký nhận sự kiện +switch-master. Khi một node gặp sự cố, ứng dụng của bạn sẽ tự động kết nối lại với leader mới, hạn chế thời gian gián đoạn ghi chỉ còn trong tích tắc vài giây.

Share: