Tính sẵn sàng cao Redis với Sentinel

1493
18-12-2023
Tính sẵn sàng cao Redis với Sentinel

Redis là một phần mềm nguồn mở cung cấp khả năng lưu trữ dữ liệu trong RAM thường được sử dụng cho bộ nhớ đệm, trình trung chuyển tin nhắn và công cụ phát trực tuyến. Redis được sử dụng bởi các công cụ nổi bật khác:

  • Twitter
  • GitHub
  • Snapchat
  • danh sách Craigslist
  • StackOverflow

Tùy từng trường hợp sử dụng mà Redis được sử dụng với các vai trò khác nhau trong một hệ thống. Và công ty của mình cũng vậy, Redis được sử dụng khá phổ biến trong hầu hết các ứng dụng. Vào một ngày đẹp trời, server Redis tự nhiên lăn ra thẳng, không thể truy cập và khôi phục lại được. Vậy là toàn bộ dữ liệu đang có trong Redis cứ thế không cánh mà bay.

Mất dữ liệu, dừng hoạt động của ứng dụng là những gì tôi phải đối mặt. Server bị trung thì có vô vàn lý do: loại trừ lý do chủ quan là code cùi, code lỗi, thì còn các lý do do khách quan mà không ai muốn xảy ra cả: các phần cứng bị lỗi, … Ở đây, mình đã xảy ra lỗi khi chạy cả ram trên máy chủ, không có bất kỳ ánh sáng nào cho bất kỳ hy vọng nào ở đây.

Sau công việc này, mình lại hì hục tìm cách làm thế nào để có thể cấu hình High Availability cho Redis để nhỡ có đen thì cũng sẽ lấy lại được những phần dữ liệu đã bị mất. Mình đã nghĩ đến Redis Replication để có thể đồng bộ dữ liệu sang nhiều server khác nhau, để mà có đen server thì cũng vẫn còn lại dữ liệu. Tuy nhiên thì mình lại cần phải có Auto-Failover nữa, vậy là mình đã tìm đến Redis Sentinel. Vậy thì mình đã làm như thế nào và ứng dụng được gì?

1. Redis Sentinel là gì?

Redis Sentinel là một tính năng sử dụng cho việc phát triển Tính sẵn sàng cao cho Redis mà không cần thiết lập cụm. Theo mô tả thì đây là các tính năng của Sentinel:

  • Giám sát. Sentinel liên tục kiểm tra xem phiên bản chính và bản sao của bạn có hoạt động như mong đợi hay không.
  • Thông báo. Sentinel có thể thông báo cho quản trị viên hệ thống hoặc các chương trình máy tính khác thông qua API rằng có sự cố xảy ra với một trong các phiên bản Redis được giám sát.
  • Tự động chuyển đổi dự phòng. Nếu bản gốc không hoạt động như mong đợi, Sentinel có thể bắt đầu quá trình chuyển đổi dự phòng trong đó bản sao được nâng cấp lên bản chính, các bản sao bổ sung khác được cấu hình lại để sử dụng bản gốc mới và các ứng dụng sử dụng máy chủ Redis sẽ được thông báo về địa chỉ mới sẽ sử dụng. - khi kết nối.
  • Nhà cung cấp cấu hình. Sentinel đóng vai trò là nguồn cấp quyền cho việc khám phá dịch vụ của khách hàng: khách hàng kết nối với Sentinels để hỏi địa chỉ của chủ Redis hiện tại chịu trách nhiệm về một dịch vụ nhất định. Nếu xảy ra chuyển đổi dự phòng, Sentinels sẽ báo cáo địa chỉ mới.

2. Khai báo Mô hình phát triển

Về cơ bản thì để phát triển khai Sentinel cũng tương đối khá dễ dàng. Mình đã và đang phát triển Redis Sentinel với 3 server và Redis thì chạy trong Docker(cái này thì có nhiều lý do, và dựa vào các ưu tiên của container nên mình thường xuyên cố gắng đưa mọi thứ vào container, miễn là phù hợp nhảy lò cò).

