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