Triển Khai Redis Cluster High Availability với Docker Compose

Để đạt được tính sẵn sàng cao và khả năng mở rộng trong Redis, chế độ cụm (Redis Cluster) là một lựa chọn lý tưởng. Tuy nhiên, việc thiết lập một cụm Redis yêu cầu tuân thủ các quy tắc về số lượng nút tối thiểu. Cụ thể, Redis Cluster cần ít nhất 3 nút master để hoạt động ổn định. Để đảm bảo khả năng chịu lỗi, mỗi master thường đi kèm với một hoặc nhiều nút replica (slave). Do đó, để triển khai một cụm với 3 master và mỗi master có 1 replica, bạn sẽ cần tổng cộng 6 thực thể Redis riêng biệt. Nếu bạn cố gắng khởi tạo một cụm chỉ với 3 nút nhưng yêu cầu 1 bản sao trên mỗi nút, bạn sẽ gặp thông báo lỗi tương tự như sau:
*** ERROR: Invalid configuration for cluster creation.  
*** Redis Cluster requires at least 3 master nodes.  
*** This is not possible with 3 nodes and 1 replicas per node.  
*** At least 6 nodes are required.
Thông báo này nhấn mạnh rằng để có cấu trúc 3 master và 3 replica, tổng cộng 6 nút là bắt buộc.

Cấu Hình Redis Cluster Bằng Docker Compose

Chúng ta sẽ sử dụng Docker Compose để dễ dàng điều phối 6 thực thể Redis. Dưới đây là tệp docker-compose.yml minh họa cách thiết lập môi trường này.
version: "3.9"
services:
  redis-node-1:
    image: redis:latest
    container_name: redis-node-1
    working_dir: /app/config
    environment:
      - REDIS_PORT=6379 # Cổng dịch vụ cho nút Redis này
    ports:
      - "6379:6379"     # Ánh xạ cổng dịch vụ Redis
      - "16379:16379"   # Ánh xạ cổng bus cluster
    stdin_open: true
    tty: true
    network_mode: host # Chế độ mạng host có thể gây vấn đề tương thích trên một số môi trường. Cân nhắc dùng mạng bridge tùy chỉnh nếu cần.
    privileged: true   # Cung cấp đặc quyền để container có thể thực hiện một số lệnh hệ thống
    volumes:
      - ./redis-cluster-config/node-6379.conf:/app/config/redis.conf # Ánh xạ tệp cấu hình
      - ./redis-cluster-data/node-6379:/data                       # Ánh xạ thư mục dữ liệu để duy trì dữ liệu
      - ./scripts/start-redis.sh:/app/config/start-redis.sh        # Ánh xạ script khởi động
    entrypoint: ["bash", "/app/config/start-redis.sh"]

  redis-node-2:
    image: redis:latest
    container_name: redis-node-2
    working_dir: /app/config
    environment:
      - REDIS_PORT=6380
    ports:
      - "6380:6380"
      - "16380:16380"
    stdin_open: true
    tty: true
    network_mode: host
    privileged: true
    volumes:
      - ./redis-cluster-config/node-6380.conf:/app/config/redis.conf
      - ./redis-cluster-data/node-6380:/data
      - ./scripts/start-redis.sh:/app/config/start-redis.sh
    entrypoint: ["bash", "/app/config/start-redis.sh"]

  redis-node-3:
    image: redis:latest
    container_name: redis-node-3
    working_dir: /app/config
    environment:
      - REDIS_PORT=6381
    ports:
      - "6381:6381"
      - "16381:16381"
    stdin_open: true
    tty: true
    network_mode: host
    privileged: true
    volumes:
      - ./redis-cluster-config/node-6381.conf:/app/config/redis.conf
      - ./redis-cluster-data/node-6381:/data
      - ./scripts/start-redis.sh:/app/config/start-redis.sh
    entrypoint: ["bash", "/app/config/start-redis.sh"]

  redis-node-4:
    image: redis:latest
    container_name: redis-node-4
    working_dir: /app/config
    environment:
      - REDIS_PORT=6382
    ports:
      - "6382:6382"
      - "16382:16382"
    stdin_open: true
    tty: true
    network_mode: host
    privileged: true
    volumes:
      - ./redis-cluster-config/node-6382.conf:/app/config/redis.conf
      - ./redis-cluster-data/node-6382:/data
      - ./scripts/start-redis.sh:/app/config/start-redis.sh
    entrypoint: ["bash", "/app/config/start-redis.sh"]

  redis-node-5:
    image: redis:latest
    container_name: redis-node-5
    working_dir: /app/config
    environment:
      - REDIS_PORT=6383
    ports:
      - "6383:6383"
      - "16383:16383"
    stdin_open: true
    tty: true
    network_mode: host
    privileged: true
    volumes:
      - ./redis-cluster-config/node-6383.conf:/app/config/redis.conf
      - ./redis-cluster-data/node-6383:/data
      - ./scripts/start-redis.sh:/app/config/start-redis.sh
    entrypoint: ["bash", "/app/config/start-redis.sh"]

  redis-node-6:
    image: redis:latest
    container_name: redis-node-6
    working_dir: /app/config
    environment:
      - REDIS_PORT=6384
    ports:
      - "6384:6384"
      - "16384:16384"
    stdin_open: true
    tty: true
    network_mode: host
    privileged: true
    volumes:
      - ./redis-cluster-config/node-6384.conf:/app/config/redis.conf
      - ./redis-cluster-data/node-6384:/data
      - ./scripts/start-redis.sh:/app/config/start-redis.sh
    entrypoint: ["bash", "/app/config/start-redis.sh"]

