Go中的gRPC客户端负载平衡

负载均衡器(LB)是可扩展且强大的应用程序的关键要素之一。 该关键组件在微服务体系结构中起着重要作用,并具有两种主要类型:客户端和代理LB。

有许多实现LB的可用解决方案,并且客户端或代理之间的决定是体系结构选择的问题。

进一步阅读:https://grpc.io/blog/loadbalancing

为什么要在客户端?

尽管客户端LB增加了复杂性,并且在大多数情况下都被认为不如代理LB,但在要求低延迟和低开销时,它尤其有用。 通过这种方法,客户端可以完全了解可用的服务器,并且可以以幼稚的方式获得良好的结果。

gRPC客户端LB

gRPC中LB的基本要求是将通道的每个RPC调用都定向到不同的服务器。 但是,由于gRPC是HTTP / 2协议之上的薄层,并且每个RPC调用都对应于HTTP / 2流,所以最终结果是所有RPC调用都发送到同一服务器。

gRPC的原始版本具有循环LB的基本实现。 解析器根据解析的A记录解析DNS记录,客户端在服务器上知道并在服务器之间执行负载平衡。

但是,尽管听起来很简单,但gRPC-go文档并不是最好的*。

工作实例

在此示例中,我将以gRPC Hello-World客户端示例为例,并对其进行修改以使其以循环方式工作。

 包主 
 导入( 
“上下文”
“日志”
  “ google.golang.org/grpc” 
“ google.golang.org/grpc/balancer/roundrobin”
pb“ google.golang.org/grpc/examples/helloworld/helloworld”
“ google.golang.org/grpc/resolver”
  const( 
地址=“ DNS记录名称:443”
defaultName =“世界”
  func main(){ 
//秘诀
resolver.SetDefaultScheme(“ dns”)
  //建立与服务器的连接。 
conn,err:= grpc.Dial(地址,grpc.WithInsecure(),grpc.WithBalancerName(roundrobin.Name))
如果err!= nil {
log.Fatalf(“未连接:%v”,错误)
}
延迟conn.Close()
c:= pb.NewGreeterClient(conn)
  //以循环方式联系服务器。 
对于我:= 0; 我<3; 我++ {
ctx:= context.Background()
r,err:= c.SayHello(ctx,&pb.HelloRequest {Name:defaultName})
如果err!= nil {
log.Fatalf(“无法打招呼:%v”,错误)
}
log.Printf(“问候:%s”,r.Message)
}
}

精明的读者会注意到我的两个更改,第一个是行grpc.Dial方法,指示grpc使用循环机制。 然而,第二个变化是所有魔术都有什么作用。 我在这个简短的博客文本https://www.marwan.io/blog/grpc-dns-load-balancing中偶然发现了resolver.SetDefaultScheme(“ dns”)

基本上,在不设置解析程序的默认方案的情况下,默认设置为“ passthrough”, 它不会执行任何操作。

这是grpc-go的passthrough.go的代码片段:

  func (* passthroughResolver)ResolveNow(o resolver.ResolveNowOption){} 

将方案设置为“ dns”时,grpc客户端使用解析器知道所有A记录。 此步骤发生在运输工具建立期间,并在其观察者中定期进行。

*我的假设是,社区不希望鼓励使用这种方法。 提到的gRPC Load Balancing文档推动了使用后备模式来支持胖客户端。