Go mod 好菜系列 - 0x03 go-redis 不是只有 set/get

从缓存思路讲到 go-redis 的常见 API、过期控制、计数器和项目里最常见的使用方式,避免只会机械 set/get。

一说 Redis,很多人第一反应就是:缓存。再进一步,很多人对 Redis 客户端的理解就只剩 SetGet。这当然不算错,但如果只停在这里,到了真实业务里你还是会经常不知道“我该怎么把它放进项目”。

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。缓存和数据库都能跑起来以后,你会越来越需要日志说人话,而且要足够结构化。

Read more

Harness Engineering:从驾驭模型到构建 AI 工厂

Harness Engineering:从驾驭模型到构建 AI 工厂

2026 年,AI 编程工具的竞争焦点发生了根本性转变:决定 AI 助手好不好用的,不再是模型本身,而是包裹在模型外面的那层"Harness"。同一个模型,在不同的 Harness 下,性能差距可以达到 78% vs 42%。 这篇文章将带你深入了解 Harness Engineering——这个正在重新定义 AI 工程实践的新兴领域。 一、什么是 Harness Engineering? Harness 的字面意思是"马具/缰绳"——用来驾驭一匹强壮但不受控的马。在 AI 语境下,Harness 就是 LLM 之外的一切:工具定义、记忆系统、权限模型、反馈循环、文档规范、多

By Fuyu Jia

Claude Code CLI + Ralph:让 AI 自动完成大型编程任务的终极方案

TL;DR 当你的编程任务大到一个 AI 对话窗口装不下时,Ralph 会帮你把任务拆成小块,让 Claude Code CLI 一个接一个地自动完成——每轮都用全新的上下文窗口,不会越写越糊涂。 一、什么是 Ralph? Ralph 是一个开源项目(GitHub 16k+ Stars),基于 Geoffrey Huntley 提出的 "Ralph Pattern" 构建。它的核心理念很简单: 不要让 AI 在一个漫长的会话里做完所有事情,而是把大任务拆成小故事,每个故事用一个全新的 AI 实例来完成。 这解决了 AI 编程中最常见的痛点——上下文窗口耗尽。当对话越来越长,AI 的输出质量会明显下降。Ralph 通过「每轮一个新实例」的方式,

By Fuyu Jia