go-redis笔记

go-redis笔记

go-redis 是 Go 语言中用于操作 Redis 数据库的流行客户端库。以下是学习和使用 go-redis 时需要掌握的 必学知识点,涵盖核心概念、常用功能和最佳实践:


1. 基础知识

(1) 安装和引入

  • 安装:使用以下命令安装 go-redis 库:

    1
    go get github.com/redis/go-redis/v9
  • 引入:在代码中引入库:

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

(2) 连接 Redis

  • 创建客户端:通过 redis.NewClient 创建 Redis 客户端。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    import (
    "context"
    "github.com/redis/go-redis/v9"
    )

    func main() {
    ctx := context.Background()
    rdb := redis.NewClient(&redis.Options{
    Addr: "localhost:6379", // Redis 地址
    Password: "", // 密码(若无则为空)
    DB: 0, // 数据库编号
    })
    defer rdb.Close()

    // 测试连接
    _, err := rdb.Ping(ctx).Result()
    if err != nil {
    panic(err)
    }
    }
  • 关键配置

    • Addr:Redis 服务器地址(格式为 host:port)。
    • Password:认证密码。
    • DB:选择 Redis 数据库(默认 0)。
    • PoolSize:连接池大小,控制并发连接数。
    • MaxRetries:失败重试次数。
    • DialTimeout / ReadTimeout / WriteTimeout:超时设置。

(3) 上下文(Context)

  • go-redis 使用 Go 的 context.Context 控制请求的生命周期,确保操作可取消或设置超时。
  • 推荐始终传递 context.Background() 或自定义的 context.WithTimeout

2. 核心操作

(1) 基本数据操作

  • 字符串(String)

    • 设置:Set(ctx, key, value, expiration)expiration 为过期时间(0 表示永不过期)。

      1
      err := rdb.Set(ctx, "key", "value", 0).Err()
    • 获取:Get(ctx, key)

      1
      val, err := rdb.Get(ctx, "key").Result()
  • 列表(List)

    • 推入:LPush / RPush

      1
      rdb.LPush(ctx, "list", "item1", "item2")
    • 弹出:LPop / RPop

  • 哈希(Hash)

    • 设置字段:HSet

      1
      rdb.HSet(ctx, "hash", "field", "value")
    • 获取字段:HGet / HGetAll

  • 集合(Set)

    • 添加:SAdd
    • 获取成员:SMembers
  • 有序集合(ZSet)

    • 添加:ZAdd

      1
      rdb.ZAdd(ctx, "zset", redis.Z{Score: 1.0, Member: "member"})
    • 范围查询:ZRange / ZRevRange

(2) 批量操作

  • Pipeline:将多个命令放入管道,减少网络往返。

    1
    2
    3
    4
    pipe := rdb.Pipeline()
    pipe.Set(ctx, "key1", "value1", 0)
    pipe.Set(ctx, "key2", "value2", 0)
    _, err := pipe.Exec(ctx)
  • Transaction(事务):使用 TxPipelineMULTI / EXEC 实现事务。

    1
    2
    3
    4
    pipe := rdb.TxPipeline()
    pipe.Set(ctx, "key1", "value1", 0)
    pipe.Set(ctx, "key2", "value2", 0)
    _, err := pipe.Exec(ctx)

(3) 发布/订阅(Pub/Sub)

  • 订阅消息

    1
    2
    3
    4
    sub := rdb.Subscribe(ctx, "channel")
    for msg := range sub.Channel() {
    fmt.Println(msg.Channel, msg.Payload)
    }
  • 发布消息

    1
    rdb.Publish(ctx, "channel", "message")

(4) 过期时间和键管理

  • 设置过期时间:Expire(ctx, key, duration)
  • 检查键存在:Exists(ctx, key)
  • 删除键:Del(ctx, key)

3. 高级功能

