主要记录的功能点

  • 配置解析
  • 连接redis
  • 单侧

配置模块

  1. 定义配置结构体
package config
type Configuration struct {// +++++++++++++++日志相关+++++++++++++++++// 日志级别,这里使用了 beego 的 log 包Log *LogConfigure `yaml:"log"`// 服务端消息chan长度ServerMsgChanBufferLength int `yaml:"server-msgchan-bufferlength"`ServerConnTimeout int `yaml:"server-conn-timeout"`//proxy agent读写server超时时间,单位秒ServerRWTimeout int `yaml:"server-rw-timeout"`
}
// 定义嵌套的块级配置
type LogConfigure struct{// [0:Emergency, 1:Alert, 2:Critical, 3:Error, 4:Warning, 5:Notice, 6:Informational, 7:Debug]LogLevel int `yaml:"log-level"`// 日志输出位置,默认日志输出到控制台// 目前只支持['console', 'file']两种形式,如非console形式这里需要指定文件的路径,可以是相对路径LogOutput string `yaml:"log-output"`// 日志最大保留天数LogMaxDays int `yaml:"log-maxdays"`
}
// 初始化默认值
var Config = &Configuration{ServerMsgChanBufferLength 10,ServerConnTimeout 1,ServerRWTimeout  1,
}
  1. 定义参数文件
log:# 日志级别,默认为3:Error# [0:Emergency, 1:Alert, 2:Critical, 3:Error, 4:Warning, 5:Notice, 6:Informational, 7:Debug]log-level: 7# 日志最大保留天数log-maxdays: 7# 日志输出位置,默认日志输出到控制台# 目前只支持['console', 'file']两种形式,如非console形式这里需要指定文件的路径,可以是相对路径log-output: log/redis-agent.log
server-msgchan-bufferlength: 3
# 连接server超时时间,单位秒
server-conn-timeout: 5
# 读写server超时时间,单位秒
server-rw-timeout: 5
  1. 解析参数文件,将配置绑定到结构体
// 加载配置文件
func (conf *Configuration) readConfigFile(path string) error {configFile, err := os.Open(path)if err != nil {os.Stderr.WriteString(fmt.Sprintf("readConfigFile(%s) os.Open failed: %v", path, err))return err}defer configFile.Close()content, err := ioutil.ReadAll(configFile)if err != nil {os.Stderr.WriteString(fmt.Sprintf("readConfigFile(%s) ioutil.ReadAll failed: %v", path, err))return err}// 解析byte编码的数据并将结果存入Config指向的值err = yaml.Unmarshal(content, Config)if err != nil {os.Stderr.WriteString(fmt.Sprintf("readConfigFile(%s) yaml.Unmarshal failed: %v", path, err))return err}return nil
}// 配置初始化
func ParseConfig(configFile string) error {var err error// 如果未传入配置文件,则返回报错if "" == configFile {return errors.New("No config file input")}// 配置文件状态检查if _, err = os.Stat(configFile); err != nil {os.Stderr.WriteString(fmt.Sprintf("%v [redis-agent start failed] Check config file failed."+" err=%v ConfFile=%v \n", time.Now().Format(TIME_FORMAT), err, configFile))return err}// 配置文件解析if err = Config.readConfigFile(configFile); err != nil {os.Stderr.WriteString(fmt.Sprintf("%v [redis-agent start failed]"+" Parse config file failed. ConfFile=%v err=%v \n", time.Now().Format(TIME_FORMAT), err, configFile))return err}return LoggerInit()
}

访问Redis

redisgo 接口使用文档
一开始用尝试用go-redis包,但是依赖较多且遇到很多不兼容问题,于是转而该用redisgo。支持自定义命令,支持各种协议的redis命令,包括sentinel相关的命令。需要注意的地方

  • 返回的数据类型是interface{},即结构体类型不固定,所以如果依赖返回值则需要判断返回值类型并做对应的类型转化
  • 正确及时的关闭连接
  • redisgo支持连接池,我这里使用的短链接的方式
  • redis.Dial 和redis.DialContext方法都可以实现创建连接,后者是带有上下文的网络请求模式
