首页后端开发GOGo项目优化——动态缓存Redis的使用

Go项目优化——动态缓存Redis的使用

时间2023-04-23 22:24:01发布访客分类GO浏览1525
导读:1. Redis:1.1 简介: garyburd/redigo 包是网上很多博文都在推荐使用的一个高Star的Redis连接包,项目已经迁移到了gomodule/redigo,同时包的获取也理所当然地改成了go get github.co...

1. Redis:

1.1 简介:

garyburd/redigo 包是网上很多博文都在推荐使用的一个高Star的Redis连接包,项目已经迁移到了gomodule/redigo,同时包的获取也理所当然地改成了go get github.com/gomodule/redigo/redis,总之,暂时不管这两个包的详细区别,以下就以新包为准,介绍下redigo包使用。

1.2 连接redis

//第一种连接方法
con,err := redis.Dial("tcp", 
	"链接地址,例如127.0.0.1:6379", 
	redis.DialPassword("密码"),
)
// or
// con,err := redis.Dial("tcp","127.0.0.1:6379")
if err != nil {

   fmt.Println(err)
}

defer con.Close()

1.3 常用api:

// Do 向服务器发送命令并返回收到的应答。
func Do(commandName string, args ...interface{
}
) (reply interface{
}
, err error)

// reply 具体类型,具体转换
func Int(reply interface{
}
, err error) (int, error) 
func String(reply interface{
}
, err error) (string, error)
func Bool(reply interface{
}
, err error) (bool, error) 
func Values(reply interface{
}
, err error) ([]interface{
}
, error) 
func Strings(reply interface{
}
, err error) ([]string, error)
func ByteSlices(reply interface{
}
, err error) ([][]byte, error)
func Ints(reply interface{
}
, err error) ([]int, error)
func StringMap(result interface{
}
, err error) (map[string]string, error)
...
// 更多函数自行探索

1.3 连接池:

  在golang的项目中,若要频繁的用redis(或者其他类似的NoSQL)来存取数据,最好用redigo自带的池来管理连接。

  不然的话,每当要操作redis时,建立连接,用完后再关闭,会导致大量的连接处于TIME_WAIT状态(redis连接本质上就是tcp)。

:TIME_WAIT,也叫TCP半连接状态,会继续占用本地端口。

import (
	"fmt"
	"github.com/gomodule/redigo/redis"
	"time"
)

var redisPoll *redis.Pool

func initRedis() {
    
	redisPoll = &
redis.Pool{

		// 连接方法
		Dial: func() (redis.Conn, error) {

			c, err := redis.Dial("tcp", "链接地址,例如127.0.0.1:6379",
				redis.DialPassword("密码"),
				redis.DialReadTimeout(1*time.Second),
				redis.DialWriteTimeout(1*time.Second),
				redis.DialConnectTimeout(1*time.Second),
			)
			if err != nil {

				return nil, err
			}

			return c, nil
		}
,
		// 最大的空闲连接数,
		// 表示即使没有redis连接时依然可以保持N个空闲的连接,而不被清除,随时处于待命状态。
		MaxIdle: 256,
		// 最大的激活连接数,表示同时最多有N个连接
		MaxActive: 256,
		// 最大的空闲连接等待时间,超过此时间后,空闲连接将被关闭
		IdleTimeout: time.Duration(120),
	}

}


// myDo
// @Title myDo
// @Description 封装的 redis Do函数
// Do(commandName string, args ...interface{
}
) (reply interface{
}
, err error)
// @Param cmd string 命令
// @Param key interface{
}
 键
// @Param args ...interface{
}
 参数
// @Return interface{
}
 redis服务器返回值
// @Return error 错误
func myDo(cmd string, key interface{
}
, args ...interface{
}
) (interface{
}
, error) {
    
	// 从pool里获取一个redis连接,如果连接池没有,会调用 Dial()
	con := redisPoll.Get()
	if err := con.Err();
 err != nil {

		return nil, err
	}

	parmas := make([]interface{
}
    , 0)
	parmas = append(parmas, key)
	// 如果参数不为空,也加入参数列表
	if len(args) >
 0 {

		for _, arg := range args {

			parmas = append(parmas, arg)
		}

	}

	return con.Do(cmd, parmas...)
}


func main() {

	initRedis()
	myDo("set", "mykey1", "myvalue1")
	result, err := myDo("get", "mykey1")
	if err != nil {

		fmt.Println(err.Error())
	}

	// String()是将命令应答转换为字符串的帮助器。
	str, _ := redis.String(result, err)
	fmt.Println(str)
}

1.4 项目中使用:

dynamic cache:动态缓存

conf/dynamicache.conf

#*******************
#动态缓存配置
#*******************
# redis地址
dynamicache_addrstr=127.0.0.1:6379
# redis密码
dynamicache_passwd=密码

conf/app.conf

...
# 引入动态缓存配置文件
include "dynamicache.conf"
...

utils/dynamic_cache.go

package dynamicache

import (
	"encoding/json"
	"github.com/astaxie/beego/logs"
	"strconv"
	"time"

	"github.com/astaxie/beego"
	"github.com/gomodule/redigo/redis"
)

var (
	pool *redis.Pool = nil
	// MaxIdle 最大的空闲连接数,
	MaxIdle int = 0
	// MaxOpen 最大的激活连接数,表示同时最多有N个连接
	MaxOpen int = 0
	// ExpireSec 超时时间
	ExpireSec int64 = 0
)

