redis连接池运转流程

redis连接池运转流程

本文主要介绍redis-pool的PoolSize与MinIdleConns的参数配置对pool中连接数conns以及空闲连接数idleConns的影响

PoolSize默认为 10 * runtime.NumCPU()

连接池对象:

	p := &ConnPool{
		conns:     make([]*Conn, 0, opt.PoolSize),
		idleConns: make([]*Conn, 0, opt.PoolSize),
	}

在一开始NewPool时,判断MinIdleConns配置,而后初始化连接

for i := 0; i < opt.MinIdleConns; i++ {
	p.checkMinIdleConns()
}
func (p *ConnPool) checkMinIdleConns() {
	if p.opt.MinIdleConns == 0 {
		return
	}
	if p.poolSize < p.opt.PoolSize && p.idleConnsLen < p.opt.MinIdleConns {
		p.poolSize++
		p.idleConnsLen++
		go p.addIdleConn()
	}
}

func (p *ConnPool) addIdleConn() {
	cn, err := p.newConn(true)
	if err != nil {
		return
	}

	p.connsMu.Lock()
	p.conns = append(p.conns, cn)
	p.idleConns = append(p.idleConns, cn)
	p.connsMu.Unlock()
}

我们会发现,建立的连接,最大为min(PoolSize,MinIdleConns),如PoolSize=10,MinIdleConns为8,则最终为8个Conns和IdleConns,并且conn的pooled字段为true

当我们执行一个redis指令时,会从IdleConns中获取,取最后一个,而后剔除切片,如果当前idleConnsLen少了,则又会checkMinIdleConns->addIdleConn,补全空闲连接。

func (p *ConnPool) Get() (*Conn, error) {
	for {
		p.connsMu.Lock()
		cn := p.popIdle()
		p.connsMu.Unlock()

		if cn == nil {
			break
		}

		return cn, nil
	}

	newcn, err := p._NewConn(true)
	if err != nil {
		return nil, err
	}

	return newcn, nil
}

从空闲连接中获取连接

func (p *ConnPool) popIdle() *Conn {
	if len(p.idleConns) == 0 {
		return nil
	}

	idx := len(p.idleConns) - 1
	cn := p.idleConns[idx]
	p.idleConns = p.idleConns[:idx]
	p.idleConnsLen--
	p.checkMinIdleConns()
	return cn
}

当空闲连接中获取不到时,新建连接,pooled参数为true,如果当前连接池的poolSize超过配置数时,cn.pooled = false

func (p *ConnPool) _NewConn(pooled bool) (*Conn, error) {
	cn, err := p.newConn(pooled)
	if err != nil {
		return nil, err
	}

	p.connsMu.Lock()
	p.conns = append(p.conns, cn)
	if pooled {
		if p.poolSize < p.opt.PoolSize {
			p.poolSize++
		} else {
			cn.pooled = false
		}
	}
	p.connsMu.Unlock()
	return cn, nil
}

当redis指令执行完时,判断err,执行Put或者Remove方法

if err == nil || internal.IsRedisError(err) {
	c.connPool.Put(cn)
} else {
	c.connPool.Remove(cn, err)
}

如果当前连接池的poolSize超过配置数时,cn.pooled = false时,直接Remove当前连接,从当前的conns中剔除,并且close连接,当cn.pooled为true时,直接塞入p.idleConns列表,连接得到复用

func (p *ConnPool) Put(cn *Conn) {
	if !cn.pooled {
		p.Remove(cn, nil)
		return
	}

	p.connsMu.Lock()
	p.idleConns = append(p.idleConns, cn)
	p.idleConnsLen++
	p.connsMu.Unlock()
	p.freeTurn()
}

当前,最大连接数Conns也收参数poolsize的影响,最多创建连接不会超过此配置,通过一个channel管道实现

queue:     make(chan struct{}, opt.PoolSize),

至此,连接的整个生命周期完成,由此看到,空闲连接数的配置,会严重影响连接的复用,当空闲连接配置过小时,而并发量又很大时,会频繁的close Tcp连接

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值