Redis集成 #

一、Redis安装 #

1.1 安装Redis客户端 #

bash
go get github.com/redis/go-redis/v9

1.2 Redis服务安装 #

bash
# macOS
brew install redis
brew services start redis

# Ubuntu
sudo apt install redis-server
sudo systemctl start redis

# Docker
docker run -d -p 6379:6379 redis

二、Redis连接 #

2.1 基本连接 #

go
package main

import (
    "context"
    "github.com/redis/go-redis/v9"
)

var rdb *redis.Client

func initRedis() error {
    rdb = redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "",
        DB:       0,
    })
    
    ctx := context.Background()
    _, err := rdb.Ping(ctx).Result()
    return err
}

2.2 连接池配置 #

go
rdb = redis.NewClient(&redis.Options{
    Addr:         "localhost:6379",
    Password:     "",
    DB:           0,
    PoolSize:     10,
    MinIdleConns: 5,
    MaxRetries:   3,
    DialTimeout:  5 * time.Second,
    ReadTimeout:  3 * time.Second,
    WriteTimeout: 3 * time.Second,
})

2.3 集群连接 #

go
rdb := redis.NewClusterClient(&redis.ClusterOptions{
    Addrs: []string{
        "redis1:6379",
        "redis2:6379",
        "redis3:6379",
    },
    Password: "password",
})

三、基本操作 #

3.1 Set/Get #

go
ctx := context.Background()

err := rdb.Set(ctx, "key", "value", 0).Err()

val, err := rdb.Get(ctx, "key").Result()
if err == redis.Nil {
    fmt.Println("key does not exist")
}

err := rdb.Set(ctx, "key", "value", 10*time.Minute).Err()

3.2 删除 #

go
rdb.Del(ctx, "key")

rdb.Del(ctx, "key1", "key2", "key3")

3.3 检查存在 #

go
exists, err := rdb.Exists(ctx, "key").Result()

3.4 设置过期时间 #

go
rdb.Expire(ctx, "key", 10*time.Minute)

ttl, err := rdb.TTL(ctx, "key").Result()

3.5 自增/自减 #

go
val, err := rdb.Incr(ctx, "counter").Result()

val, err := rdb.IncrBy(ctx, "counter", 10).Result()

val, err := rdb.Decr(ctx, "counter").Result()

四、数据结构 #

4.1 String #

go
rdb.Set(ctx, "name", "张三", 0)

val, _ := rdb.Get(ctx, "name").Result()

rdb.SetNX(ctx, "key", "value", 10*time.Minute)

rdb.Append(ctx, "key", "append")

val, _ := rdb.GetRange(ctx, "key", 0, 5).Result()

rdb.SetRange(ctx, "key", 0, "new")

rdb.StrLen(ctx, "key")

4.2 Hash #

go
rdb.HSet(ctx, "user:1", "name", "张三")
rdb.HSet(ctx, "user:1", "age", 25)

rdb.HMSet(ctx, "user:1", map[string]interface{}{
    "name":  "张三",
    "email": "zhangsan@example.com",
    "age":   25,
})

val, _ := rdb.HGet(ctx, "user:1", "name").Result()

vals, _ := rdb.HGetAll(ctx, "user:1").Result()

rdb.HDel(ctx, "user:1", "age")

exists, _ := rdb.HExists(ctx, "user:1", "name").Result()

keys, _ := rdb.HKeys(ctx, "user:1").Result()

vals, _ := rdb.HVals(ctx, "user:1").Result()

rdb.HIncrBy(ctx, "user:1", "age", 1)

4.3 List #

go
rdb.LPush(ctx, "list", "a", "b", "c")

rdb.RPush(ctx, "list", "d", "e", "f")

val, _ := rdb.LPop(ctx, "list").Result()

val, _ := rdb.RPop(ctx, "list").Result()

val, _ := rdb.LIndex(ctx, "list", 0).Result()

vals, _ := rdb.LRange(ctx, "list", 0, -1).Result()

rdb.LSet(ctx, "list", 0, "new")

len, _ := rdb.LLen(ctx, "list").Result()

4.4 Set #

go
rdb.SAdd(ctx, "set", "a", "b", "c")

members, _ := rdb.SMembers(ctx, "set").Result()

exists, _ := rdb.SIsMember(ctx, "set", "a").Result()

rdb.SRem(ctx, "set", "a")