// InitCache 在 sysinit.go 中调用
// 初始化redis配置
func InitCache() {

	addr := beego.AppConfig.String("dynamicache_addrstr")
	if len(addr) == 0 {

		addr = "127.0.0.1:6379"
	}

	if MaxIdle = 0 {

		MaxIdle = 256
	}


	password := beego.AppConfig.String("dynamicache_passwd")
	if len(password) == 0 {
    
		pool = &
redis.Pool{

			MaxIdle:     MaxIdle,
			MaxActive:   MaxOpen, // 最大
			IdleTimeout: time.Duration(120),
			Dial: func() (redis.Conn, error) {

				return redis.Dial(
					"tcp",
					addr,
					redis.DialReadTimeout(1*time.Second),
					redis.DialWriteTimeout(1*time.Second),
					redis.DialConnectTimeout(1*time.Second),
				)
			}
,
		}

	}
 else {
    
		pool = &
redis.Pool{

			MaxIdle:     MaxIdle,
			MaxActive:   MaxOpen,
			IdleTimeout: time.Duration(120),
			Dial: func() (redis.Conn, error) {

				return redis.Dial(
					"tcp",
					addr,
					redis.DialReadTimeout(1*time.Second),
					redis.DialWriteTimeout(1*time.Second),
					redis.DialConnectTimeout(1*time.Second),
					redis.DialPassword(password),
				)
			}
,
		}

	}

}

sysinit/sysinit.go

package sysinit

import (
    ...
	"mybook/utils/dynamicache"
	...
)
....
// initDynamicCache
// @Title initDynamicCache
// @Description 初始化dynamic_cache.go里的公有值,并初始化redis配置 
func initDynamicCache() {

	dynamicache.MaxOpen = 128
	dynamicache.MaxIdle = 128
	dynamicache.ExpireSec = 10
	dynamicache.InitCache()
}

....

根据实际业务需要,在utils/dynamic_cache.go里封装会用到的方法

utils/dynamic_cache.go

...
// redisDo
// @Title redisDo
// @Description 封装的 redis Do函数
// Do(commandName string, args ...interface{
}
) (reply interface{
}
, err error)
// @Param cmd string 命令
// @Param key interface{
}
 键
// @Param args ...interface{
}
 参数
// @Return interface{
}
 redis服务器返回值
// @Return error 错误
func redisDo(cmd string, key interface{
}
, args ...interface{
}
) (interface{
}
, error) {
    
	con := pool.Get()
	if err := con.Err();
 err != nil {

		return nil, err
	}

	params := make([]interface{
}
    , 0)
	params = append(params, key)
	if len(args) >
 0 {

		for _, v := range args {

			params = append(params, v)
		}

	}

	return con.Do(cmd, params...)
}


// WriteString
// @Title WriteString
// @Description 写字符串
// @Param key string 键
// @Param value string 值
// @Return error 错误
func WriteString(key string, value string) error {

	_, err := redisDo("SET", key, value)
	logs.Debug("redis set:" + key + "-" + value)
	redisDo("EXPIRE", key, ExpireSec)
	return err
}


// ReadString
// @Title ReadString
// @Description  读字符串
// @Param key string 键
// @Param value string 值
// @Return error 错误
func ReadString(key string) (string, error) {

	result, err := redisDo("GET", key)
	logs.Debug("redis get:" + key)
	if nil == err {

		str, _ := redis.String(result, err)
		return str, nil
	}
 else {

		logs.Debug("redis get error:" + err.Error())
		return "", err
	}

}


// 以下封装的方法都是在WriteString() ReadString()上封装的,使用的都是redis里的string类型

// WriteStruct
// @Title WriteStruct
// @Description 写结构体(本质是还是写json字符串)
func WriteStruct(key string, obj interface{
}
) error {

	data, err := json.Marshal(obj)
	if nil == err {

		return WriteString(key, string(data))
	}
 else {

		return nil
	}

}


// ReadStruct
// @Title ReadStruct
// @Description 读结构体
func ReadStruct(key string, obj interface{
}
) error {
    
	if data, err := ReadString(key);
 nil == err {

		return json.Unmarshal([]byte(data), obj)
	}
 else {

		return err
	}

}


// WriteList
// @Title WriteList
// @Description 写数组
func WriteList(key string, list interface{
}
, total int) error {

	realKeyList := key + "_list"
	realKeyCount := key + "_count"
	data, err := json.Marshal(list)
	if nil == err {

		WriteString(realKeyCount, strconv.Itoa(total))
		return WriteString(realKeyList, string(data))
	}
 else {

		return nil
	}

}


// ReadList
// @Title ReadList
// @Description 读数组
func ReadList(key string, list interface{
}
) (int, error) {
    
	realKeyList := key + "_list"
	realKeyCount := key + "_count"
	if data, err := ReadString(realKeyList);
 nil == err {
    
		totalStr, _ := ReadString(realKeyCount)
		total := 0
		if len(totalStr) >
 0 {

			total, _ = strconv.Atoi(totalStr)
		}

		return total, json.Unmarshal([]byte(data), list)
	}
 else {

		return 0, err
	}

}
    

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!

go缓存迁移连接优化

若转载请注明出处: Go项目优化——动态缓存Redis的使用
本文地址: https://pptw.com/jishu/6695.html
2023-04-16:给定一个长度为N的数组,值一定在0~N-1范围,且每个值不重复 比如,arr = [4, 2, 0, 3, 1] Go语言——使用模糊查询检索关键词小技巧

游客 回复需填写必要信息