(1) 连接池管理

  • go-redis 内置连接池,合理配置 PoolSizeMinIdleConns
  • 使用 rdb.Close() 关闭客户端释放资源。

(2) 错误处理

  • go-redis 的方法返回 *redis.Cmd,通过 .Err() 检查错误。
  • 常见错误:
    • redis.Nil:键不存在。
    • 网络超时或连接断开错误。

(3) 集群支持

  • 对于 Redis Cluster,使用 redis.NewClusterClient

    1
    2
    3
    rdb := redis.NewClusterClient(&redis.ClusterOptions{
    Addrs: []string{"node1:6379", "node2:6379"},
    })

(4) Lua 脚本

  • 执行 Lua 脚本以实现原子操作:

    1
    2
    3
    4
    script := redis.NewScript(`
    return redis.call('SET', KEYS[1], ARGV[1])
    `)
    err := script.Run(ctx, rdb, []string{"key"}, "value").Err()

(5) 分布式锁

  • 使用 Redis 实现分布式锁(推荐使用 SETNX 或 Redlock 算法):

    1
    2
    3
    4
    5
    success, err := rdb.SetNX(ctx, "lock", "value", 10*time.Second).Result()
    if success {
    // 获取锁成功
    defer rdb.Del(ctx, "lock")
    }

4. 最佳实践

(1) 错误处理

  • 始终检查 .Err(),并根据业务逻辑处理 redis.Nil 等错误。
  • 使用 context 设置超时,避免请求挂起。

(2) 连接管理

  • 避免频繁创建/关闭客户端,复用单一客户端实例。
  • 配置合理的连接池参数(如 PoolSize)以应对高并发。

(3) 性能优化

  • 使用 Pipeline 或事务减少网络开销。
  • 批量操作代替多次单次操作(如 MSet / MGet)。

(4) 监控和调试

  • 启用 OnConnect 回调监控连接状态。

    1
    2
    3
    4
    5
    6
    7
    rdb := redis.NewClient(&redis.Options{
    Addr: "localhost:6379",
    OnConnect: func(ctx context.Context, cn *redis.Conn) error {
    fmt.Println("Connected to Redis")
    return nil
    },
    })
  • 使用 Redis 的 INFO 命令或外部工具(如 RedisInsight)监控性能。

(5) 安全性

  • 配置密码(Password)和 TLS(TLSConfig)以保护数据。
  • 避免在生产环境中使用默认配置。

5. 常见问题和注意事项

  • 空值处理Get 操作可能返回 redis.Nil,需显式检查。
  • 并发安全:go-redis 客户端是线程安全的,但单个命令不是原子操作,需使用事务或 Lua 脚本。
  • 版本兼容:go-redis/v9 是最新版本,注意与 Redis 服务器版本兼容。
  • 超时设置:合理配置 DialTimeoutReadTimeoutWriteTimeout,避免请求阻塞。

6. 学习资源


7. 扩展学习

  • Redlock 算法:学习分布式锁的高级实现。
  • Redis Streams:处理流式数据(go-redis 支持 XAddXRead 等)。
  • 高可用性:学习 Redis Sentinel 和 Cluster 的配置与使用。
  • 性能测试:使用工具(如 redis-benchmark)测试 go-redis 性能。

示例:完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package main

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

func main() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
defer rdb.Close()

// 设置键值
err := rdb.Set(ctx, "key", "value", 10*time.Second).Err()
if err != nil {
panic(err)
}

// 获取键值
val, err := rdb.Get(ctx, "key").Result()
if err == redis.Nil {
fmt.Println("Key does not exist")
} else if err != nil {
panic(err)
} else {
fmt.Println("Key:", val)
}

// Pipeline 示例
pipe := rdb.Pipeline()
pipe.Set(ctx, "key1", "value1", 0)
pipe.Set(ctx, "key2", "value2", 0)
_, err = pipe.Exec(ctx)
if err != nil {
panic(err)
}
}

[up主专用,视频内嵌代码贴在这]