go-redis

redis go

记录在使用go-redis中的代码细节以及个人理解。

介绍

go-redis是支持Redis Server和Redis Cluster的Golang客户端,中文官方链接:https://redis.uptrace.dev/zh/

Quick Start( .go)

redis已在"localhost:6379"启动且遵循默认配置。通过以下代码块建立连接,返回rdb句柄。

rdb := redis.NewClient(&redis.Options{
    Addr:     "localhost:6379",
    Password: "", // no password set
    DB:       0,  // use default DB
})

而通过NewClient返回的rdb相关结构如下:

type Client struct {
	*baseClient
	cmdable
	hooksMixin
}
type baseClient struct {
	opt      *Options
	connPool pool.Pooler
	onClose func() error // hook called when client is closed
}
/ Options keeps the settings to set up redis connection.
type Options struct {
	Network string	// The network type, either tcp or unix.// Default is tcp.	
	Addr string// host:port address.
	ClientName string// ClientName will execute the `CLIENT SETNAME ClientName` command for each conn.
    ...
}

主要涉及options中的连接配置,如地址、密码、连接数,当然也支持拼接连接方式,只不过扩展性有限。

opt, err := redis.ParseURL("redis://<user>:<pass>@localhost:6379/<db>")
if err != nil {
	panic(err)
}
rdb := redis.NewClient(opt)

类似于redis-cli提供的GET/SET/HMSET/HGET等方法,go-redis也提供类似方法,如下分别增加并获取string/hash数据:

var ctx = context.Background() //empty context with nothing
err := rdb.Set(ctx, "key", "value", 0).Err()
if err != nil {
    panic(err)
}
//val, err := rdb.Do(ctx, "get", "key").Text() 该方法与下行等效
val, err := rdb.Get(ctx, "key").Result()
if err != nil {
    panic(err)
}
fmt.Println("key 's value:", val)
//输出:key 's value: value
val2, err := rdb.Get(ctx, "key2").Result()
if err == redis.Nil {
    fmt.Println("key2 does not exist")
} else if err != nil {
    panic(err)
} else {
    fmt.Println("key2's value:", val2)
}
//输出:key2 does not exist
err3 := rdb.HSet(ctx, "T1Y", "field1", "T", "field2", "Y").Err()
if err3 != nil {
    panic(err)
} else {
    fmt.Println("Hash insert OK")
}
val3, err := rdb.HGet(ctx, "T1Y", "field1").Result()
//val4, err := rdb.HGetAll(ctx, "T1Y").Result()
if err != nil {
    fmt.Println("err accur:", err)
} else {
    fmt.Println(val3)
}
//输出:Hello
//GetALL可以输出map[field1:Hello field2:World]

特别的,也可使用.Do达到类似接近使用命令行cmd操作redis的效果,如欲获取“key”对应的value值,可以如下表达:

//等效写法/等效于 val, err := rdb.Get(ctx, "key").Result()
val, err := rdb.Do(ctx, "get", "key").Text()

此外内置格式转换,看起来还是非常灵活的。

性能分析

redis因其高qps为主要特征,因此尝试以go-redis编写一个测试程序,具体代码如下:

package main
import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/go-redis/redis/v8"
)
var (
	Pool     *redis.Client  //连接池
	oSynWait sync.WaitGroup //互斥锁
)
const (
	OnMaxRun   = 10000                    //单线程执行命令数
	AllMaxRun  = 50                       //并发数
	TimeFormat = "2006-01-02 15:04:05.99" //时间格式
	Type       = "set"                    //指令类型
)
func main() {
	fmt.Println("---开始redis压力测试---")
	GetPool()
	OldTime := time.Now()
	fmt.Println("开始", OldTime.Format(TimeFormat))

	oSynWait.Add(AllMaxRun)
	for i := 0; i < AllMaxRun; i++ {
		go ReadWriteInfo()
	}
	oSynWait.Wait()

	EndTime := time.Now()
	fmt.Println("结束", EndTime.Format(TimeFormat))
	fmt.Printf("并发数: %d ;总数据量:%d ;耗时: %.2fs ;\n类型:%s ;key:1;value:1;\nqps:%.0f\n",
		AllMaxRun, AllMaxRun*OnMaxRun, EndTime.Sub(OldTime).Seconds(), Type, AllMaxRun*OnMaxRun/time.Since(OldTime).Seconds())
	fmt.Println("---测试结束-")
}
// 取得一个连接池
func GetPool() {
	Pool = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
		PoolSize: AllMaxRun,  //默认情况下, go-redis 连接池大小为 runtime.GOMAXPROCS * 10 // runtime.GOMAXPROCS(1)
	})
}
// 存放数据
func ReadWriteInfo() {
	ctx := context.TODO()
	defer oSynWait.Done()
	for i := 0; i < OnMaxRun; i++ {
		err := Pool.Set(ctx, "1", "1", 0).Err()
		if err != nil {
			fmt.Println("存放数据失败", err)
			return
		}

		// _, err = Pool.Get(ctx, "1").Result()
		// if err != nil {
		// 	fmt.Println("取出数据失败", err)
		// 	return
		// }
	}
}

输出内容如下:

-------------------------开始redis压力测试-------------------------
开始 2023-07-20 20:42:26.25
结束 2023-07-20 20:42:37.28
并发数: 50 ;总数据量:500000 ;耗时: 11.03s ;
类型:set ;key:1;value:1;
qps:93474
-----------------------------测试结束-----------------------------

仅存数据时qps能达到10w,若增加取出数据则约为5w,还是比较理想的情况。
当修改PoolSize: AllMaxRun, 指定的连接池数量时,如改为1qps约为1w,此时频繁地建立连接(网络因素)严重影响其性能。而redis性能另一方面是内存大小了。

MySQL

尝试去测试与Mysql的联动(未完待续,2023年7月21日)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值