gRPC与gRPC Connection Pool实现

Posted by 大攀 on Wednesday, November 18, 2020

TOC

gRPC

  gRPC是Google公司基于HTTP/2ProtoBuf序列化协议设计开发的高性能、开源的RPC框架。其支持多种开发语言,不同语言的客户端和服务端之间可以互相传递消息。

基本开发步骤:

  1. 定义服务的.proto文件(proto3语法),其中包括服务的请求、响应内容格式,以及服务方法;
  2. 使用protocol buffer编译器(可以使用gogoprotobuf)生成服务端和客户端RouteGuide代码;
  3. 使用gRPC API 使用编写的服务。

gRPC支持四种服务方法:简单RPC、服务端流式RPC、客户端流式RPC、双向流式RPC。

示例代码地址:https://github.com/xumamba/go-life/tree/master/example/grpc

gRPC 连接池

代码地址:https://github.com/xumamba/go-life/tree/master/library/grpcpool

设计目的:

  连接复用,节省创建连接和销毁连接的开销;

设计原则:

  • 连接超时处理
  • 连接心跳保活
  • 自定义连接建立方式、状态检测

接口设计:

// Pool connections pool
type Pool interface {
	// GetConn get a connection
	GetConn(addr string) (*grpc.ClientConn, error)
	// Dial force a new connection
	Dial(addr string) (*grpc.ClientConn, error)
	// GetViableConn get current viable connections
	GetViableConn() []string 
}

type ConnectionPool struct {
	locker sync.RWMutex
	ctx    context.Context
	cancel context.CancelFunc

	dialFunc       DialFunc
	stateCheckFunc StateCheckFunc
	connections    map[string]*gRPCConn
	viableConn     map[string]*gRPCConn

	expiresTime       time.Duration
	checkReadyTimeout time.Duration
	heartbeatInterval time.Duration
}

连接池使用:

import (
    "context"
    "fmt"
    
    "google.golang.org/grpc"
    "google.golang.org/grpc/connectivity"
    
    pb "go-life/example/grpc/base"
)

func TestGetConn(t *testing.T) {
	healthStateCheck := func(ctx context.Context, conn *grpc.ClientConn) connectivity.State {
		client := pb.NewGreeterClient(conn)
		_, err := client.HealthCheck(ctx, &pb.Request{Ping: "health check"})
		if err != nil {
			return connectivity.Idle
		}
		return connectivity.Ready
	}
	dial := func(addr string) (*grpc.ClientConn, error) {
		return grpc.Dial(addr, grpc.WithInsecure(), grpc.WithBlock())
	}
	cp := New(
		SetDialFunc(dial),
		SetStateCheckFunc(healthStateCheck),
		SetExpiresTime(5*time.Second),
		SetCheckReadyTimeout(1*time.Second),
		SetHeartbeatInterval(2*time.Second),
	)

	conn, err := cp.GetConn(serverAddr)
	if err != nil {
		t.Fatal(err)
	}
	client := pb.NewGreeterClient(conn)
	reply, err := client.SayHello(ctx, &pb.HelloRequest{Name: "hello gRPC connection pool"})
	fmt.Println(reply, err)
}

comments powered by Disqus