如果你以为只会用 set 和 get 就能自称 Redis 高手,那简直是对 Redis 的能力有点大不敬,哈哈。
Redis 是目前广泛使用的 NoSQL 数据库之一,凭借其强大的数据结构、内存操作性能和丰富的特性,成为许多高性能应用的首选。
对于 Go 语言的开发者,go-redis/redis
提供了一个功能全面且高效的 Redis 客户端库,支持 Redis 的所有操作。
在这篇文章中将会介绍如何使用 go-redis/redis
,探索它的所有特性,并提供丰富的示例代码,帮助大家更好地掌握并使用它,好了,下面直接开始。
1. 安装 go-redis
可以使用以下命令安装:
go get github.com/go-redis/redis/v8
2. 基本连接
你可以通过 redis.NewClient 方法创建 Redis 客户端。
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
)
var ctx = context.Background()
func main() {
// 创建 Redis 客户端
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379", // Redis 地址
Password: "", // Redis 密码
DB: 0, // 使用默认数据库
})
// 测试连接
pong, err := rdb.Ping(ctx).Result()
if err != nil {
fmt.Println("无法连接到 Redis:", err)
} else {
fmt.Println("连接成功:", pong)
}
}
3. 基本 Redis 操作
设置键值对:SET
err := rdb.Set(ctx, "key", "value", 0).Err()
if err != nil {
fmt.Println("设置键值对失败:", err)
}
获取键值:GET
val, err := rdb.Get(ctx, "key").Result()
if err != nil {
fmt.Println("获取键值失败:", err)
} else {
fmt.Println("键值为:", val)
}
删除键:DEL
err := rdb.Del(ctx, "key").Err()
if err != nil {
fmt.Println("删除键失败:", err)
}
4. 键过期时间
在 Redis 中,可以为键设置过期时间。
你可以使用 Set 方法中的第三个参数来指定键的过期时间,或者使用 Expire 方法单独设置过期时间。
设置键值和过期时间:
// 设置键值并设置过期时间为10秒
err := rdb.Set(ctx, "key", "value", 10*time.Second).Err()
手动设置过期时间:
err := rdb.Expire(ctx, "key", 10*time.Second).Err()
5. Redis 数据结构操作
Redis 支持多种数据结构,如字符串、列表、集合、哈希和有序集合等。
字符串操作:
rdb.Set(ctx, "name", "John", 0) // 设置字符串值
name, _ := rdb.Get(ctx, "name").Result() // 获取字符串值
fmt.Println("Name:", name)
列表操作:
rdb.RPush(ctx, "list", "item1") // 向列表右侧推入元素
rdb.LPush(ctx, "list", "item2") // 向列表左侧推入元素
items, _ := rdb.LRange(ctx, "list", 0, -1).Result() // 获取列表中的所有元素
fmt.Println("List items:", items)
集合操作:
rdb.SAdd(ctx, "set", "member1", "member2") // 向集合添加元素
members, _ := rdb.SMembers(ctx, "set").Result() // 获取集合中的所有成员
fmt.Println("Set members:", members)
哈希操作:
rdb.HSet(ctx, "hash", "field1", "value1") // 设置哈希字段
val, _ := rdb.HGet(ctx, "hash", "field1").Result() // 获取哈希字段的值
fmt.Println("Hash field:", val)
有序集合操作:
rdb.ZAdd(ctx, "zset", &redis.Z{Score: 1, Member: "member1"}) // 添加有序集合元素
zrange, _ := rdb.ZRangeWithScores(ctx, "zset", 0, -1).Result() // 获取有序集合元素
fmt.Println("ZSet elements:", zrange)
6. Redis 事务(Transactions)
go-redis 提供了对 Redis 事务的支持。
通过 Watch 和 TxPipelined 你可以实现多操作事务。
err := rdb.Watch(ctx, func(tx *redis.Tx) error {
// 获取 key 的当前值
n, err := tx.Get(ctx, "counter").Int()
if err != nil && err != redis.Nil {
return err
}
// 事务操作:增加 key 的值
_, err = tx.Pipelined(ctx, func(pipe redis.Pipeliner) error {
pipe.Set(ctx, "counter", n+1, 0)
return nil
})
return err
}, "counter")
7. 管道(Pipelining)
管道是一种优化 Redis 性能的方式,通过将多个命令一起发送,而不是逐个发送命令,减少网络延迟。
pipe := rdb.Pipeline()
pipe.Set(ctx, "key1", "value1", 0)
pipe.Set(ctx, "key2", "value2", 0)
_, err := pipe.Exec(ctx)
8. 发布与订阅(Pub/Sub)
// 订阅频道
pubsub := rdb.Subscribe(ctx, "channel1")
// 发布消息
rdb.Publish(ctx, "channel1", "hello")
// 接收订阅消息
msg, err := pubsub.ReceiveMessage(ctx)
fmt.Println("Received message:", msg.Payload)
9. 事务管道(Transaction Pipelining)
通过事务管道,你可以将多个事务命令打包在一起,减少交互延迟,同时保持事务的原子性。
pipe := rdb.TxPipeline()
pipe.Set(ctx, "key1", "value1", 0)
pipe.Set(ctx, "key2", "value2", 0)
_, err := pipe.Exec(ctx)
10. Lua 脚本支持
go-redis 允许你直接在 Redis 中执行 Lua 脚本。
script := redis.NewScript(`
return redis.call('SET', KEYS[1], ARGV[1])
`)
result, err := script.Run(ctx, rdb, []string{"key1"}, "value1").Result()
fmt.Println("Script result:", result)
11. Redis 流(Streams)
Redis 流是 Redis 5.0 引入的一种新的数据结构,适合处理消息流和事件数据。
// 添加流数据
rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "mystream",
Values: map[string]interface{}{"name": "John"},
})
// 读取流数据
entries, _ := rdb.XRange(ctx, "mystream", "-", "+").Result()
for _, entry := range entries {
fmt.Println("Stream entry:", entry)
}
12. 分布式锁
可以使用 SET 命令实现简单的分布式锁,或者使用 Redlock 算法实现更复杂的分布式锁机制。
// 尝试获取锁
ok, err := rdb.SetNX(ctx, "mylock", "locked", 10*time.Second).Result()
if ok {
fmt.Println("获取锁成功")
} else {
fmt.Println("锁已存在")
}
13. Redis 集群支持
可以通过 redis.NewClusterClient 来连接到 Redis 集群。
rdb := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{"localhost:7000", "localhost:7001", "localhost:7002"},
})
pong, err := rdb.Ping(ctx).Result()
fmt.Println(pong, err)
14. Redis 哨兵支持
可以通过 redis.NewFailoverClient 创建哨兵客户端。
rdb := redis.NewFailoverClient(&redis.FailoverOptions{
MasterName: "mymaster",
SentinelAddrs: []string{"localhost:26379", "localhost:26380"},
})
15. 自定义重试机制
提供了自动重试机制,并允许自定义重试次数和策略。
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
MaxRetries: 5, // 最大重试 5 次
MinRetryBackoff: 10 * time.Millisecond, // 最小重试等待时间
MaxRetryBackoff: 500 * time.Millisecond, // 最大重试等待时间
})
16. 性能监控与指标
可以通过 Redis 的 INFO 命令获取服务器的运行状态和性能指标。
info, err := rdb.Info(ctx, "all").Result()
fmt.Println("Redis Info:", info)
17. Redis 键扫描
通过 SCAN、SSCAN、HSCAN 和 ZSCAN 命令,你可以高效地遍历 Redis 数据,而不会阻塞服务器。
var cursor uint64
var keys []string
for {
keys, cursor, err = rdb.Scan(ctx, cursor, "*", 10).Result()
if err != nil {
break
}
for _, key := range keys {
fmt.Println("Scanned key:", key)
}
if cursor == 0 {
break
}
}
18. HyperLogLog 操作
Redis 提供了 HyperLogLog 数据结构,用于估算不重复元素的基数。
// 添加元素到 HyperLogLog
err := rdb.PFAdd(ctx, "hll", "item1", "item2", "item3").Err()
// 获取 HyperLogLog 中的基数估算值
count, err := rdb.PFCount(ctx, "hll").Result()
fmt.Println("HyperLogLog 基数:", count)
19. Bitmaps 操作
Redis 支持位图(Bitmaps)操作。
// 设置键的第 7 位为 1
err := rdb.SetBit(ctx, "bitmap_key", 7, 1).Err()
// 获取键的第 7 位的值
bit, err := rdb.GetBit(ctx, "bitmap_key", 7).Result()
fmt.Println("第 7 位的值:", bit)
20. 地理位置(Geo)操作
Redis 支持 GEO 操作,允许你存储、查询地理坐标和进行地理位置相关的操作,例如计算距离、查找附近的点等。
// 添加地理位置
_, err := rdb.GeoAdd(ctx, "locations", &redis.GeoLocation{
Name: "Beijing",
Longitude: 116.4075,
Latitude: 39.9042,
}).Result()
// 计算两个地点之间的距离
distance, err := rdb.GeoDist(ctx, "locations", "Beijing", "Shanghai", "km").Result()
fmt.Println("北京到上海的距离(公里):", distance)
// 查找某个地点附近的地理位置
nearby, err := rdb.GeoRadius(ctx, "locations", 116.4075, 39.9042, &redis.GeoRadiusQuery{
Radius: 100,
Unit: "km",
WithCoord: true,
WithDist: true,
WithHash: true,
Count: 10,
Sort: "ASC",
}).Result()
for _, loc := range nearby {
fmt.Printf("地点: %s 距离: %fkm\n", loc.Name, loc.Dist)
}
21. 自定义命令
允许发送自定义的 Redis 命令,适用于 Redis 中某些特殊或不常用的操作。
// 使用 Do 方法发送任意 Redis 命令
result, err := rdb.Do(ctx, "SET", "custom_key", "custom_value").Result()
fmt.Println("自定义命令结果:", result)
22. 自动连接池管理
提供了自动的连接池管理功能。
通过 Options 你可以配置最大连接数、空闲连接数以及连接池的行为。
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
PoolSize: 20, // 最大连接数
MinIdleConns: 5, // 最小空闲连接数
IdleTimeout: 5 * time.Minute, // 空闲连接超时时间
})
23. 延迟监控(Latency Monitor)
Redis 提供了延迟监控功能,可以通过 LATENCY LATEST 命令查看最新的延迟情况。
latency, err := rdb.Do(ctx, "LATENCY", "LATEST").Result()
fmt.Println("Redis 延迟监控:", latency)
24. Redis Stream 消费组
Redis 的 Stream 数据结构提供了消费组(Consumer Groups)功能,用于实现类似 Kafka 的消息队列消费模型。
// 创建消费组
err := rdb.XGroupCreateMkStream(ctx, "mystream", "mygroup", "0").Err()
// 消费组读取消息
msgs, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{
Group: "mygroup",
Consumer: "consumer1",
Streams: []string{"mystream", ">"},
Count: 10,
Block: 0,
}).Result()
for _, msg := range msgs[0].Messages {
fmt.Printf("消息 ID: %s, 值: %v\n", msg.ID, msg.Values)
}
25. 集群模式高级操作
提供了自动路由和高级操作支持。
rdb := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{"localhost:7000", "localhost:7001", "localhost:7002"},
})
// 在集群模式下设置和获取值
err := rdb.Set(ctx, "key_in_cluster", "value", 0).Err()
val, err := rdb.Get(ctx, "key_in_cluster").Result()
fmt.Println("集群键值:", val)
26. 超时与取消请求
通过 Go 的 context.Context,go-redis 支持请求的超时和取消功能,确保在 Redis 响应过慢或出现异常时,及时取消请求,避免资源浪费。
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
_, err := rdb.Get(ctx, "somekey").Result()
if err == context.DeadlineExceeded {
fmt.Println("请求超时")
} else if err != nil {
fmt.Println("其他错误:", err)
}
27. 多主模式支持
支持 Redis 的多主模式(multi-master mode),特别适用于高可用架构下的主从复制(Master-Slave Replication)以及 Redis Sentinel 的故障转移(Failover)。
rdb := redis.NewFailoverClient(&redis.FailoverOptions{
MasterName: "mymaster",
SentinelAddrs: []string{"localhost:26379", "localhost:26380"},
})
// 使用哨兵管理主从模式下的连接
val, err := rdb.Get(ctx, "somekey").Result()
fmt.Println("从主服务器获取的值:", val)
28. 自定义 Hook
支持自定义钩子(Hook),可以在请求之前或之后执行自定义逻辑。
常用于日志记录、性能监控或自定义业务逻辑。
type customHook struct{}
func (h customHook) BeforeProcess(ctx context.Context, cmd redis.Cmder) (context.Context, error) {
fmt.Println("即将执行命令:", cmd)
return ctx, nil
}
func (h customHook) AfterProcess(ctx context.Context, cmd redis.Cmder) error {
fmt.Println("命令执行完成:", cmd)
return nil
}
rdb.AddHook(customHook{})
不得不说,这个 go-redis 真的是太全面了!
无论你是在开发小型项目,还是处理大规模分布式系统,go-redis 都是一个高效、强大且易于使用的解决方案。
在我封装的框架中,Redis 客户端使用的正是 go-redis。
可点击下方👇关注公众号