Lưu ý về network_mode: host: Chế độ mạng host cho phép các container sử dụng trực tiếp ngăn xếp mạng của máy chủ. Điều này có thể hữu ích để đơn giản hóa việc khám phá nút trong các thiết lập cụm cục bộ, nhưng nó có thể gây ra xung đột cổng và không được khuyến nghị trong môi trường sản xuất đa máy chủ hoặc với một số cấu hình Docker Compose. Đối với các triển khai phức tạp hơn, việc sử dụng các mạng bridge do Docker quản lý hoặc mạng overlay là lựa chọn tốt hơn.

Tệp Cấu Hình Redis (Ví dụ node-6379.conf)

Mỗi nút Redis sẽ cần một tệp cấu hình riêng, với các cổng và tệp cấu hình cụm được điều chỉnh. Dưới đây là mẫu cho một nút.
# Cấu hình mạng
bind 0.0.0.0              # Cho phép kết nối từ mọi địa chỉ IP
protected-mode no         # Tắt chế độ bảo vệ để cho phép truy cập từ bên ngoài container
port 6379                 # Cổng dịch vụ chính của Redis

# Cấu hình Redis Cluster
cluster-enabled yes                     # Bật chế độ Cluster
cluster-config-file nodes-6379.conf     # Tên tệp cấu hình cluster riêng cho nút này
cluster-node-timeout 15000              # Thời gian timeout cho nút (miliseconds)

# Cấu hình Persistence (RDB & AOF)
save 900 1      # Lưu DB sau 900 giây nếu có ít nhất 1 thay đổi
save 300 10     # Lưu DB sau 300 giây nếu có ít nhất 10 thay đổi
save 60 10000   # Lưu DB sau 60 giây nếu có ít nhất 10000 thay đổi
stop-writes-on-bgsave-error yes # Ngừng ghi nếu RDB snapshot thất bại
rdbcompression yes              # Nén tệp RDB
dbfilename dump-6379.rdb        # Tên tệp RDB cho nút này
appendonly yes                  # Bật chế độ AOF (Append Only File)
appendfilename "appendonly-6379.aof" # Tên tệp AOF cho nút này
appendfsync everysec            # Fsync AOF mỗi giây
dir "/data"                     # Thư mục làm việc trong container (được map ra host)