package redisimport ("context""fmt""redis-agent/common""time""github.com/gomodule/redigo/redis"
)// 初始化proxy的密码设置
var ProxyPwd = &common.Config.ProxyPwd
var Conf = common.Configfunc InitRedis(serverType string, port int64) (redis.Conn, error) {// 初始化连接参数var options []redis.DialOptionredisOpt := append([]redis.DialOption{redis.DialReadTimeout(time.Duration(Conf.ServerRWTimeout) * time.Second),redis.DialWriteTimeout(time.Duration(Conf.ServerRWTimeout) * time.Second),redis.DialConnectTimeout(time.Duration(Conf.ServerConnTimeout) * time.Second)},options...)var ctx = context.Background()var addr = fmt.Sprintf("127.0.0.1:%d", port)c, err := redis.DialContext(ctx, "tcp", addr, redisOpt...)if err != nil {return nil, err}// 如果服务类型为proxy则设置密码var password = ""if serverType == "Proxy" {// 如果密码不为空则进行权限认证if password = *ProxyPwd; password != "" {if _, err := c.Do("AUTH", password); err != nil {return nil, err}}}return c, nil
}func Exec(serverType string, port int64, cmd string, key interface{}, args ...interface{}) (interface{}, error) {var con redis.Connvar err errorcon, err = InitRedis(serverType, port)if err != nil {return nil, err}defer con.Close()parmas := make([]interface{}, 0)parmas = append(parmas, key)if len(args) > 0 {for _, v := range args {parmas = append(parmas, v)}}reply, err := con.Do(cmd, parmas...)if err != nil {errMsg := fmt.Sprintf("exec cmd error,cmd=%v parmas=%v error=%v", cmd, parmas, err)fmt.Println(errMsg)return reply, err}/* 可视化结果集string类型的key的访问及管理命令默认返回的数据类型为[]uint8,将其转化为string显示集合类的结果集通过redis.Strings转化为[]string*/switch reply.(type) {case []uint8:reply, err = redis.String(reply, err)case []interface{}:reply, err = redis.Strings(reply, err)}return reply, err
}

单元测试

在代码文件所在的同一目录下创建$(文件名)_test.go文件。
使用了测试框架convey,使得测试代码也更简洁了一些,
Convery有三个参数,第一个是描述,第二个是测试表testing.T结构体,第三个是闭包,
So是固定用法,用来校验所给参数是否符合预期

