Go mod 好菜系列 - 0x03 go-redis 不是只有 set/get
从缓存思路讲到 go-redis 的常见 API、过期控制、计数器和项目里最常见的使用方式,避免只会机械 set/get。
一说 Redis,很多人第一反应就是:缓存。再进一步,很多人对 Redis 客户端的理解就只剩 Set、Get。这当然不算错,但如果只停在这里,到了真实业务里你还是会经常不知道“我该怎么把它放进项目”。
go-redis 在项目里通常扮演什么角色
最常见的是这几类:
- 缓存热点数据
- 做计数器
- 存短期状态
- 做简单消息/队列辅助
- 做限流、去重、分布式锁这种工程性工具
但如果是你第一次用,我建议先把第一层吃透:缓存与常用 key 操作。
最基本的客户端初始化
rdb := redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379",
Password: "",
DB: 0,
})
ctx := context.Background()
if err := rdb.Ping(ctx).Err(); err != nil {
return err
}和数据库连接一样,别只创建客户端不验证。你要尽早确认 Redis 真的能连上。
set/get 当然是基础
err := rdb.Set(ctx, "article:1", "hello", 5*time.Minute).Err()
if err != nil {
return err
}
value, err := rdb.Get(ctx, "article:1").Result()
if err != nil {
return err
}
fmt.Println(value)这里最值得注意的是过期时间。很多缓存设计失败,不是因为 Redis 不够快,而是因为 key 生命周期一开始就没想清楚。
计数器也很常见
count, err := rdb.Incr(ctx, "article:1:view_count").Result()
if err != nil {
return err
}
fmt.Println(count)浏览量、点赞数、限流计数,这些都很适合这种原子自增的能力。
不存在和出错要分开理解
新手很容易把“key 不存在”和“Redis 调用失败”混在一起。go-redis 里,key 不存在通常会给你一个特殊错误:redis.Nil。
value, err := rdb.Get(ctx, "not-exist").Result()
if err == redis.Nil {
fmt.Println("key 不存在")
} else if err != nil {
return err
} else {
fmt.Println(value)
}这点非常重要。不存在是正常业务情况,连接失败才是真异常。
缓存回填才是项目里最常见的姿势
func GetArticle(ctx context.Context, id int64) (*Article, error) {
key := fmt.Sprintf("article:%d", id)
data, err := rdb.Get(ctx, key).Result()
if err == nil {
var article Article
if json.Unmarshal([]byte(data), &article) == nil {
return &article, nil
}
}
article, err := repo.FindArticleByID(ctx, id)
if err != nil {
return nil, err
}
raw, _ := json.Marshal(article)
_ = rdb.Set(ctx, key, raw, 10*time.Minute).Err()
return article, nil
}这才是 go-redis 真正在业务里最常见的形态。它不是孤零零存在的,而是夹在 repository 和 service 之间,帮你挡住重复慢查询。
别把所有东西都塞 Redis
Redis 快,不代表它适合装万物。几个常见误区:
- 低频数据也缓存,结果收益极低
- 缓存比数据库还难理解
- 忘记过期策略
- 更新数据库后不处理缓存一致性
Redis 不是“上了就会快”的按钮,它是你系统里又一个需要认真设计的数据层。
小结
go-redis 这道菜看起来朴素,其实在工程里很实用:
- 初始化、连通性验证、错误区分都别省
redis.Nil和真正的异常不是一回事- 缓存回填是最常见的使用方式
- Redis 应该解决具体问题,不是当杂物间
下一篇我们讲 zap。缓存和数据库都能跑起来以后,你会越来越需要日志说人话,而且要足够结构化。