Golang中Redis缓存的实现位置在哪里
Golang中Redis缓存的实现位置在哪里 在哪里实现Redis缓存最合适? API服务器还是前端?还是两者都需要?
API 将在网页和移动端使用。我认为我需要在各处实现缓存。这样将减少网络调用(如果在前端实现)和数据库调用(如果在 API 中实现)。
更多关于Golang中Redis缓存的实现位置在哪里的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
嗯,这真的取决于你的需求。
首先,你应该在后端层面实现,或者,也许更好的是,在“API网关”层面实现。 一旦你在后端层面有了它,你也可以考虑在前端层面做一些缓存。不过,在那种情况下,我不会为此使用Redis,而只会使用内存缓存。
嗯,Redis是一款只能运行在服务器上的软件,你无法将其交付给浏览器运行,如果这就是你所说的“前端”的话。
同样,运行在浏览器中的JavaScript也无法直接连接到Redis实例。
因此,如果你想将Redis用作缓存,这对其部署位置施加了一些限制。
当然,还有很多其他的缓存策略可供选择,其中一些可以在服务器端使用,另一些则可以在客户端使用。
它们都有各自不同的使用场景、优点和缺点。所有策略都必须处理缓存失效问题,这是计算机科学中两大难题之一……
- 命名
- 缓存失效
- 差一错误
在Golang项目中实现Redis缓存的最佳位置是API服务器层。前端通常不直接与Redis交互,而是通过API服务器作为中介。以下是典型的实现方式:
1. 服务层/业务逻辑层实现
在服务层实现Redis缓存是最常见的做法:
package service
import (
"context"
"encoding/json"
"time"
"github.com/go-redis/redis/v8"
)
type UserService struct {
redisClient *redis.Client
userRepo UserRepository
}
func (s *UserService) GetUserByID(ctx context.Context, userID string) (*User, error) {
cacheKey := "user:" + userID
// 1. 尝试从Redis获取缓存
cachedData, err := s.redisClient.Get(ctx, cacheKey).Result()
if err == nil {
var user User
if err := json.Unmarshal([]byte(cachedData), &user); err == nil {
return &user, nil
}
}
// 2. 缓存未命中,从数据库查询
user, err := s.userRepo.FindByID(ctx, userID)
if err != nil {
return nil, err
}
// 3. 将结果存入Redis缓存
userJSON, _ := json.Marshal(user)
s.redisClient.Set(ctx, cacheKey, userJSON, 10*time.Minute)
return user, nil
}
2. 仓储层(Repository)封装
也可以在仓储层实现缓存逻辑:
package repository
import (
"context"
"encoding/json"
"time"
"github.com/go-redis/redis/v8"
"gorm.io/gorm"
)
type CachedUserRepository struct {
db *gorm.DB
redisClient *redis.Client
}
func (r *CachedUserRepository) FindByID(ctx context.Context, id string) (*User, error) {
cacheKey := "user:" + id
// 检查缓存
cached, err := r.redisClient.Get(ctx, cacheKey).Result()
if err == nil {
var user User
json.Unmarshal([]byte(cached), &user)
return &user, nil
}
// 数据库查询
var user User
if err := r.db.WithContext(ctx).First(&user, "id = ?", id).Error; err != nil {
return nil, err
}
// 设置缓存
userJSON, _ := json.Marshal(user)
r.redisClient.Set(ctx, cacheKey, userJSON, 10*time.Minute)
return &user, nil
}
3. 中间件实现
对于HTTP请求级别的缓存:
package middleware
import (
"context"
"net/http"
"time"
"github.com/go-redis/redis/v8"
)
func RedisCacheMiddleware(redisClient *redis.Client, ttl time.Duration) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cacheKey := "http:" + r.Method + ":" + r.URL.Path
// 只缓存GET请求
if r.Method == http.MethodGet {
cached, err := redisClient.Get(r.Context(), cacheKey).Bytes()
if err == nil {
w.Header().Set("X-Cache", "HIT")
w.Write(cached)
return
}
}
// 缓存未命中,继续处理
recorder := &responseRecorder{ResponseWriter: w}
next.ServeHTTP(recorder, r)
// 缓存响应
if r.Method == http.MethodGet && recorder.status == http.StatusOK {
redisClient.Set(r.Context(), cacheKey, recorder.body, ttl)
}
})
}
}
4. 缓存策略示例
package cache
import (
"context"
"fmt"
"time"
"github.com/go-redis/redis/v8"
)
type CacheManager struct {
client *redis.Client
}
// 带锁的缓存获取,防止缓存击穿
func (cm *CacheManager) GetOrSet(ctx context.Context, key string, ttl time.Duration,
fetchFunc func() (interface{}, error)) (string, error) {
// 尝试获取缓存
val, err := cm.client.Get(ctx, key).Result()
if err == nil {
return val, nil
}
// 获取分布式锁
lockKey := "lock:" + key
locked, err := cm.client.SetNX(ctx, lockKey, "1", 5*time.Second).Result()
if err != nil {
return "", err
}
if locked {
defer cm.client.Del(ctx, lockKey)
// 执行数据获取函数
data, err := fetchFunc()
if err != nil {
return "", err
}
// 序列化并存储
dataStr := fmt.Sprintf("%v", data)
cm.client.Set(ctx, key, dataStr, ttl)
return dataStr, nil
}
// 等待其他goroutine设置缓存
time.Sleep(100 * time.Millisecond)
return cm.client.Get(ctx, key).Result()
}
总结
Redis缓存在Golang中通常在API服务器的服务层或仓储层实现。前端不直接操作Redis,而是通过API接口获取已缓存的数据。这种架构确保了数据一致性和安全性,同时提供了良好的性能优化。

