• (Go)16.Redis连接池的使用


    1.为什么要使用连接池

    一个数据库服务器只拥有有限的连接资源,一旦所有的连接资源都在使用,那么其它需要连接的资源就只能等待释放连接资源。所以,在连接资源有限的情况下,提高单位时间的连接的使用效率,缩短连接时间,就能显著缩短请求时间。

    所以就有了连接池的概念,在初始化时,创建一定数量的连接,先把所有连接存起来,然后,谁需要使用,从这里取走,干完活立马放回来。 如果请求数超出连接池容量,那么就排队等待或者直接丢弃掉。这样就可以省掉每次都创建和关闭连接的资源消耗和时间。

    如果不使用连接池,那么,每次传输数据,我们都需要耗费大量的系统资源进行创建连接,收发数据,关闭连接。很明显,重复创建连接 关闭连接这样的消耗是可以节省。

    2.怎么使用Redis连接池

    https://github.com/gomodule/redigo/  

    安装库:

    $ go get -v github.com/gomodule/redigo/redis
    github.com/gomodule/redigo (download)
    github.com/gomodule/redigo/redis
    基本配置说明
    MaxIdle:最大的空闲连接数,表示即使没有redis连接时依然可以保持N个空闲的连接,而不被清除,随时处于待命状态。
    MaxActive:最大的连接数,表示同时最多有N个连接。0表示不限制。
    IdleTimeout:最大的空闲连接等待时间,超过此时间后,空闲连接将被关闭。如果设置成0,空闲连接将不会被关闭。应该设置一个比redis服务端超时时间更短的时间。
    DialConnectTimeout:连接Redis超时时间。
    DialReadTimeout:从Redis读取数据超时时间。
    DialWriteTimeout:向Redis写入数据超时时间。

    先看下简单的使用案例。
    首先当然是下载类库包
    go get github.com/gomodule/redigo/redis
    贴下简单的使用代码

    package main
    
    import (
        red "github.com/gomodule/redigo/redis"
        "time"
        "fmt"
    )
    
    type Redis struct {
        pool     *red.Pool
    }
    
    var redis *Redis
    
    func initRedis() {
        redis = new(Redis)
        redis.pool = &red.Pool{
            MaxIdle:     256,
            MaxActive:   0,
            IdleTimeout: time.Duration(120),
            Dial: func() (red.Conn, error) {
                return red.Dial(
                    "tcp",
                    "127.0.0.1:6379",
                    red.DialReadTimeout(time.Duration(1000)*time.Millisecond),
                    red.DialWriteTimeout(time.Duration(1000)*time.Millisecond),
                    red.DialConnectTimeout(time.Duration(1000)*time.Millisecond),
                    red.DialDatabase(0),
                    //red.DialPassword(""),
                )
            },
        }
    }
    
    func Exec(cmd string, key interface{}, args ...interface{}) (interface{}, error) {
        con := redis.pool.Get()
        if err := con.Err(); 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)
            }
        }
        return con.Do(cmd, parmas...)
    }
    
    func main() {
        initRedis()
    
        Exec("set","hello","world")
        fmt.Print(2)
        result,err := Exec("get","hello")
        if err != nil {
            fmt.Print(err.Error())
        }
        str,_:=red.String(result,err)
        fmt.Print(str)
    }

    使用类库操作连接池就比较简单,只要从连接池获取一个连接,进行数据操作,然后关闭连接。连接池对连接的创建 回收等的管理,都是连接池内部实现。
    执行看下结果

    go build -o test_web.bin
    ./test_web.bin
    2world

    连接流程大概是这样的
    1.尝试从空闲列表MaxIdle中,获得一个可用连接;如果成功直接返回,失败则尝试步骤2
    2.如果当前的MaxIdle < 连接数 < MaxActive,则尝试创建一个新连接,失败则尝试步骤3

    如果连接数 > MaxActive就等待,直到满足步骤2的条件,重复步骤2

    遇到过的问题

    目前为止,连接池的问题只遇到过一次问题,而且是在测试环境的,当时的配置是

    DialConnectTimeout:time.Duration(200)*time.Millisecond
    DialReadTimeout:time.Duration(200)*time.Millisecond
    DialWriteTimeout:time.Duration(200)*time.Millisecond

    配置的都是200毫秒。有一次使用hgetall的时候,就一直报错,大概类似下面的提示

    read tcp 127.0.0.1:6379: i/o timeout

    字面意思就是 read tcp 超时,可能某些写入大点数据的时候也会报,write tcp timeout。
    后来将读写超时时间都改为1000毫秒,就再也没有出现过类似的报错。

  • 相关阅读:
    小孩补脑 微信公众号
    学习用具汇总 微信公众号
    多带小孩去的地方 微信公众号
    PHP如何开启opcache缓存
    clip命令
    git pull push 报错 no matching host key type found. Their offer sshrsa
    生信分析 | 哲学方法论
    深入浅出Nginx实战与架构
    YCFramework版本更新:V1.0.7
    我的学习方法论
  • 原文地址:https://www.cnblogs.com/lvcisco/p/12172294.html
Copyright © 2020-2023  润新知