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)
}

在使用的时候,由于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
}

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调用
}

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

你可能感兴趣的:(golang,开发语言,后端)