package redisimport ("fmt""testing". "github.com/smartystreets/goconvey/convey"
)func TestExec(t *testing.T) {res, err := Exec("proxy", 1111, "get", "a")fmt.Printf("res: %v,type=%T\n", res, res)Convey("Exec", t, func() {// So(res, ShouldNotBeNil)So(err, ShouldBeNil)})
}

命令行执行测试代码

# 进入到项目一级目录下,执行,这里代码和测试代码均在二级目录redis下,以下命令会自动执行指定目录下的所有测试文件
go test -v ./redis/
# 输出结果
=== RUN   TestExec
res: aa,type=stringExec ✔1 total assertion--- PASS: TestExec (0.02s)
PASS
ok      redis-agent/redis       0.040s

如果只执行特定的测试文件,指定测试文件执行

go test -v ./redis/connect_test.go ./redis/connect.go

如果只执行特定测试文件中的某些测试函数

# -run 指定待执行函数名的前缀
go test -v ./redis/  -run TestExec

一定要注意测试结果默认是被缓存的,不适用于动态修改测试代码debug结果的场景,关闭缓存功能加参数-count=1

通过go 语言访问redis相关推荐

  1. centos 7下的redis 环境搭建以及C语言使用hiredis访问redis

    系统  CentOS7 Redis 官网下载   https://redis.io/download 1.下载解压 [root@TestServer-DFJR programs]# /usr/loca ...

  2. Serverless 解惑——函数计算如何访问 Redis 数据库

    函数计算(Function Compute):函数计算 是事件驱动的全托管计算服务.使用函数计算,您无需采购与管理服务器等基础设施,只需编写并上传代码.函数计算为您准备好计算资源,弹性地可靠地运行任务 ...

  3. redis的那种目录结构能新建么_Serverless 解惑——函数计算如何访问 Redis 数据库...

    函数计算(Function Compute):函数计算 是事件驱动的全托管计算服务.使用函数计算,您无需采购与管理服务器等基础设施,只需编写并上传代码.函数计算为您准备好计算资源,弹性地可靠地运行任务 ...

  4. c语言访问mysql,C语言访问mysql数据库

    mysql中新建的数据库为hyx,hyx中的表为my_schema,表中的数据为下图: 编写代码,访问表中的数据,测试代码如下: #include "stdafx.h" #incl ...

  5. 【Go】用 Go 访问 Redis

    用 Go 访问 Redis Redis 官方并没有提供 Redis 访问包,官网列出来了很多 Go 语言的客户端包,它们都能实现对 Redis 的访问和操作,本文以其中较为人性化的 Redigo 来讲 ...

  6. c语言操作redis数据库

    前言 redis(Remote Dictionary Server)是一个使用ANSI C编写的开源.支持网络.基于内存.可选持久性的键值对存储数据库–来自维基百科.由于其读写性能高.数据结构丰富.支 ...

  7. 运维实践-最新Nginx二进制构建编译lua-nginx-module动态链接Lua脚本访问Redis数据库读取静态资源隐式展现...

    关注「WeiyiGeek」公众号 设为「特别关注」每天带你玩转网络安全运维.应用开发.物联网IOT学习! 本章目录: 0x0n 前言简述 知识引入 Lua模块指令阶段 0x01 部署环境 安装说明 安 ...

  8. python语言数据库规模_Python语言访问MySQL数据库

    4.使用python语言访问MySQL 1)pymysql库:Python语言访问MySQL接口 -安装: 在线:pip install pymysql 离线: 第一步:下载安装包,下载地址: htt ...

  9. windows下vs2013使用C++访问redis

    刚开始在windows下使用c++访问reids各种报错,经过网上到处搜方案,终于可以在windows下访问redis了, 特将注意事项记录下来: 1.获取redis Window下的开发库源码,从g ...

最新文章

  1. 【Python-ML】神经网络-Theano张量库(GPU版的Numpy)
  2. 菜单 java_java 菜单
  3. python常用的开发环境包括_Python语言主要包括哪些集成开发环境?_学小易找答案...
  4. sql server分页
  5. Python开发利器PyCharm 2.7附注册码
  6. C# PDF 转成图片利用GhostScript
  7. Windows获取系统版本号
  8. Spring配置中的classpath:与classpath*:的区别研究(转)
  9. Debug Assertion Failed.Expression:_BLOCK_TYPE_IS_VALID(phead-nBlockUse)
  10. 聊聊Elasticsearch RestClient的RequestLogger
  11. 非常适合新手的jq/zepto源码分析05
  12. ant压缩html,ant+yuicompressor压缩js/css
  13. Java高并发编程实战4,synchronized与Lock底层原理
  14. 用python制作勒索病毒_python生成的exe被360识别为勒索病毒原因及解决方法
  15. mobileu-vst声卡设置
  16. ae软件安装计算机丢失,Win10系统AE软件安装失败怎么办
  17. icom对讲机写频线定义_哈罗CQ火腿社区 - QRP and DIY - 各种写频线的资料,放上来备用吧 - Powered by phpwind...
  18. linux 文件比较覆盖,Linux系统 wget 覆盖本地文件
  19. JAVA 使用POI读取文档
  20. 8583协议报文例子。

热门文章

  1. webpack打包优化(webpack打包优化 文件大小)
  2. 编写一段程序,为一个文本文件的每一行前面添加行号,并以一个新的文件保存添加 了行号的文本
  3. 画心的方法_书画常识:怎样保存书画的画心
  4. Windows和Linux、Unix的区别
  5. (转)WebService是什么
  6. “基于云平台的移动终端实时渲染”学习参考
  7. SQL Serve Intersect(交集)
  8. 2021最前端最常见的面试题
  9. 操作系统发展史及特点
  10. c语言孪生素数对问题