• golang工程——grpc 连接池简单实现


    grpc client连接池

    grpc连接池可以采用sync.Pool实现。 可以有效减少重复创建grpc连接的资源消耗

    package client_pool
    
    import (
    	"google.golang.org/grpc"
    	"google.golang.org/grpc/connectivity"
    	"log"
    	"sync"
    )
    
    // 用sync.pool实现
    
    var p sync.Pool
    
    type ClientPool interface {
    	Get() *grpc.ClientConn
    	Put(conn *grpc.ClientConn)
    }
    
    type clientPool struct {
    	pool sync.Pool
    }
    
    func GetPool(target string, opts ...grpc.DialOption)(ClientPool, error) {
    	return &clientPool{
    		pool: sync.Pool{
    			New: func() any {
    				conn, err := grpc.Dial(target, opts...)
    				if err != nil {
    					log.Println(err)
    					return nil
    				}
    				return conn
    			},
    		},
    	}, nil
    }
    
    func (c *clientPool) Get() *grpc.ClientConn {
    	conn := c.pool.Get().(*grpc.ClientConn)
    	// 如果连接关闭或者失败
    	if conn.GetState() == connectivity.Shutdown || conn.GetState() == connectivity.TransientFailure {
    		conn.Close()
    		conn = c.pool.New().(*grpc.ClientConn)
    	}
    
    	return conn
    }
    
    func (c *clientPool) Put(conn *grpc.ClientConn) {
    	if conn.GetState() == connectivity.Shutdown || conn.GetState() == connectivity.TransientFailure {
    		conn.Close()
    		conn = c.pool.New().(*grpc.ClientConn)
    	}
    	c.pool.Put(conn)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    在使用的时候,由于sync.Pool Get方法会pop处集合中的资源,使用完后需要Put回去

    func (p *Pool) Get() any {
    	if race.Enabled {
    		race.Disable()
    	}
    	l, pid := p.pin()
    	x := l.private
    	l.private = nil
    	if x == nil {
    		// Try to pop the head of the local shard. We prefer
    		// the head over the tail for temporal locality of
    		// reuse.
    		x, _ = l.shared.popHead()
    		if x == nil {
    			x = p.getSlow(pid)
    		}
    	}
    	runtime_procUnpin()
    	if race.Enabled {
    		race.Enable()
    		if x != nil {
    			race.Acquire(poolRaceAddr(x))
    		}
    	}
    	if x == nil && p.New != nil {
    		x = p.New()
    	}
    	return x
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    main.go

    func main() {
        flag.Parse()
    
    
        //conn, err := grpc.Dial(*addr, getDiaOption()...)
    
        // 根据协议+服务名 通过服务名称解析 访问服务器
        pool, err := client_pool.GetPool(*addr, getDiaOption()...)
    
        if err != nil {
            log.Fatal(err)
        }
        conn := pool.Get()
        // 重复使用连接,不用关闭
        defer pool.Put(conn)
        c := echo.NewEchoClient(conn)
        // grpc调用
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    最后,连接池里的对象只是临时的,golang gc的时候也会释放掉一些不用的对象,连接池的对象也并不是一直存在的。

  • 相关阅读:
    栈的应用----括号匹配问题
    现代企业管理笔记——管理概论
    9.20(复习9.19,9.17,9.13)
    2023年总结:不上班的这半年!
    博客摘录「 MPLS/LDP原理介绍+报文分析+配置示例」2023年9月26日
    基于YOLOv8模型的水下目标检测系统(PyTorch+Pyside6+YOLOv8模型)
    Android WebRTC 入门教程(二) -- 模拟p2p本地视频传输
    从零开始实现一个MyBatis加解密插件
    Go语言学习基础(二)编写注意,数据类型,关键字,标识符等
    设计模式有哪些?
  • 原文地址:https://blog.csdn.net/qq_43058348/article/details/133578198