Go从入门到精通(24) - 一个简单web项目-添加redis缓存

发布于:2025-07-16 ⋅ 阅读:(24) ⋅ 点赞:(0)

Go从入门到精通(24)

一个简单web项目-添加redis缓存



前言

在 Go 语言中使用 Redis 缓存频繁访问的数据,可以显著提升应用性能。

缓存流程说明

查询流程

  • Cache Hit → 直接返回缓存数据
  • Cache Miss → 查询数据库 → 写入缓存 → 返回数据

更新流程

  • 更新数据库 → 删除缓存(而非更新)→ 下次查询时自动刷新

缓存策略

  • 使用 JSON 序列化存储对象
  • 设置 5 分钟过期时间(根据业务需求调整)
  • 采用Read-Through和Write-Invalidate策略

优势

  • 减少数据库压力(高频访问的数据仅第一次查询 DB)
  • 提升响应速度(Redis 读取延迟通常 < 1ms)
  • 支持分布式缓存(多实例共享同一 Redis)

redis使用

安装依赖

go get github.com/go-redis/redis/v8

配置 Redis 连接

// cache/redis.go
package cache

import (
	"context"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/go-redis/redis/v8"
)

var RedisClient redis.UniversalClient
var Ctx = context.Background()

func InitRedis() {
	// 从环境变量获取 Redis 配置
	mode := os.Getenv("REDIS_MODE")
	if mode == "" {
		mode = "single" // 默认单节点模式
	}

	switch mode {
	case "cluster":
		// 集群模式
		addresses := os.Getenv("REDIS_CLUSTER_ADDRESSES")
		if addresses == "" {
			log.Fatal("REDIS_CLUSTER_ADDRESSES 环境变量未设置")
		}

		password := os.Getenv("REDIS_PASSWORD")

		RedisClient = redis.NewClusterClient(&redis.ClusterOptions{
			Addrs:    strings.Split(addresses, ","),
			Password: password,
			// 其他可选配置
			MaxRetries:      3,
			MinRetryBackoff: 8 * time.Millisecond,
			MaxRetryBackoff: 512 * time.Millisecond,
			DialTimeout:     5 * time.Second,
			ReadTimeout:     3 * time.Second,
			WriteTimeout:    3 * time.Second,
			PoolSize:        100,
			MinIdleConns:    20,
		})

	default:
		// 单节点模式
		host := os.Getenv("REDIS_HOST")
		if host == "" {
			host = "localhost"
		}

		port := os.Getenv("REDIS_PORT")
		if port == "" {
			port = "6379"
		}

		password := os.Getenv("REDIS_PASSWORD")
		db, _ := strconv.Atoi(os.Getenv("REDIS_DB"))

		RedisClient = redis.NewClient(&redis.Options{
			Addr:     fmt.Sprintf("%s:%s", host, port),
			Password: password,
			DB:       db,
			// 其他可选配置
			MaxRetries:      3,
			MinRetryBackoff: 8 * time.Millisecond,
			MaxRetryBackoff: 512 * time.Millisecond,
			DialTimeout:     5 * time.Second,
			ReadTimeout:     3 * time.Second,
			WriteTimeout:    3 * time.Second,
			PoolSize:        100,
			MinIdleConns:    20,
		})
	}

	// 测试连接
	if mode == "cluster" {
		_, err := RedisClient.Ping(Ctx).Result()
		if err != nil {
			log.Fatalf("无法连接到 Redis Cluster: %v", err)
		}
		log.Println("Redis Cluster 连接成功")
	} else {
		_, err := RedisClient.Ping(Ctx).Result()
		if err != nil {
			log.Fatalf("无法连接到 Redis: %v", err)
		}
		log.Println("Redis 单节点连接成功")
	}
}

修改用户处理函数添加缓存

func GetCurrentUserHandler(c *gin.Context) {
	userID := c.MustGet("user_id").(string)
	// 1. 先从 Redis 缓存中获取
	cacheKey := fmt.Sprintf("user:%s", userID)
	userJSON, err := cache.RedisClient.Get(cache.Ctx, cacheKey).Result()
	if err == nil {
		// 缓存命中
		var user models.User
		if err := json.Unmarshal([]byte(userJSON), &user); err == nil {
			c.JSON(http.StatusOK, user)
			return
		}
	}

	// 2. 缓存未命中,从数据库获取
	user, exists := users[userID]
	if !exists {
		c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
		return
	}
	// 不返回密码
	user.Password = ""

	// 3. 将数据存入 Redis 缓存(设置 5 分钟过期)
	userByteArray, err := json.Marshal(user)
	if err == nil {
		userJSON = string(userByteArray)
		cache.RedisClient.Set(cache.Ctx, cacheKey, userJSON, 5*time.Minute)
	}

	c.JSON(http.StatusOK, user)
}

//其他方法类似

修改主函数初始化 Redis

    cache.InitRedis()

配置环境变量

# 单节点模式配置
REDIS_MODE=single
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0

# 集群模式配置(覆盖单节点配置)
# REDIS_MODE=cluster
# REDIS_CLUSTER_ADDRESSES=192.168.1.1:6379,192.168.1.2:6379,192.168.1.3:6379
# REDIS_PASSWORD=

网站公告

今日签到

点亮在社区的每一天
去签到