len, _ := rdb.SCard(ctx, "set").Result()

rdb.SPop(ctx, "set")

4.5 Sorted Set #

go
rdb.ZAdd(ctx, "zset", redis.Z{Score: 1, Member: "a"})
rdb.ZAdd(ctx, "zset", redis.Z{Score: 2, Member: "b"})

members, _ := rdb.ZRange(ctx, "zset", 0, -1).Result()

members, _ := rdb.ZRangeWithScores(ctx, "zset", 0, -1).Result()

score, _ := rdb.ZScore(ctx, "zset", "a").Result()

rdb.ZRem(ctx, "zset", "a")

rdb.ZIncrBy(ctx, "zset", 1, "a")

len, _ := rdb.ZCard(ctx, "zset").Result()

五、缓存应用 #

5.1 缓存中间件 #

go
func cacheMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
    return func(c echo.Context) error {
        key := "cache:" + c.Request().URL.Path
        
        cached, err := rdb.Get(context.Background(), key).Result()
        if err == nil {
            return c.JSON(http.StatusOK, cached)
        }
        
        return next(c)
    }
}

5.2 缓存函数 #

go
func GetWithCache(ctx context.Context, key string, ttl time.Duration, fn func() (interface{}, error)) (interface{}, error) {
    cached, err := rdb.Get(ctx, key).Result()
    if err == nil {
        return cached, nil
    }
    
    data, err := fn()
    if err != nil {
        return nil, err
    }
    
    rdb.Set(ctx, key, data, ttl)
    
    return data, nil
}

5.3 用户缓存 #

go
type UserCache struct {
    rdb *redis.Client
}

func (c *UserCache) Get(ctx context.Context, id string) (*User, error) {
    key := "user:" + id
    
    data, err := c.rdb.HGetAll(ctx, key).Result()
    if err != nil {
        return nil, err
    }
    
    if len(data) == 0 {
        return nil, redis.Nil
    }
    
    user := &User{
        ID:    data["id"],
        Name:  data["name"],
        Email: data["email"],
    }
    
    return user, nil
}

func (c *UserCache) Set(ctx context.Context, user *User) error {
    key := "user:" + user.ID
    
    return c.rdb.HMSet(ctx, key, map[string]interface{}{
        "id":    user.ID,
        "name":  user.Name,
        "email": user.Email,
    }).Err()
}

func (c *UserCache) Delete(ctx context.Context, id string) error {
    key := "user:" + id
    return c.rdb.Del(ctx, key).Err()
}

六、会话存储 #

6.1 Session存储 #

go
type SessionStore struct {
    rdb *redis.Client
}

func (s *SessionStore) Set(ctx context.Context, sessionID string, userID string, ttl time.Duration) error {
    return s.rdb.Set(ctx, "session:"+sessionID, userID, ttl).Err()
}

func (s *SessionStore) Get(ctx context.Context, sessionID string) (string, error) {
    return s.rdb.Get(ctx, "session:"+sessionID).Result()
}

func (s *SessionStore) Delete(ctx context.Context, sessionID string) error {
    return s.rdb.Del(ctx, "session:"+sessionID).Err()
}

6.2 认证中间件 #

go
func authMiddleware(store *SessionStore) echo.MiddlewareFunc {
    return func(next echo.HandlerFunc) echo.HandlerFunc {
        return func(c echo.Context) error {
            sessionID := c.Cookie("session")
            if sessionID == nil {
                return echo.NewHTTPError(http.StatusUnauthorized, "请登录")
            }
            
            ctx := context.Background()
            userID, err := store.Get(ctx, sessionID.Value)
            if err != nil {
                return echo.NewHTTPError(http.StatusUnauthorized, "会话已过期")
            }
            
            c.Set("userID", userID)
            
            return next(c)
        }
    }
}

七、限流 #

7.1 令牌桶限流 #

go
func rateLimitMiddleware(rdb *redis.Client, limit int, window time.Duration) echo.MiddlewareFunc {
    return func(next echo.HandlerFunc) echo.HandlerFunc {
        return func(c echo.Context) error {
            key := "ratelimit:" + c.RealIP()
            ctx := context.Background()
            
            count, err := rdb.Incr(ctx, key).Result()
            if err != nil {
                return err
            }
            
            if count == 1 {
                rdb.Expire(ctx, key, window)
            }
            
            if count > int64(limit) {
                return echo.NewHTTPError(http.StatusTooManyRequests, "请求过于频繁")
            }
            
            return next(c)
        }
    }
}