Tính sẵn sàng cao Redis với Sentinel - Ảnh 1.

trong đó, các nút có IP địa chỉ tương ứng như sau: Tên nút | Địa chỉ IP | ———-|———— redis-xpg72e62 | 20.10.161.181 | redis5-repl-1 | 20.10.161.80 | redis5-repl-2 | 20.10.161.111 |

3. Cấu hình

  1. Trên các nút tạo các thư mục sau
     mkdir -p /var/log/redis /var/run/redis /var/lib/redis /etc/redis 

    Tạo cấu hình tệp /etc/redis/redis.conf để cấu hình sao chép lại cấu hình như sau:

    • Trên nút 1
        activerehashing yes   always-show-logo yes   aof-load-truncated yes   aof-rewrite-incremental-fsync yes   aof-use-rdb-preamble yes   appendfilename appendonly.aof   appendfsync everysec   appendonly no   auto-aof-rewrite-min-size 64mb   auto-aof-rewrite-percentage 100   client-output-buffer-limit normal 0 0 0   client-output-buffer-limit pubsub 32mb 8mb 60   daemonize no   databases 16   dbfilename dump.rdb   dir /var/lib/redis/data   dynamic-hz yes   hash-max-ziplist-entries 512   hash-max-ziplist-value 64   hll-sparse-max-bytes 3000   hz 10   latency-monitor-threshold 0   lazyfree-lazy-eviction no   lazyfree-lazy-expire no   lazyfree-lazy-server-del no   list-compress-depth 0   list-max-ziplist-size -2   logfile /var/log/redis/redis.log   loglevel notice   lua-time-limit 5000   maxmemory 870mb   no-appendfsync-on-rewrite no   notify-keyspace-events ''   pidfile /var/run/redis/redis.pid   port 6379   protected-mode no   rdb-save-incremental-fsync yes   rdbchecksum yes   rdbcompression yes   repl-disable-tcp-nodelay no   repl-diskless-sync yes   repl-diskless-sync-delay 10   save 300 10   save 60 10000   save 900 1   set-max-intset-entries 512   slowlog-log-slower-than 10000   slowlog-max-len 128   stop-writes-on-bgsave-error yes   stream-node-max-bytes 4096   stream-node-max-entries 100   supervised no   tcp-backlog 511   tcp-keepalive 300   timeout 0   unixsocket /var/run/redis/redis.sock   unixsocketperm 700   zset-max-ziplist-entries 128   zset-max-ziplist-value 64   requirepass <password>   masterauth <password> 
    • Trên nút 2
        activerehashing yes   always-show-logo yes   aof-load-truncated yes   aof-rewrite-incremental-fsync yes   aof-use-rdb-preamble yes   appendfilename "appendonly.aof"   appendfsync everysec   appendonly no   auto-aof-rewrite-min-size 64mb   auto-aof-rewrite-percentage 100   client-output-buffer-limit normal 0 0 0   daemonize no   databases 16   dbfilename "dump.rdb"   dir "/var/lib/redis/data"   dynamic-hz yes   hash-max-ziplist-entries 512   hash-max-ziplist-value 64   hll-sparse-max-bytes 3000   hz 10   latency-monitor-threshold 0   lazyfree-lazy-eviction no   lazyfree-lazy-expire no   lazyfree-lazy-server-del no   list-compress-depth 0   list-max-ziplist-size -2   logfile "/var/log/redis/redis.log"   loglevel notice   lua-time-limit 5000   maxmemory 870mb   no-appendfsync-on-rewrite no   notify-keyspace-events ""   pidfile "/var/run/redis/redis.pid"   port 6379   protected-mode no   rdb-save-incremental-fsync yes   rdbchecksum yes   rdbcompression yes   repl-disable-tcp-nodelay no   repl-diskless-sync no   repl-diskless-sync-delay 5   save 300 10   save 60 10000   save 900 1   set-max-intset-entries 512   slowlog-log-slower-than 10000   slowlog-max-len 128   stop-writes-on-bgsave-error yes   stream-node-max-bytes 4096   stream-node-max-entries 100   supervised no   tcp-backlog 511   tcp-keepalive 300   timeout 0   unixsocket "/var/run/redis/redis.sock"   unixsocketperm 700   zset-max-ziplist-entries 128   zset-max-ziplist-value 64   requirepass <password>   masterauth <password>   min-replicas-max-lag 10   min-replicas-to-write 1   replica-lazy-flush no   replica-priority 100   replica-read-only yes   replica-serve-stale-data yes   replicaof 10.20.161.181 6379 
    • Trên nút 3
        activerehashing yes   always-show-logo yes   aof-load-truncated yes   aof-rewrite-incremental-fsync yes   aof-use-rdb-preamble yes   appendfilename "appendonly.aof"   appendfsync everysec   appendonly no   auto-aof-rewrite-min-size 64mb   auto-aof-rewrite-percentage 100   client-output-buffer-limit normal 0 0 0   daemonize no   databases 16   dbfilename "dump.rdb"   dir "/var/lib/redis/data"   dynamic-hz yes   hash-max-ziplist-entries 512   hash-max-ziplist-value 64   hll-sparse-max-bytes 3000   hz 10   latency-monitor-threshold 0   lazyfree-lazy-eviction no   lazyfree-lazy-expire no   lazyfree-lazy-server-del no   list-compress-depth 0   list-max-ziplist-size -2   logfile "/var/log/redis/redis.log"   loglevel notice   lua-time-limit 5000   maxmemory 870mb   no-appendfsync-on-rewrite no   notify-keyspace-events ""   pidfile "/var/run/redis/redis.pid"   port 6379   protected-mode no   rdb-save-incremental-fsync yes   rdbchecksum yes   rdbcompression yes   repl-disable-tcp-nodelay no   repl-diskless-sync no   repl-diskless-sync-delay 5   save 300 10   save 60 10000   save 900 1   set-max-intset-entries 512   slowlog-log-slower-than 10000   slowlog-max-len 128   stop-writes-on-bgsave-error yes   stream-node-max-bytes 4096   stream-node-max-entries 100   supervised no   tcp-backlog 511   tcp-keepalive 300   timeout 0   unixsocket "/var/run/redis/redis.sock"   unixsocketperm 700   zset-max-ziplist-entries 128   zset-max-ziplist-value 64   requirepass <password>   masterauth <password>   min-replicas-max-lag 10   min-replicas-to-write 1   replica-lazy-flush no   replica-priority 100   replica-read-only yes   replica-serve-stale-data yes   replicaof 10.20.161.181 6379 

      Lưu ý: Cần thay đổi địa chỉ IP tương ứng của bạn vào

    Tạo cấu hình tệp /etc/redis/sentinel.conf để cấu hình Sentinel như sau: bash daemonize no dir /var/lib/redis/data logfile /var/log/redis/sentinel.log pidfile /var/run/redis/sentinel.pid port 26379 protected-mode no unixsocket /var/run/redis/sentinel.sock unixsocketperm 700 requirepass <password> sentinel myid b16319cdc0783a0bf3b49e3f60759c3a173cbe7b sentinel deny-scripts-reconfig no sentinel monitor s6l 10.20.161.181 6379 2 sentinel down-after-milliseconds s6l 10000 sentinel failover-timeout s6l 10000 sentinel auth-pass s6l <password> sentinel config-epoch s6l 0 sentinel leader-epoch s6l 0 sentinel known-replica s6l 10.20.161.111 6379 sentinel known-replica s6l 10.20.161.80 6379 sentinel current-epoch 0

    • Trên nút 2
        daemonize no   dir "/var/lib/redis/data"   logfile "/var/log/redis/sentinel.log"   pidfile "/var/run/redis/sentinel.pid"   port 26379   protected-mode no   unixsocket "/var/run/redis/sentinel.sock"   unixsocketperm 700   requirepass <password>   sentinel myid 2a88d7cbe2c3ae42505b7ced061b84e53cd353ce   sentinel deny-scripts-reconfig no   sentinel monitor s6l 10.20.161.181 6379 2   sentinel down-after-milliseconds s6l 10000   sentinel failover-timeout s6l 10000   sentinel auth-pass s6l <password>   sentinel leader-epoch s6l 0   sentinel known-replica s6l 10.20.161.80 6379   sentinel known-replica s6l 10.20.161.111 6379   sentinel current-epoch 0 
    • Trên nút 3
        daemonize no   dir "/var/lib/redis/data"   logfile "/var/log/redis/sentinel.log"   pidfile "/var/run/redis/sentinel.pid"   port 26379   protected-mode no   unixsocket "/var/run/redis/sentinel.sock"   unixsocketperm 700   requirepass <password>   sentinel myid e3e9b126a9a6b17bbf1ccadda0d05315abe1dc28   sentinel deny-scripts-reconfig no   sentinel monitor s6l 10.20.161.181 6379 2   sentinel down-after-milliseconds s6l 10000   sentinel failover-timeout s6l 10000   sentinel auth-pass s6l <password>   sentinel config-epoch s6l 0   sentinel leader-epoch s6l 0   sentinel known-replica s6l 10.20.161.111 6379   sentinel known-replica s6l 10.20.161.80 6379   sentinel current-epoch 0 

      Lưu ý: Cần thay đổi địa chỉ IP tương ứng của bạn vào

  2. Tạo cơ sở dữ liệu vùng chứa trên các nút

Trên các nút tiến hành tạo các container như sau:

  • Tạo container chạy Redis bash docker create --name database --network host \ -v /dev/shm:/dev/shm \ -v /etc/redis/etc/redis \ -v /var/lib/redis:/var/lib/redis \ -v /var/log/redis:/var/log/redis \ -v /var/run/redis:/var/run/redis \ redis:5.0.14 /etc/redis/sentinel.conf
  • Tạo container chạy Sentinel bash docker create --name sentinel --network host \ -v /dev/shm:/dev/shm \ -v /etc/redis/etc/redis \ -v /var/lib/redis:/var/lib/redis \ -v /var/log/redis:/var/log/redis \ -v /var/run/redis:/var/run/redis \ redis:5.0.14 --sentinel /etc/redis/sentinel.conf

4. Kiểm tra kết quả

Thực hiện kết nối tới một máy chủ redis bất kỳ trên cổng 26379

redis-cli -h <ip_address> - p 26379 auth <password>  info sentinel sentinel_masters:1 sentinel_tilt:0 sentinel_running_scripts:0 sentinel_scripts_queue_length:0 sentinel_simulate_failure_flags:0 master0:name=s6l,status=ok,address=10.20.161.181:6379,slaves=2,sentinels=4 

Lúc này, chúng tôi có thể tắt nút chính để kiểm tra quá trình chuyển đổi dự phòng tự động.

Mã ví dụ trong python

import redis  def connect_to_redis_sentinel():   """   Connects to Redis Sentinel.    Returns:     A Redis connection object.   """    sentinel = redis.sentinel.Sentinel([     ('localhost', 26379),     ('localhost', 26380),     ('localhost', 26381),   ])    master = sentinel.master_for('s6l')    return redis.Redis(connection_pool=master)  # Example usage:  redis = connect_to_redis_sentinel()  # Set a value in Redis: redis.set('my_key', 'my_value')  # Get a value from Redis: value = redis.get('my_key')  print(value)
SHARE