load_balancing.go 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. package main
  2. import (
  3. "../clientImpl"
  4. "../constants"
  5. "fmt"
  6. "google.golang.org/grpc"
  7. "google.golang.org/grpc/balancer/roundrobin"
  8. "google.golang.org/grpc/resolver"
  9. "log"
  10. "time"
  11. )
  12. // gRPC官方库负载均衡实现示例,客户端,参考 https://grpc-up-and-running.github.io/
  13. func main() {
  14. // 以服务命名来建立与实际服务终结点的连接,默认仅连接第一个终结点
  15. pickFirstConn, err := grpc.Dial(
  16. fmt.Sprintf("%s:///%s", constants.ExampleScheme, constants.ExampleServiceName), // "grpc:///go-example" 注意必须是三个斜杠
  17. grpc.WithInsecure(),
  18. )
  19. if err != nil {
  20. log.Fatalf("did not connect: %v", err)
  21. }
  22. defer func() {
  23. _ = pickFirstConn.Close()
  24. }()
  25. log.Println("==== Calling go-example with pick_first ====")
  26. clientImpl.MakeCalls(pickFirstConn, 10)
  27. // 以服务命名来建立与实际服务终结点的连接,设置以轮询策略连接
  28. roundRobinConn, err := grpc.Dial(
  29. fmt.Sprintf("%s:///%s", constants.ExampleScheme, constants.ExampleServiceName), // "grpc:///go-example" 注意必须是三个斜杠
  30. //grpc.WithBalancerName(roundrobin.Name), // 官方仅提供pick first和round robin两种策略,更多负载均衡策略找第三方或自己实现
  31. // 因为WithBalancerName过时了,推荐用WithDefaultServiceConfig,其参数是个服务配置的JSON
  32. // 可配置的项目包括超时时间、最大请求响应大小等,参考 https://github.com/grpc/grpc/blob/master/doc/service_config.md
  33. grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"loadBalancingPolicy":"%s"}`, roundrobin.Name)),
  34. grpc.WithInsecure(),
  35. )
  36. if err != nil {
  37. log.Fatalf("did not connect: %v", err)
  38. }
  39. defer func() {
  40. _ = roundRobinConn.Close()
  41. }()
  42. log.Println("==== Calling go-example with round_robin ====")
  43. clientImpl.MakeCalls(roundRobinConn, 10)
  44. // 停顿10秒再请求,此时可手工增减服务端启动的端口监听,以测试服务端部分节点掉线或新节点上线的情况
  45. println(`sleeping ------------------------------------------------------->`)
  46. time.Sleep(10 * time.Second)
  47. clientImpl.MakeCalls(roundRobinConn, 10)
  48. }
  49. // 将resolver添加进resolvers map,必须在init函数中
  50. // 服务命名和实际服务终结点列表的映射关系即在此时建立
  51. // 此方案最不可行之处在于,在k8s这样的动态环境上,需要花费额外的成本和复杂度来维护这个映射
  52. func init() {
  53. resolver.Register(&clientImpl.ExampleResolverBuilder{})
  54. }