Redis是一种流行的内存键值数据库,被广泛用于构建高性能的缓存和消息队列应用。本文将介绍如何通过go-redis访问redis。
1. 安装依赖
go get github.com/go-redis/redis
golang 如何连接 redis
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379", // redis地址
Password: "", // 密码
DB: 0, // 使用默认数据库
ReadTimeout: 3, // socket读取超时时间, 默认 3s
WriteTimeout: 10, // socket写超时时间
MinRetryBackoff: 10 * time.Second, // 最大重试时间间隔, 默认是 512ms; -1 表示关闭
})
提示:go-redis包自带了连接池,会自动维护redis连接,因此创建一次client即可,不要查询一次redis就关闭client。
Options参数详解
type Options struct {
// 网络类型 tcp 或者 unix.
// 默认是 tcp.
Network string
// redis地址,格式 host:port
Addr string
// 新建一个redis连接的时候,会回调这个函数
OnConnect func(*Conn) error
// redis密码,redis server没有设置可以为空。
Password string
// redis数据库,序号从0开始,默认是0,可以不用设置
DB int
// redis操作失败最大重试次数,默认不重试。
MaxRetries int
// 最小重试时间间隔. 默认是 8ms ; -1 表示关闭.
MinRetryBackoff time.Duration
// 最大重试时间间隔. 默认是 512ms; -1 表示关闭.
MaxRetryBackoff time.Duration
// redis连接超时时间. 默认是 5 秒.
DialTimeout time.Duration
// socket读取超时时间. 默认 3 秒.
ReadTimeout time.Duration
// socket写超时时间
WriteTimeout time.Duration
// redis连接池的最大连接数. 默认连接池大小等于 cpu个数 * 10
PoolSize int
// redis连接池最小空闲连接数.
MinIdleConns int
// redis连接最大的存活时间,默认不会关闭过时的连接.
MaxConnAge time.Duration
// 当你从redis连接池获取一个连接之后,连接池最多等待这个拿出去的连接多长时间。 默认是等待 ReadTimeout + 1 秒.
PoolTimeout time.Duration
// redis连接池多久会关闭一个空闲连接. 默认是 5 分钟. -1 则表示关闭这个配置项
IdleTimeout time.Duration
// 多长时间检测一下,空闲连接. 默认是 1 分钟. -1 表示关闭空闲连接检测
IdleCheckFrequency time.Duration
// 只读设置,如果设置为true, redis只能查询缓存不能更新。
readOnly bool
}
2. 基本的 set、get 操作
package main
import (
"fmt"
"github.com/go-redis/redis"
"time"
)
/**
安装依赖:
go get github.com/go-redis/redis
*/
// 创建redis客户端
func newClient() *redis.Client {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379", // redis地址
Password: "", // 密码
DB: 0, // 使用默认数据库
ReadTimeout: 3, // socket读取超时时间, 默认 3s
WriteTimeout: 10, // socket写超时时间
MinRetryBackoff: 10 * time.Second, // 最大重试时间间隔, 默认是 512ms; -1 表示关闭
})
return client
}
func main() {
// 创建redis客户端
client := newClient()
defer client.Close()
// 设置 key, 第三个参数代表key的过期时间, 0代表不会过期
err := client.Set("name", "john", 0).Err()
if err != nil {
panic(err)
}
// 设置过期时间 key
// err := client.Set("key", "value", 100* time.Second ).Err()
// 获取key
val, err := client.Get("name").Result()
if err != nil {
panic(err)
}
fmt.Println("name", val)
val2, err := rdb.Get("age").Result()
// redis.Nil 表示这个key 在Redis中不存在
if err == redis.Nil {
fmt.Println("key2 does not exists")
} else if err != nil {
panic(err)
} else {
fmt.Println("key2", val2)
}
}
redis.NewClient
创建了一个Redis客户端。然后使用 set方法设置了一个key-value,之后使用get方法获取它的值。 Get的结果可能是redis.Nil
表示这个key 在Redis中不存在。
3. hash 操作
// Set hash field
err := client.HSet( "myhash", "field1", "value1").Err()
if err != nil {
panic(err)
}
// Fetch hash field
val, err := client.HGet("myhash", "field1").Result()
if err != nil {
panic(err)
}
fmt.Println("myhash field1:", val)
// Delete hash field
err = client.HDel( "myhash", "field1").Err()
if err != nil {
panic(err)
}
// Fetch all hash fields
vals, err := client.HGetAll( "myhash").Result()
if err != nil {
panic(err)
}
fmt.Println("myhash:", vals)
4. pubsub发布订阅
package main
import (
"fmt"
"github.com/go-redis/redis"
)
func subscriber(client *redis.Client) {
pubsub := client.Subscribe("mychannel")
defer pubsub.Close()
// 处理订阅接收到的消息
for {
msg, err := pubsub.ReceiveMessage()
if err != nil {
return
}
fmt.Println(msg.Channel, msg.Payload)
}
}
func publisher(client *redis.Client) {
for {
// 发布消息到频道
err := client.Publish("mychannel", "hello").Err()
if err != nil {
panic(err)
}
}
}
func main() {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
go subscriber(client)
go publisher(client)
<-make(chan struct{})
}
使用 go-redis 可以方便地实现发布订阅模型:
- 通过
client.Subscribe
订阅了一个频道,然后在循环里接收消息。 - 另开一个 goroutine发布消息。
5. 消息队列示例
package main
import (
"fmt"
"math/rand"
"time"
"github.com/go-redis/redis"
)
var client *redis.Client
// 初始化连接
func initClient() {
client = redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
}
// 生产者 - 发布消息
func producer() {
for {
message := rand.Intn(1000)
err := client.LPush("queue", message).Err()
if err != nil {
panic(err)
}
fmt.Println("pushed", message)
time.Sleep(1 * time.Second)
}
}
// 消费者 - 处理消息
func consumer(id int) {
for {
message, err := client.BRPop(0, "queue").Result()
if err != nil {
panic(err)
}
fmt.Printf("consumer%d popped %s \n", id, message[1])
time.Sleep(500 * time.Millisecond)
}
}
func main() {
// 初始化
initClient()
// 生产者goroutine
go producer()
// 3个消费者goroutine
for i := 0; i < 3; i++ {
go consumer(i)
}
// 阻塞主goroutine
<-make(chan struct{})
}
使用BRPop实现阻塞式出队,LPush入队,可以构建基于Redis的消息队列。 多个消费者可以共享队列实现负载均衡。
更加详细的redis操作,见下一篇讲解 go-redis 的各种 API 使用。