八、完整示例 #

go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "net/http"
    "time"
    "github.com/labstack/echo/v4"
    "github.com/labstack/echo/v4/middleware"
    "github.com/redis/go-redis/v9"
)

type User struct {
    ID    string `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

var rdb *redis.Client

func initRedis() error {
    rdb = redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "",
        DB:       0,
    })
    
    ctx := context.Background()
    _, err := rdb.Ping(ctx).Result()
    return err
}

func main() {
    if err := initRedis(); err != nil {
        panic(err)
    }
    
    e := echo.New()
    
    e.Use(middleware.Logger())
    e.Use(middleware.Recover())
    
    e.Use(rateLimitMiddleware(rdb, 100, time.Minute))
    
    e.GET("/users/:id", getUser)
    e.POST("/users", createUser)
    e.DELETE("/users/:id", deleteUser)
    e.POST("/login", login)
    
    e.Logger.Fatal(e.Start(":8080"))
}

func rateLimitMiddleware(rdb *redis.Client, limit int, window time.Duration) echo.MiddlewareFunc {
    return func(next echo.HandlerFunc) echo.HandlerFunc {
        return func(c echo.Context) error {
            key := "ratelimit:" + c.RealIP()
            ctx := context.Background()
            
            count, err := rdb.Incr(ctx, key).Result()
            if err != nil {
                return next(c)
            }
            
            if count == 1 {
                rdb.Expire(ctx, key, window)
            }
            
            if count > int64(limit) {
                return echo.NewHTTPError(http.StatusTooManyRequests, "请求过于频繁")
            }
            
            return next(c)
        }
    }
}

func getUser(c echo.Context) error {
    id := c.Param("id")
    ctx := context.Background()
    
    key := "user:" + id
    data, err := rdb.Get(ctx, key).Result()
    if err == nil {
        var user User
        json.Unmarshal([]byte(data), &user)
        return c.JSON(http.StatusOK, user)
    }
    
    user := User{
        ID:    id,
        Name:  "张三",
        Email: "zhangsan@example.com",
    }
    
    jsonData, _ := json.Marshal(user)
    rdb.Set(ctx, key, jsonData, 10*time.Minute)
    
    return c.JSON(http.StatusOK, user)
}

func createUser(c echo.Context) error {
    user := new(User)
    if err := c.Bind(user); err != nil {
        return err
    }
    
    ctx := context.Background()
    key := "user:" + user.ID
    
    jsonData, _ := json.Marshal(user)
    rdb.Set(ctx, key, jsonData, 10*time.Minute)
    
    return c.JSON(http.StatusCreated, user)
}

func deleteUser(c echo.Context) error {
    id := c.Param("id")
    ctx := context.Background()
    
    rdb.Del(ctx, "user:"+id)
    
    return c.NoContent(http.StatusNoContent)
}

func login(c echo.Context) error {
    type LoginForm struct {
        Username string `json:"username"`
        Password string `json:"password"`
    }
    
    form := new(LoginForm)
    if err := c.Bind(form); err != nil {
        return err
    }
    
    if form.Username != "admin" || form.Password != "password" {
        return echo.NewHTTPError(http.StatusUnauthorized, "用户名或密码错误")
    }
    
    sessionID := fmt.Sprintf("%d", time.Now().UnixNano())
    ctx := context.Background()
    
    rdb.Set(ctx, "session:"+sessionID, form.Username, 24*time.Hour)
    
    cookie := &http.Cookie{
        Name:    "session",
        Value:   sessionID,
        Path:    "/",
        Expires: time.Now().Add(24 * time.Hour),
    }
    c.SetCookie(cookie)
    
    return c.JSON(http.StatusOK, map[string]string{
        "message": "登录成功",
    })
}

九、总结 #

Redis集成要点:

要点 说明
连接 redis.NewClient()
String Set/Get/Del
Hash HSet/HGet/HGetAll
List LPush/RPush/LPop/RPop
Set SAdd/SMembers/SRem
Sorted Set ZAdd/ZRange/ZRem
缓存 Set/Get with TTL
会话 Session存储
限流 Incr/Expire

准备好学习高级特性了吗?让我们进入下一章!

最后更新:2026-03-28