redis性能调优一则
来源:互联网 发布:全国68所网络教育学校 编辑:程序博客网 时间:2024/05/16 10:49
redis作为提升web服务端数据交互能力的重要利器,其本身也有开销,为了让redis变得更快,有必要对和redis交互的地方进行性能优化。
今天说一下golang中比较著名的一个redis库—-redigo。它的conn.Do()、Send()、Flush()、Receive()的合理使用是很有必要的。
先上一个我本地测试的例子:
func main(){ _=InitRedis(10,"127.0.0.1","6379","requirepass",false) //初始化redis,这里就不细写了 GetRedisKey() GetRedisKey2()}func GetRedisKey() { now:=time.Now() conn := redisPool.Get() defer conn.Close() for i:=0;i<1000;i++{ //做1000次get key := "1125"+"test"+strconv.Itoa(i) //_, err := conn.Do("set", key,"testValue") 这个是之前set _, err := redis.String(conn.Do("get", key)) //执行get,并获取结果 if err!=nil { fmt.Println(err) } //fmt.Println(result) } finish1:=time.Since(now) //计时 fmt.Println(finish1)}func GetRedisKey2() { now:=time.Now() conn := redisPool.Get() defer conn.Close() var count int for i:=0;i<1000;i++{ //做1000次get key := "1125"+"test2_"+strconv.Itoa(i) //err := conn.Send("set", key,"testValue")之前set err := conn.Send("get",key) //注意这里是send,不是Do了 if err!=nil { fmt.Println(err) } count++ } err := conn.Flush() //发送指令 if err != nil { fmt.Println(err) } for i:=0 ; i<count; i++ { _, err := redis.String(conn.Receive()) //获取get结果 if err != nil { fmt.Println(err) } } finish2:=time.Since(now) //计时 fmt.Println(finish2)}
实验结果:
80.0561ms //GetRedisKey()运行耗时4.0033ms //GetRedisKey2()运行耗时
结果很明显,同样是做了1000次查询,第二个方法比第一个方法快了20倍。这是为什么呢?接下来说明其中原理。
这个时候要看一看redigo的源码了,先看这个conn的结构:
type conn struct { // Shared mu sync.Mutex pending int err error conn net.Conn // Read readTimeout time.Duration br *bufio.Reader // Write writeTimeout time.Duration bw *bufio.Writer // Scratch space for formatting argument length. // '*' or '$', length, "\r\n" lenScratch [32]byte // Scratch space for formatting integers and floats. numScratch [40]byte}
这个是redis连接的结构,我们发现有两个成员,分别是*bufio.Reader和*bufio.Writer。然后再来看这个Do():
func (c *conn) Do(cmd string, args ...interface{}) (interface{}, error) { c.mu.Lock() pending := c.pending c.pending = 0 c.mu.Unlock() if cmd == "" && pending == 0 { return nil, nil } if c.writeTimeout != 0 { c.conn.SetWriteDeadline(time.Now().Add(c.writeTimeout)) } if cmd != "" { if err := c.writeCommand(cmd, args); err != nil { //将指令写入到一个地方去 return nil, c.fatal(err) } } if err := c.bw.Flush(); err != nil { //将缓冲取出,放到io.Writer中,看到这句代码,我们就应该知道,上面那条c.writeCommand()应该是把指令放到缓冲里了。 return nil, c.fatal(err) } if c.readTimeout != 0 { c.conn.SetReadDeadline(time.Now().Add(c.readTimeout)) } if cmd == "" { reply := make([]interface{}, pending) for i := range reply { r, e := c.readReply() if e != nil { return nil, c.fatal(e) } reply[i] = r } return reply, nil } var err error var reply interface{} for i := 0; i <= pending; i++ { var e error if reply, e = c.readReply(); e != nil { //读redis server返回的数据 return nil, c.fatal(e) } if e, ok := reply.(Error); ok && err == nil { err = e } } return reply, err}
为了一探究竟,看了c.writeCommand()的实现:
func (c *conn) writeCommand(cmd string, args []interface{}) error { c.writeLen('*', 1+len(args)) if err := c.writeString(cmd); err != nil { //再进一步看这个方法,见下面那段 return err } for _, arg := range args { if err := c.writeArg(arg, true); err != nil { return err } } return nil}
func (c *conn) writeString(s string) error { c.writeLen('$', len(s)) c.bw.WriteString(s) //果然调用了bufio的WriteString()方法,把指令都写到了缓冲中 _, err := c.bw.WriteString("\r\n") return err}
到这里,我们知道,Do()这个方法基本上是包办了Send(),Flush(),Receive(),那为什么第二个测试函数会比Do()快这么多呢?原因就是,我for循环执行了多次Send(),目的就是把多条要执行的指令写到缓冲中。
func (c *conn) Send(cmd string, args ...interface{}) error { c.mu.Lock() c.pending += 1 c.mu.Unlock() if c.writeTimeout != 0 { c.conn.SetWriteDeadline(time.Now().Add(c.writeTimeout)) } if err := c.writeCommand(cmd, args); err != nil { return c.fatal(err) } return nil}
这是Send()的源码,其实和Do()一开始做的事情一样,都是c.writeCommand(cmd, args)。
区别就在于,我多次执行Send(),是多条指令写到缓冲中,而不是像Do()那样,不断的执行send,flush,recv。写到缓冲之后,我再统一Flush(),把指令全写到网络io中。因为redis server支持pipelining,我再从io中一个一个Receive出来即可。这样看,1000条指令,我只进行了一次网络传输。而用Do,则执行了1000次网络传输,这差距就显而易见了。
- redis性能调优一则
- redis应用调优经验一则
- JVM GC调优一则--增大Eden Space提高性能
- JVM GC调优一则--增大Eden Space提高性能
- JVM GC调优一则--增大Eden Space提高性能
- JVM GC调优一则--增大Eden Space提高性能
- JVM GC调优一则--增大Eden Space提高性能
- JVM GC调优一则--增大Eden Space提高性能
- JVM GC调优一则--增大Eden Space提高性能
- JVM GC调优一则--增大Eden Space提高性能
- redis 性能调优
- Redis性能调优建议
- REDIS性能调优说明
- redis性能调优总结
- redis-cluster 性能调优
- JVM GC调优一则–增大Eden Space提高性能
- Redis 性能调优相关笔记
- Redis性能调优:保存SNAPSHOT对性能的影响
- 最大01矩阵相关题目 【经典的悬线法】 bzoj1057
- 查看tensor数值
- Mac下DOSBox汇编环境的搭建
- EMD
- Centos网络带宽验证与网络监控工具
- redis性能调优一则
- java 8大数据类型
- 计算机基础学习资料整理和推荐
- 在VMware虚拟机中安装CentOS 7(图文教程)
- android faster screencap
- TensorFlow新手实例源码--mnist源码
- MySQL笔记
- 米联开发板资料链接
- Xcode9 iOS11模拟器和真机 APP图标不显示问题