gopkg.in/redis.v3 源码分析

本文耗时60分钟,阅读需要10分钟。

今天要跟大家剖析的是 redis client in golang gopkg.in/redis.v3

前文回顾

其实在此之前,我已经对这个库的源码进行过初步介绍和分析了。

Golang redis.v3源代码分析 Golang redis.v3 源代码再分析

为什么还要来分析呢?

主要是最近我们线上环境使用到redis的一个服务出现了这样的错误信息:

redis: connection pool timeout
...
redis: you open connections too fast (last error: xxx)

错误信息提示的很清楚,超时之后又是打开连接太快了。

应该不难理解,其实就是当连接池里面的连接超时不可用了之后,再重新创建,但是因为业务量对于redis连接数的诉求比较大,所以短时间内就出现了超过设定的连接池大小了,而这个错误是超过其预设连接池的2倍就会触发。

为什么是2倍呢?带着这样的问题,我就开始查看错误信息的来源[源码 gopkg.in/redis.v3/pool.go#L199]

注意我这里提供的源码项目版本是:

{
			"ImportPath": "gopkg.in/redis.v3",
			"Comment": "v3.1.4-1-g5f975ec",
			"Rev": "5f975ec92c05174cbde7254f204219ab6966c15e"
}

备注:GitHub 上已经没有3.1.4.1的分支了,那我直接给大家贴源码吧。

// 来源于:pool.go
// Establish a new connection
func (p *connPool) new() (*conn, error) {
	if p.rl.Limit() {
		err := fmt.Errorf(
			"redis: you open connections too fast (last error: %v)",
			p.lastDialErr,
		)
		return nil, err
	}

	cn, err := p.dialer()
	if err != nil {
		p.lastDialErr = err
		return nil, err
	}

	return cn, nil
}

注意p.rl.Limit(),通过ratelimit源码,就很清楚的知道,这里是被限速了。

接下来再来看看这个限速是在什么地方预设的:

func newConnPool(opt *Options) *connPool {
	p := &connPool{
		dialer: newConnDialer(opt),

		rl:        ratelimit.New(2*opt.getPoolSize(), time.Second),// 限速: 每秒创建连接不超过配置连接池的2倍
		opt:       opt,
		conns:     newConnList(opt.getPoolSize()),
		freeConns: make(chan *conn, opt.getPoolSize()),
	}
	if p.opt.getIdleTimeout() > 0 {
		go p.reaper()
	}
	return p
}

// ...

func NewClient(opt *Options) *Client {
	pool := newConnPool(opt)
	return newClient(opt, pool)
}

参考资料

  1. go-redis(gopkg.in/redis.v3)
  2. ratelimit

茶歇驿站

一个让你可以在茶歇之余,停下来看一看,里面的内容或许对你有一些帮助。

这里的内容主要是团队管理,个人管理,后台技术相关,其他个人杂想。

茶歇驿站二维码

当然,你觉得对你有帮助,也可以给我打赏。 打赏