在web开发中,接口慢、数据库压力大,往往不是因为代码不行,而是缺少一个高速缓冲层。Redis就像高速路旁开了一条绿色通道,让你的应用能快速取到最常用的数据,从而大幅提升性能。
文末有源码下载链接
1、为什么要用Redis?
- 1.1 速度极快(基于内存):Redis完全基于内存操作,单次读写能做到微秒级,性能远高于传统数据库。
- 1.2 缓解数据库压力:将热点数据缓存到Redis,避免每次都查询数据库,让数据库专注处理更重要的请求。
- 1.3 天然支持数据过期机制:适合保存(token、验证码、热点业务数据、防刷限流计数)
- 1.4 多种数据结构,灵活强大: string、hash、list、set、zset等,非常适合构建各种类型的缓存和功能
2、在Go应用中集成Redis(基于go-redis v9)
2.1 安装依赖
go get github.com/redis/go-redis/v9
2.2 建立Redis客户端连接
package config
import (
"os"
"github.com/redis/go-redis/v9"
"github.com/spf13/cast"
)
var Redis *redis.Client
func ConnectRedis() {
addr := os.Getenv("REDIS_ADDR")
if addr == "" {
panic("请在环境变量里配置【REDIS_ADDR】")
}
pass := os.Getenv("REDIS_PASS")
if pass == "" {
panic("请在环境变量里配置【REDIS_PASS】")
}
db := os.Getenv("REDIS_DB")
if db == "" {
panic("请在环境变量里配置【REDIS_DB】")
}
Redis = redis.NewClient(&redis.Options{
Addr: addr,
Password: pass,
DB: cast.ToInt(db),
PoolSize: 10,
})
}
2.3 常用的缓存操作示例
2.3.1 写入缓存(带过期时间)
config.Redis.Set(Ctx, "user:1", "Codee君", 5*time.Minute)
2.3.2 读取缓存
author, err := config.Redis.Get(Ctx, "user:1").Result()
2.3.3 删除缓存
config.Redis.Del(Ctx, "user:1")
3、实战:缓存热点数据,提高接口性能
3.1 增加服务services/user.service.go
package services
import (
"context"
"encoding/json"
"fmt"
"gindemo2/config"
"gindemo2/models"
"time"
"github.com/gin-gonic/gin"
)
var (
User *UserService
Ctx context.Context = context.Background()
)
type UserService struct {
}
// 初始化用户服务
func init() {
User = &UserService{}
}
func (s *UserService) GetById(c *gin.Context) (user models.User, err error) {
// 获取上下文传过来的用户id
uid := c.GetUint(`user_id`)
// 组合redis的key
key := fmt.Sprintf("user:%d", uid)
// 从redis里取数据
data, err := config.Redis.Get(Ctx, key).Result()
if err == nil {
// 取到了,反序列化到user里
json.Unmarshal([]byte(data), &user)
return
}
// 没取到,从mysql里取数据
err = config.DB.Where(`id=?`, uid).First(&user).Error
if err != nil {
return
}
// 取到了,序列化数据
btdata, _ := json.Marshal(user)
// 放入redis里
config.Redis.Set(Ctx, key, btdata, time.Hour)
return
}
3.2 修改控制器 controllers/auth.controller.go
// 查询当前登录者的信息
func Me(c *gin.Context) {
user, err := services.User.GetById(c)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
`error`: err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"message": "查询成功",
"user": gin.H{
"id": user.ID,
"username": user.Username,
},
})
}
3.3 查询用户详情
$ curl -X POST http://localhost:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"coding_jun","passwd":"golang"}'
{"message":"登 录 成 功 ","token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJpc3MiOiJDb2RlZeWQmyIsImV4cCI6MTc2MzM4NzEx
OSwiaWF0IjoxNzYzMzAwNzE5fQ.2w1zrlsWz6wja3YTopr7sXdm_yO4KY0yQtmRdVZjHXA","user":{"id":1,"username":"coding_jun"}}
$ curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJpc3MiOiJDb2RlZeWQmyIsImV4cCI6MTc2MzM4N
zExOSwiaWF0IjoxNzYzMzAwNzE5fQ.2w1zrlsWz6wja3YTopr7sXdm_yO4KY0yQtmRdVZjHXA" http://localhost:8080/api/v1/auth/me
{"message":"查 询 成 功 ","user":{"id":1,"username":"coding_jun"}}
两次查询,可以看见只有第一次查询对数据库进行了查询,第二次直接从redis里取,不查库了
[19.601ms] [rows:1] SELECT * FROM `users` WHERE id=1 AND `users`.`deleted_at` IS NULL ORDER BY `users`.`id` LIMIT 1
[GIN] 2025/11/16 - 21:48:48 | 200 | 41.348ms | 127.0.0.1 | GET "/api/v1/auth/me"
[GIN] 2025/11/16 - 21:48:51 | 200 | 17.9949ms | 127.0.0.1 | GET "/api/v1/auth/me"
4、常用优化方式:双写策略、缓存击穿|穿透|雪崩
4.1 双写策略
在操作发生时,同时把数据写入主数据库DB和Redis缓存。通常用于写后读场景,减少后续读操作的缓存未命中。常见方法有:
- 同步双写:事务中先写DB,再写缓存。
- 异步双写:写DB后,开一个协程在后台去更新缓存,写操作后立即返回。
- 禁止先更新缓存再更新DB,可能导致数据不一致问题。
4.2 解决缓存穿透,对不存在的数据不停访问->每次都命中数据库,解决办法:
- Redis设置空值,带短期过期时间,一般为1-5分钟
- 布隆过滤器,把可能存在的合法key预先加载到布隆过滤器中,请求先查布隆过滤器,不存在则直接返回,避免命中DB
4.3 解决缓存击穿, 某一个热点key过期瞬间大量并发访问,全部命中DB,解决办法:
- 加互斥锁,第一个到的人去DB查询并回填缓存,其他请求等待或短轮询。分布式锁(Redis SETNX+expire)
- 请求排队/单飞者(singleflight),并发请求合并,只有一次真实后端查询,结果共享给所有请求。github.com/janos/singl…
- 加随机过期时间,避免集中过期
- 永不过期,不把缓存做到精确TTL过期,而是存入value中包含一个逻辑过期的时间(expire_time)读到过期数据时,返回旧数据,异步调用后台协程刷新缓存
- 短时间内限制并发穿透到DB,熔断器或者限流
4.4 解决缓存雪崩,大量key同时过期,解决办法:
- 给key过期时间+随机值,避免大规模同一时间到期
- 分批更新
- 多级缓存,本地进程内缓存,Redis作为二级缓存
- 降级与限流,当检测到后端承载接近阈值时,降级返回默认值、静态缓存或部分功能降级;同时实行全局限流或熔断
- 预热/主动刷新,应用可以在缓存快到期前主动刷新(延长有效期),后端异步轮询热key做缓存续命 还有哪些有效的优化方案?把你知道的在留言区留下互相学习吧!
源码地址
如果您喜欢这篇文章,请您(点赞、分享、亮爱心),万分感谢!