gRPC负载均衡

gRPC负载均衡

负载均衡是gRPC的关键特性之一,它允许将来自客户端的请求分发到多个服务器上。这有助于防止任何一台服务器过载,并允许系统通过添加更多服务器进行扩展。

名称解析器为gRPC负载平衡策略提供服务器IP地址列表。策略负责维护到服务器的连接(子通道),并在发送RPC请求时选择要使用的连接。

官方文档

配置方法

gRPC提供了一些负载均衡策略值得注意的是 “pick_first”(默认值),“round_robin” 和 “grpclb”。

在客户端调用 “grpc.Dial()” 方法来建立与服务端连接时,使用 “grpc.WithDefaultServiceConfig()” 传入配置选项,配置项使用 json 格式。

例如下面的代码,配置了 “round_robin” 负载均衡策略。

// 连接到服务端,配置 “round_robin” 负载均衡策略
conn, err := grpc.Dial(
    "scheme:///serviceName",
    grpc.WithTransportCredentials(insecure.NewCredentials()),
    grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, roundrobin.Name)),
)

示例

接口定义

// 指定 proto 的版本
syntax = "proto3";

// 指定生成的 go 文件存放位置及其包名
option go_package = ".;proto";

// 定义服务
service Hello {
    rpc SayHello(Request) returns (Response);
}

// 定义消息体
message Request {
    string requestName = 1;
}

message Response {
    string responseMsg = 1;
}

服务端

package main

import (
	pb "GoStudy/grpc/load_balance/proto"
	"context"
	"fmt"
	"net"
	"sync"

	"google.golang.org/grpc"
)

var addrs = []string{"localhost:8811", "localhost:8812", "localhost:8813"}

type server struct {
	pb.UnimplementedHelloServer
	addr string
}

func (s *server) SayHello(ctx context.Context, req *pb.Request) (*pb.Response, error) {
	return &pb.Response{ResponseMsg: "Hello " + req.GetRequestName() + " [FROM ]" + s.addr}, nil
}

func SatrtServer(addr string) {
	// 开启监听端口
	lis, _ := net.Listen("tcp", addr)
	// 创建gRPC服务
	grpcServer := grpc.NewServer()
	// 在grpc服务端注册我们编写的服务
	pb.RegisterHelloServer(grpcServer, &server{addr: addr})

	// 启动服务
	err := grpcServer.Serve(lis)
	if err != nil {
		fmt.Printf("grpcServer start failed: %v", err)
		return
	}
}

func main() {
	var wg sync.WaitGroup
	for _, addr := range addrs {
		wg.Add(1)
		go func(addr string) {
			defer wg.Done()
			SatrtServer(addr)
		}(addr)
	}
	wg.Wait()
}

客户端

package main

import (
	pb "GoStudy/grpc/load_balance/proto"
	"context"
	"fmt"

	"google.golang.org/grpc"
	"google.golang.org/grpc/balancer/roundrobin"
	"google.golang.org/grpc/credentials/insecure"
)

const (
	scheme      = "example"
	serviceName = "hello"
)

func main() {
	// 连接到服务端,未使用安全连接
	conn, err := grpc.Dial(
		scheme+":///"+serviceName,
		grpc.WithTransportCredentials(insecure.NewCredentials()),
		grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, roundrobin.Name)),
	)
	if err != nil {
		fmt.Printf("connect to grpcServer failed: %v", err)
		return
	}
	defer conn.Close()

	// 创建 grpc 客户端
	client := pb.NewHelloClient(conn)

	// 执行 rpc 调用
	for i := 0; i < 10; i++ {
		resp1, _ := client.SayHello(context.Background(), &pb.Request{RequestName: "Macle"})
		fmt.Println(resp1.GetResponseMsg())
	}
}

名称解析器(Resolver)

因为 gRPC 默认使用 DNS 解析方案,在本地不方便进行测试使用,所以此处实现了一个简易的 Resolver。

package main

//实现自定义的名称解析器
import (
	"google.golang.org/grpc/resolver"
)

var addrs = []string{"localhost:8811", "localhost:8812", "localhost:8813"}

func init() {
	resolver.Register(&exampleResolverBuilder{})
}

type exampleResolver struct {
	cc    resolver.ClientConn
	addrs []string
}

func (e *exampleResolver) ResolveNow(resolver.ResolveNowOptions) {}

func (e *exampleResolver) Close() {}

func (e *exampleResolver) updateState() {
	var addrList resolver.State
	for _, addr := range e.addrs {
		addrList.Addresses = append(addrList.Addresses, resolver.Address{Addr: addr})
	}
	e.cc.UpdateState(addrList)
}

type exampleResolverBuilder struct{}

func (b *exampleResolverBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {
	er := &exampleResolver{
		cc:    cc,
		addrs: addrs,
	}

	er.updateState()

	return er, nil
}

func (b *exampleResolverBuilder) Scheme() string {
	return scheme
}

目录结构如下

load_balance
    │
    ├─client
    │      main.go
    │      resolver.go
    │
    ├─proto
    │      hello.pb.go
    │      hello.proto
    │      hello_grpc.pb.go
    │
    └─server
            main.go

运行结果

启动服务后,再运行客户端。
可以看到客户端发起了十次RPC调用,结果基本符合轮询特征。

PS E:\GoStudy\grpc\load_balance\client> go run .\main.go .\resolver.go
Hello Macle [FROM ]localhost:8812
Hello Macle [FROM ]localhost:8813
Hello Macle [FROM ]localhost:8811
Hello Macle [FROM ]localhost:8812
Hello Macle [FROM ]localhost:8813
Hello Macle [FROM ]localhost:8811
Hello Macle [FROM ]localhost:8812
Hello Macle [FROM ]localhost:8813
Hello Macle [FROM ]localhost:8811
Hello Macle [FROM ]localhost:8812
PS E:\GoStudy\grpc\load_balance\client> 
posted @ 2023-06-10 22:07  爱十三的柒  阅读(182)  评论(0)    收藏  举报