# Cấu hình chung
loglevel notice                 # Mức độ log
always-show-logo yes            # Hiển thị logo Redis khi khởi động

Bạn cần tạo các tệp cấu hình tương tự cho các cổng 6380, 6381, 6382, 6383 và 6384, đảm bảo rằng giá trị port, cluster-config-file, dbfilenameappendfilename được cập nhật cho mỗi nút.

Kịch bản Khởi động (start-redis.sh)

Tệp kịch bản này sẽ được sử dụng bởi tất cả các dịch vụ Redis để khởi động chúng với tệp cấu hình và cổng phù hợp.
#!/bin/bash
# Script khởi động Redis Server trong môi trường Docker
echo "Đang khởi động Redis server trên cổng ${REDIS_PORT}..."
# Khởi động Redis với tệp cấu hình chính, ghi đè cổng và tệp cấu hình cluster bằng biến môi trường
redis-server /app/config/redis.conf --port "${REDIS_PORT}" --cluster-config-file "nodes-${REDIS_PORT}.conf" --dir /data

Các Bước Triển Khai

  1. Tạo cấu trúc thư mục: Trên máy chủ của bạn, tạo các thư mục sau. Đây là nơi các tệp cấu hình và dữ liệu của Redis sẽ được lưu trữ:
    mkdir -p redis-cluster-config
    mkdir -p redis-cluster-data/node-6379
    mkdir -p redis-cluster-data/node-6380
    mkdir -p redis-cluster-data/node-6381
    mkdir -p redis-cluster-data/node-6382
    mkdir -p redis-cluster-data/node-6383
    mkdir -p redis-cluster-data/node-6384
    mkdir -p scripts
  2. Lưu tệp cấu hình:
    • Lưu tệp docker-compose.yml vào thư mục gốc của dự án.
    • Tạo 6 tệp .conf (ví dụ: node-6379.conf, node-6380.conf, ...) trong thư mục redis-cluster-config, mỗi tệp được cấu hình với cổng tương ứng và các tùy chọn cluster đã nêu.
    • Lưu tệp start-redis.sh vào thư mục scripts.
  3. Cấp quyền thực thi: Đảm bảo script khởi động có quyền thực thi:
    chmod +x scripts/start-redis.sh
  4. Khởi động các dịch vụ Redis: Chạy lệnh sau trong thư mục gốc của dự án:
    docker-compose up -d
    Lệnh này sẽ khởi tạo và chạy 6 container Redis ở chế độ nền.
  5. Khởi tạo Redis Cluster: Sau khi tất cả các container đã chạy, bạn cần kết nối chúng thành một cụm. Sử dụng lệnh redis-cli --cluster create với IP của máy chủ Docker của bạn (ví dụ: 192.168.0.170):
    redis-cli --cluster create \
      192.168.0.170:6379 192.168.0.170:6380 192.168.0.170:6381 \
      192.168.0.170:6382 192.168.0.170:6383 192.168.0.170:6384 \
      --cluster-replicas 1
    Hệ thống sẽ hỏi bạn xác nhận việc tạo cụm và phân bổ các slot, hãy nhập yes.
  6. Kiểm tra trạng thái cụm: Để xác minh cụm đã được thiết lập đúng cách, bạn có thể kiểm tra thông tin và các nút trong cụm từ bất kỳ nút nào, ví dụ: nút 6379:
    redis-cli -h 192.168.0.170 -p 6379 cluster info
    Và để xem các nút cùng trạng thái master/replica của chúng:
    redis-cli -h 192.168.0.170 -p 6379 cluster nodes
  7. Kết nối tới cụm: Khi làm việc với Redis Cluster, điều quan trọng là phải sử dụng chế độ cluster client (-c) để các lệnh được định tuyến chính xác đến nút sở hữu key:
    redis-cli -h 192.168.0.170 -p 6379 -c

Thẻ: Redis Redis Cluster Docker Compose High Availability containerization

Đăng vào ngày 6 tháng 6 lúc 03:38