前置条件:
1、导入库:
import (
"github.com/go-redis/redis/v8"
)
2、搭建哨兵模式集群
具体可以百度、谷歌搜索,网上现成配置教程太多了,不行还可以搜教程视频,跟着视频博主一步一个慢动作,慢慢整。
本文只介绍通过 “主从架构 / 哨兵模式” 访问的形式,这是因为,单个 redis 服务器在线上正式服务器,真实的生产环境之中是不太现实的。
好的:
1、首先定义一个 RedisClient 结构
type RedisClient struct {
MasterName string
SentinelAddrs []string
Password string
DB int
Client *redis.Client
}
2、其次实现一个 FailoverClient(Redis 哨兵客户端)
func (my *RedisClient) NewFailoverClient() *redis.Client {
sf := &redis.FailoverOptions{
MasterName: my.MasterName, // 主节点名称
SentinelAddrs: my.SentinelAddrs, // 哨兵服务器地址列
Password: my.Password, // 登入密码
DB: my.DB, // 访问那一个DB(从0开始,缺省为0)
}
return redis.NewFailoverClient(sf)
}
Redis 哨兵服务器地址列表:
SentinelAddrs := []string{"172.31.109.138:20000",
"172.31.109.138:20001",
"172.31.109.138:20002"}
注意:
不是 Redis Master / Slaves 服务器地址,是哨兵服务器地址,即通过指定 --sentinel 运行的 redis-server 服务器绑定侦听的 IPEndPoint 地址。
这是因为,哨兵客户端通过链接哨兵服务器来获取当前的 redis-server 信息,如当前的 master 节点地址端点。
同样的主观下线、客观下线,我们并不需要单独进行处理,go-redis 库会自动为我们进行切换,当然,若希望在 go 程式之中捕获 master 节点主观下线事件,可以适用 AddHook 添加钩子方法。
package main
import (
"fmt"
"github.com/go-redis/redis/v8"
)
func main() {
sentinelClient := redis.NewSentinelClient(&redis.Options{
Addr: "sentinel-ip:port",
})
sentinelClient.AddHook(redis.NewFailoverHook(func(oldMaster, newMaster *redis.Client) {
// 处理主观下线事件
fmt.Printf("Master changed from %s to %s\n", oldMaster.Options().Addr, newMaster.Options().Addr)
}))
masterClient := sentinelClient.MasterFor("mymaster", nil)
val, err := masterClient.Get(ctx, "key").Result()
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Value:", val)
}
3、构造 RedisClient 结构体
func NewRedisClient(master_name, password string, addresses []string, db int) *RedisClient {
sentinel := RedisClient{
MasterName: master_name,
SentinelAddrs: addresses,
Password: password,
DB: db,
}
sentinel.Client = sentinel.NewFailoverClient()
return &sentinel
}
4、实现关闭 Redis 客户端接口
func (my *RedisClient) Close() {
client := my.Client
if client != nil {
client.Close()
}
}
5、实现 Ping 函数,测试服务器节点在线与否,但需要注意:多个节点之中若有一个节点反馈OK,都算是成功,所以不要过于信任该函数提供的服务器正常的反馈。
func (my *RedisClient) Close() {
client := my.Client
if client != nil {
client.Close()
}
}
6、Pipeline(管线)
func (my *RedisClient) Pipeline() (redis.Pipeliner, error) {
client := my.Client
if client == nil {
return nil, fmt.Errorf("redis client connect is nil")
}
pipe := client.Pipeline()
return pipe, nil
}
如何调用 Pipeline 管线?它是 Redis 之中一种批量执行写数据操作的机制,即人们可以一次性执行多个SET数据命令,并通过 Pipeline 一次性提交到 redis 服务器进行执行。
例:
// 创建管线
pipeline, err := my.redis.Pipeline()
if err != nil {
return err
}
ctx := context.Background()
err := pipeline.Set(ctx, key, json, time.Second*time.Duration(USER_CACHE_TIMEOUT)).Err()
if err != nil {
return err
}
// 如果设置了命令则执行,否则可以忽略。
bant := true
if bany {
_, err = pipeline.Exec(context.Background())
if err != nil {
return err
}
}