0

Bài 2: Cấu hình Kết nối - Standalone, Redis Sentinel và Redis Cluster

Mục tiêu bài học:

  • Phân biệt rõ 3 mô hình triển khai phổ biến của Redis: Standalone, Sentinel và Cluster.
  • Biết cách sử dụng go-redis để thiết lập kết nối chuẩn xác cho từng mô hình trong môi trường Production.

1. Phân Biệt 3 Mô Hình Redis

Trước khi viết code, bạn cần nắm rõ hệ thống đang sử dụng mô hình nào để gọi đúng Client trong go-redis.

Tiêu chí Standalone (Đơn node) Redis Sentinel (HA) Redis Cluster (Scale + HA)
Bản chất Chạy trên 1 server duy nhất. 1 Master + nhiều Replicas (Slaves) + các node Sentinel giám sát. Phân mảnh dữ liệu (Sharding) trên nhiều node Master/Replica.
Khả năng chịu lỗi (Failover) Không. Master chết là hệ thống dừng. Tự động. Sentinel sẽ bầu Replica lên làm Master mới nếu Master cũ sập. Tự động. Các node tự giao tiếp và bầu Master mới cho phân mảnh bị lỗi.
Mở rộng ghi (Write Scale) Khó mở rộng. Không (Tất cả lệnh Ghi vẫn vào 1 Master). Có. Dữ liệu chia đều cho nhiều Master, tăng tốc độ Ghi.
Loại Client go-redis redis.NewClient() redis.NewFailoverClient() redis.NewClusterClient()
Ứng dụng Môi trường Dev, cache dự án nhỏ. Dự án vừa, cần đảm bảo uptime (High Availability). Hệ thống lớn, traffic cực cao, dữ liệu phình to vượt RAM 1 máy.

2. Cấu Hình Redis Standalone (Nhắc Lại Nhanh)

Đây là mô hình chúng ta đã làm quen ở Bài 1. Sử dụng redis.NewClient.

package main

import "github.com/redis/go-redis/v9"

func initStandaloneClient() *redis.Client {
	return redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // Set mật khẩu nếu có
		DB:       0,
	})
}

3. Cấu Hình Redis Sentinel (Failover Client)

Đối với Sentinel, bạn không kết nối trực tiếp vào node Master. Thay vào đó, bạn kết nối tới các node Sentinel. Thư viện go-redis sẽ tự động hỏi Sentinel xem ai đang là Master hiện tại để định tuyến các lệnh Ghi, và tự động chuyển hướng nếu có sự kiện Failover xảy ra.

package main

import (
	"context"
	"fmt"
	"github.com/redis/go-redis/v9"
)

func initSentinelClient() *redis.Client {
	client := redis.NewFailoverClient(&redis.FailoverOptions{
		MasterName:    "mymaster", // Tên cụm Master (cấu hình trong sentinel.conf)
		SentinelAddrs: []string{
			"192.168.1.10:26379", // Danh sách các node Sentinel
			"192.168.1.11:26379",
			"192.168.1.12:26379",
		},
		Password:      "my-redis-password", // Mật khẩu của node Redis
		// SentinelPassword: "my-sentinel-password", // Bỏ comment nếu Sentinel cũng có mật khẩu
		DB:            0,
	})

	return client
}

func main() {
	rdb := initSentinelClient()
	defer rdb.Close()

	ctx := context.Background()
	if err := rdb.Ping(ctx).Err(); err != nil {
		fmt.Println("Lỗi kết nối Sentinel:", err)
		return
	}
	fmt.Println("Kết nối Sentinel thành công!")
}

4. Cấu Hình Redis Cluster (Cluster Client)

Redis Cluster phân mảnh dữ liệu (sharding) thành 16384 hash slots. Khi dùng Cluster, bạn phải khai báo nhiều địa chỉ node. go-redis sẽ tự động lấy bản đồ hash slots về client và định tuyến key của bạn đến đúng node chứa dữ liệu đó.

Lưu ý: Redis Cluster không hỗ trợ tham số DB (mặc định luôn dùng DB 0).

package main

import (
	"context"
	"fmt"
	"github.com/redis/go-redis/v9"
)

func initClusterClient() *redis.ClusterClient {
	client := redis.NewClusterClient(&redis.ClusterOptions{
		Addrs: []string{
			"127.0.0.1:7000", // Cung cấp một vài node trong Cluster
			"127.0.0.1:7001", // Không nhất thiết phải list toàn bộ
			"127.0.0.1:7002", // go-redis sẽ tự động discover các node còn lại
		},
		Password: "my-cluster-password",

		// Optional: Định tuyến các lệnh Đọc (Read) sang các node Replicas để giảm tải cho Master
		ReadOnly: true, 
		RouteRandomly: true,
	})

	return client
}

func main() {
	rdb := initClusterClient()
	defer rdb.Close()

	ctx := context.Background()

	// Test kết nối bằng cách set 1 key
	err := rdb.Set(ctx, "cluster_key", "hello cluster", 0).Err()
	if err != nil {
		fmt.Println("Lỗi ghi Cluster:", err)
		return
	}
	fmt.Println("Ghi dữ liệu vào Cluster thành công!")
}

💡 Mẹo Chuẩn Production

Ở cả 3 mô hình, thư viện go-redis đều trả về một đối tượng implement interface redis.Cmdable. Nếu bạn viết các hàm repository, hãy nhận vào redis.Cmdable thay vì *redis.Client hay *redis.ClusterClient. Nhờ đó, code của bạn sẽ chạy được trên cả Standalone lẫn Cluster mà không cần sửa lại logic.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí