redigo的redis.Pool 配置参数调优

Posted dy blog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redigo的redis.Pool 配置参数调优相关的知识,希望对你有一定的参考价值。

redigo的redis.Pool 配置参数调优

 

reids.Pool结构介绍

// github.com/garyburd/redigo/redis/pool.go
type Pool struct {

    // Dial()方法返回一个连接,从在需要创建连接到的时候调用
    Dial func() (Conn, error)

    // TestOnBorrow()方法是一个可选项,该方法用来诊断一个连接的健康状态
    TestOnBorrow func(c Conn, t time.Time) error

    // 最大空闲连接数
    MaxIdle int

    // 一个pool所能分配的最大的连接数目
    // 当设置成0的时候,该pool连接数没有限制
    MaxActive int

    // 空闲连接超时时间,超过超时时间的空闲连接会被关闭。
    // 如果设置成0,空闲连接将不会被关闭
    // 应该设置一个比redis服务端超时时间更短的时间
    IdleTimeout time.Duration

    // 如果Wait被设置成true,则Get()方法将会阻塞
    Wait bool

    // mu protects fields defined below.
    mu     sync.Mutex
    cond   *sync.Cond
    closed bool
    active int

    // 空闲连接队列
    idle list.List
}

  

 

从连接池中获取连接

// get prunes stale connections and returns a connection from the idle list or
// creates a new connection.
func (p *Pool) get() (Conn, error) {
    p.mu.Lock()

    //修剪idle列表上那些超时的连接 
    if timeout := p.IdleTimeout; timeout > 0 {
        for i, n := 0, p.idle.Len(); i < n; i++ {
            e := p.idle.Back()//取得idle列表中的最后一个连接(空闲时间最长)
            if e == nil {
                break
            }
            ic := e.Value.(idleConn)
            if ic.t.Add(timeout).After(nowFunc()) { //如果空闲时间最长的连接都没有超时,则不再修剪
                break
            }
            p.idle.Remove(e)//从空闲列表中移除这个连接
            p.release()//减少p.active,发消息给阻塞的请求
            p.mu.Unlock()
            ic.c.Close()//关闭连接
            p.mu.Lock()
        }
    }

    for {

        // 从idle列表中获取一个可用的连接
        for i, n := 0, p.idle.Len(); i < n; i++ {
            e := p.idle.Front()//从idle列表前面取连接,是刚刚使用过的连接
            if e == nil {
                break
            }
            ic := e.Value.(idleConn)
            p.idle.Remove(e)//从空闲列表中去除该连接
            test := p.TestOnBorrow
            p.mu.Unlock()
            if test == nil || test(ic.c, ic.t) == nil {//如果测试函数不为空,则测试这个连接的可用性
                return ic.c, nil//可用或者测试方法为空,则返回连接
            }
            ic.c.Close()//不可用,关闭该连接
            p.mu.Lock()
            p.release()//减少p.active,发消息给阻塞的请求
        }

        // 检查pool本身有没有关闭
        if p.closed {
            p.mu.Unlock()
            return nil, errors.New("redigo: get on closed pool")
        }

        // 建立新的连接
        if p.MaxActive == 0 || p.active < p.MaxActive {//看看是否没有到最大的active限制
            dial := p.Dial
            p.active += 1
            p.mu.Unlock()
            c, err := dial()//调用dial方法去建立连接
            if err != nil {
                p.mu.Lock()
                p.release()
                p.mu.Unlock()
                c = nil
            }
            return c, err
        }

        //如果建立连接失败或者建立达到连接池的限制
        if !p.Wait {//不阻塞就直接返回错误
            p.mu.Unlock()
            return nil, ErrPoolExhausted
        }

        if p.cond == nil {
            p.cond = sync.NewCond(&p.mu)
        }
        p.cond.Wait()//阻塞,等待唤醒
    }
}

  

关闭连接

func (p *Pool) put(c Conn, forceClose bool) error {
    err := c.Err()
    p.mu.Lock()
    if !p.closed && err == nil && !forceClose {//p没有关闭,且没有错误,且不是强制关闭连接
        p.idle.PushFront(idleConn{t: nowFunc(), c: c})// 把返回的连接放到idle的队首
        if p.idle.Len() > p.MaxIdle {// 如果idle列表的长度过长(至多也只能多1)
            c = p.idle.Remove(p.idle.Back()).(idleConn).c// idle列表的最后一个连接
        } else {
            c = nil
        }
    }

    if c == nil {
        if p.cond != nil {
            p.cond.Signal()//成功放回空闲连接通知其他阻塞的进程
        }
        p.mu.Unlock()
        return nil
    }

    p.release()//减少active计数
    p.mu.Unlock()
    return c.Close()//关闭该连接
}

  

 

配置场景

再来看下主要参数

  • MaxIdle 
    • 表示连接池空闲连接列表的长度限制
    • 空闲列表是一个栈式的结构,先进后出
  • MaxActive 
    • 表示连接池中最大连接数限制
    • 主要考虑到服务端支持的连接数上限,以及应用之间”瓜分”连接数
  • IdleTimeout 
    • 空闲连接的超时设置,一旦超时,将会从空闲列表中摘除
    • 该超时时间时间应该小于服务端的连接超时设置

区分两种使用场景:

    1. 高频调用的场景,需要尽量压榨redis的性能: 
      • 调高MaxIdle的大小,该数目小于maxActive,由于作为一个缓冲区一样的存在,扩大缓冲区自然没有问题
      • 调高MaxActive,考虑到服务端的支持上限,尽量调高
      • IdleTimeout由于是高频使用场景,设置短一点也无所谓,需要注意的一点是MaxIdle设置的长了,队列中的过期连接可能会增多,这个时候IdleTimeout也要相应变化
    2. 低频调用的场景,调用量远未达到redis的负载,稳定性为重: 
      • MaxIdle可以设置的小一些
      • IdleTimeout相应地设置小一些
      • MaxActive随意,够用就好,容易检测到异常

以上是关于redigo的redis.Pool 配置参数调优的主要内容,如果未能解决你的问题,请参考以下文章

go-redis

redis+spring

gocelery 测试例子(windows会有报错,建议linux执行)

JedisPool操作

GC调优配置参数

hadoop 调优措施 调优参数