zoukankan      html  css  js  c++  java
  • 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随意,够用就好,容易检测到异常
  • 相关阅读:
    01时间处理--02 指定日期--转成星期
    中文乱码处理
    判断js变量是否定义,
    安卓请求服务器js文件下载到本地,版本号不一致就下载
    a标签href跳转---传值---禁止单引号
    修改mysql配置文件,group_concat设置为最大.默认1024个字节字符串.多条json会超出
    GROUP_CONCAT()多条数据.拼接字符串 最大长度1024
    使用变量判断之前.务必先定义
    多种序列化器-指定类对象
    JsonHelper
  • 原文地址:https://www.cnblogs.com/cdyboke/p/7709980.html
Copyright © 2011-2022 走看看