golang 通用连接池 高性能连接各种tcp连接,实例rabbitmq,mysql ,redis....
完整代码在https://github.com/human2312/tcp-pool
package Pool// @Time : 2020年3月13日12:27:33// @Author : Lemyhello// @Desc: 通用连接池import ("errors""fmt""sync""time")var (//ErrMaxActiveConnReached 连接池超限ErrMaxActiveConnReached = errors.New("MaxActiveConnReached"))// Config 连接池相关配置type Config struct {//连接池中拥有的最小连接数InitialCap int//最大并发存活连接数MaxCap int//最大空闲连接MaxIdle int//生成连接的方法Factory func() (interface{}, error)//关闭连接的方法Close func(interface{}) error//检查连接是否有效的方法Ping func(interface{}) error//连接最大空闲时间,超过该事件则将失效IdleTimeout time.Duration}// channelPool 存放连接信息type channelPool struct {mu sync.RWMutexconns chan *idleConnfactory func() (interface{}, error)close func(interface{}) errorping func(interface{}) erroridleTimeout, waitTimeOut time.DurationmaxActive intopeningConns int}type idleConn struct {conn interface{}t time.Time}var (//ErrClosed 连接池已经关闭ErrorErrClosed = errors.New("pool is closed"))// Pool 基本方法type Pool interface {Get() (interface{}, error)Put(interface{}) errorClose(interface{}) errorRelease()Len() int}// NewChannelPool 初始化连接func NewChannelPool(poolConfig *Config) (Pool, error) {if ! (poolConfig.InitialCap <= poolConfig.MaxIdle && poolConfig.MaxCap >= poolConfig.MaxIdle && poolConfig.InitialCap >= 0 ){return nil, errors.New("invalid capacity settings")}if poolConfig.Factory == nil {return nil, errors.New("invalid factory func settings")}if poolConfig.Close == nil {return nil, errors.New("invalid close func settings")}c := &channelPool{conns: make(chan *idleConn, poolConfig.MaxIdle),factory: poolConfig.Factory,close: poolConfig.Close,idleTimeout: poolConfig.IdleTimeout,maxActive: poolConfig.MaxCap,openingConns: poolConfig.InitialCap,}if poolConfig.Ping != nil {c.ping = poolConfig.Ping}for i := 0; i < poolConfig.InitialCap; i++ {conn, err := c.factory()if err != nil {c.Release()return nil, fmt.Errorf("factory is not able to fill the pool: %s", err)}c.conns 0 {if wrapConn.t.Add(timeout).Before(time.Now()) {//丢弃并关闭该连接c.Close(wrapConn.conn)continue}}//判断是否失效,失效则丢弃,如果用户没有设定 ping 方法,就不检查if c.ping != nil {if err := c.Ping(wrapConn.conn); err != nil {c.Close(wrapConn.conn)continue}}return wrapConn.conn, nildefault:c.mu.Lock()defer c.mu.Unlock()if c.openingConns >= c.maxActive {return nil, ErrMaxActiveConnReached}if c.factory == nil {return nil, ErrClosed}conn, err := c.factory()if err != nil {return nil, err}c.openingConns++return conn, nil}}}// Put 将连接放回pool中func (c *channelPool) Put(conn interface{}) error {if conn == nil {return errors.New("connection is nil. rejecting")}c.mu.Lock()if c.conns == nil {c.mu.Unlock()return c.Close(conn)}select {case c.conns
main函数实例调试
package main// @Time : 2020年3月13日19:35:35// @Author : Lemyhello// @Desc: 展示如何使用Pool连接池拿到tcp各种应用实例import ("fmt""github.com/streadway/amqp""net""time""tcp-pool/Pool")var (mqurl = "amqp://root:root@127.0.0.1:5672/test" //根据实际情况填写mq配置连接mqPool Pool.Pool)func main() {rabbitmq()mysql()redis()//拿到一个连接mq,_ := mqPool.Get()//实例化对象mqconn :=mq.(*amqp.Connection)//将连接放回连接池中defer mqPool.Put(mq)//开始操作rabbitmq...mqconn.Channel()//do something....}//rabbitmq rabbitmq连接池func rabbitmq() {//factory 创建连接的方法factory := func() (interface{}, error) { return amqp.Dial(mqurl) }//close 关闭连接的方法close := func(v interface{}) error { return v.(net.Conn).Close() }//创建一个连接池: 初始化2,最大连接5,空闲连接数是4poolConfig := &Pool.Config{InitialCap: 2,MaxIdle: 5,MaxCap: 4,Factory: factory,Close: close,//连接最大空闲时间,超过该时间的连接 将会关闭,可避免空闲时连接EOF,自动失效的问题IdleTimeout: 15 * time.Second,}mqPool, _ = Pool.NewChannelPool(poolConfig)//从连接池中取得一个连接//v, err := p.Get()//do something//conn :=v.(*amqp.Connection)//将连接放回连接池中//p.Put(v)//释放连接池中的所有连接//p.Release()//查看当前连接中的数量current := mqPool.Len()fmt.Println("len=", current)return}//mysql mysql连接池func mysql() {}//redis redis连接池func redis() {}
最后测试一下连接池能不能正常使用
完美。。。