grpc外部負荷イコライザテスト

10917 ワード

grpc外部負荷イコライザテスト


(金慶のコラム2020.4)
grpcは、各リクエストに対して負荷等化を行う.負荷の均等化には、次の方法があります.
  • プロキシモード
  • クライアント実装
  • 外部負荷等化
  • 参考:gRPC LBhttps://blog.csdn.net/xiaojia1100/article/details/78842295
    gRPCにおける負荷等化の主なメカニズムは外部負荷等化である.
    gRPCは、外部負荷等化サービスのインタフェースを定義します.https://github.com/grpc/grpc/tree/master/src/proto/grpc/lb/v1
  • load_balancer.protoクライアントはlb服にバックエンドリスト
  • を問い合わせる.
  • load_reporter.proto lb服向後端服照会負荷
  • https://github.com/bsm/grpclbgrpcの外部負荷等化服を実現した.負荷等化服のインタフェース仕様よりも早く実現されるため、インタフェース定義はgrpc仕様とは異なる.issue 26を参照:https://github.com/bsm/grpclb/issues/26#issuecomment-613873655 grpclbは現在、consulサービス発見のみをサポートしています.
    標準的なgrpclb実装は現在、https://github.com/joa/jawlb. JAwlbはKubernetes APIを介してサービスを発見する.
    次のテストgrpcクライアントはjawlb服からサーバリストをクエリーし、サービスを要求します.まず、本機で複数のgreeter服のインスタンスを開き、ポートが異なります.その後greeterクライアントを変更し、greeter服アドレスに直接接続するのではなくjawlb服アドレスを割り当てます.同時にjawlbを変更し、サービス発見を削除し、固定出力ローカルサービスリストに変更し、タイミングを切り替えます.
    greeterとはgrpc-goの例です:grpc-goexampleshelloworldgreeter

    greeter服変更


    パラメータを追加してサービスポートを指定します.
    package main
    
    import (
    	"fmt"
    	"log"
    	"net"
    
    	"github.com/spf13/pflag"
    	"github.com/spf13/viper"
    	"golang.org/x/net/context"
    	"google.golang.org/grpc"
    	pb "google.golang.org/grpc/examples/helloworld/helloworld"
    )
    
    // GreeterServer is used to implement helloworld.GreeterServer.
    type GreeterServer struct {
    }
    
    // SayHello implements helloworld.GreeterServer
    func (s *GreeterServer) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    	msg := fmt.Sprintf("Hello %s from server-%d", in.Name, viper.GetInt("port"))
    	return &pb.HelloReply{Message: msg}, nil
    }
    
    func main() {
    	pflag.Int("port", 8000, "server bind port")
    	pflag.Parse()
    	viper.BindPFlags(pflag.CommandLine)
    	port := viper.GetInt("port")
    
    	addr := fmt.Sprintf(":%d", port)
    	lis, err := net.Listen("tcp", addr)
    	if err != nil {
    		log.Fatalf("failed to listen: %v", err)
    	}
    	s := grpc.NewServer()
    	pb.RegisterGreeterServer(s, &GreeterServer{})
    	s.Serve(lis)
    }
    

    greeterクライアント変更

    package main
    
    import (
    	"context"
    	"log"
    	"os"
    	"time"
    
    	"github.com/sirupsen/logrus"
    	"google.golang.org/grpc"
    	_ "google.golang.org/grpc/balancer/grpclb"
    	pb "google.golang.org/grpc/examples/helloworld/helloworld"
    	"google.golang.org/grpc/grpclog"
    	"google.golang.org/grpc/resolver"
    	"google.golang.org/grpc/resolver/manual"
    )
    
    const (
    	defaultName = "world"
    )
    
    func init() {
    	grpclog.SetLogger(logrus.New())
    }
    
    func main() {
    	rb := manual.NewBuilderWithScheme("whatever")
    	rb.InitialState(resolver.State{Addresses: []resolver.Address{
    		{Addr: "127.0.0.1:8888", Type: resolver.GRPCLB},
    	}})
    
    	conn, err := grpc.Dial("whatever:///this-gets-overwritten", grpc.WithInsecure(), grpc.WithBlock(),
    		grpc.WithResolvers(rb))
    	if err != nil {
    		log.Fatalf("did not connect: %v", err)
    	}
    	defer conn.Close()
    	c := pb.NewGreeterClient(conn)
    
    	name := defaultName
    	if len(os.Args) > 1 {
    		name = os.Args[1]
    	}
    
    	for {
    		ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
    		r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
    		cancel()
    
    		if err != nil {
    			log.Fatalf("could not greet: %v", err)
    			time.Sleep(time.Second)
    			continue
    		}
    
    		log.Printf("Greeting: %s", r.GetMessage())
    		time.Sleep(time.Second)
    	}
    }
    

    次の変更があります.
  • import _ “google.golang.org/grpc/balancer/grpclb”
  • grpc.Dial(“whatever:///this-gets-overwritten”, grpc.WithResolvers(rb))
  • jawlbアドレス
  • を取得するためのカスタム解析器を採用する
  • Scheme(「whatever」)は任意で、解析器名
  • として使用できます.
  • ターゲットthis-gets-overwrittenはjawlbが
  • という名前を無視しているため、任意に使用できます.
  • 127.0.0.1:8888はjawlbアドレス
  • である.
  • は、1秒間に1回の
  • を要求するように変更する.
    通常のgrpclbはDNSにSRVレコードを設定し、ここでDNSの設定を避けるテストを行い、カスタム解析器を採用し、コードに数行増えた.DNSで設定するメリットは、バックエンドIPとして直接解析したり、grpclbを追加したりすることで、コード上でバックエンドに直接接続するようにすることができます.
    	conn, err := grpc.Dial("dns:///myservice.domain.com", grpc.WithInsecure())
    

    JAwlb変更


    main.go


    すべての構成を削除し、ホスト8888ポートのリスニングを固定するように変更します.
  • 削除envconfig.MustProcess("JAWLB", &cfg)
  • listen()を
    func listen() (conn net.Listener, err error) {
    	conn, err = net.Listen("tcp", ":8888")
    	return
    }
    
  • に変更

    watch.go

    package main
    
    import (
    	"context"
    	"fmt"
    	"net"
    	"time"
    )
    
    func watchService(ctx context.Context) (_ 

    すべてのサービス発見コードを削除し、10秒ごとにポートを切り替えるように変更します:80108020 8018021

    うんてん


    jawlb

    λ jawlb.exe
    2020/04/16 15:35:17 waiting for TERM
    i = 1
    2020/04/16 15:35:27 endpoints:
    2020/04/16 15:35:27     127.0.0.1:8011
    2020/04/16 15:35:27     127.0.0.1:8021
    i = 2
    2020/04/16 15:35:37 endpoints:
    2020/04/16 15:35:37     127.0.0.1:8010
    2020/04/16 15:35:37     127.0.0.1:8020
    

    server


    4つのインスタンスを実行します.
    server --port 8010
    server --port 8020
    server --port 8011
    server --port 8021
    

    client

    λ client
    INFO[0002] lbBalancer: handle SubConn state change: 0xc00008a590, CONNECTING
    INFO[0002] Channel Connectivity change to CONNECTING
    INFO[0002] lbBalancer: handle SubConn state change: 0xc00008a5f0, CONNECTING
    INFO[0002] Subchannel picks a new address "127.0.0.1:8021" to connect
    INFO[0002] Subchannel Connectivity change to READY
    INFO[0002] lbBalancer: handle SubConn state change: 0xc00008a590, READY
    INFO[0002] Channel Connectivity change to READY
    INFO[0002] Subchannel Connectivity change to READY
    INFO[0002] lbBalancer: handle SubConn state change: 0xc00008a5f0, READY
    2020/04/16 15:37:47 Greeting: Hello world from server-8021
    2020/04/16 15:37:48 Greeting: Hello world from server-8011
    2020/04/16 15:37:49 Greeting: Hello world from server-8021
    2020/04/16 15:37:50 Greeting: Hello world from server-8011
    2020/04/16 15:37:51 Greeting: Hello world from server-8021
    2020/04/16 15:37:52 Greeting: Hello world from server-8011
    2020/04/16 15:37:53 Greeting: Hello world from server-8021
    2020/04/16 15:37:54 Greeting: Hello world from server-8011
    2020/04/16 15:37:55 Greeting: Hello world from server-8021
    2020/04/16 15:37:56 Greeting: Hello world from server-8011
    INFO[0012] lbBalancer: processing server list: servers: servers:
    INFO[0012] lbBalancer: server list entry[0]: ipStr:|127.0.0.1|, port:|8020|, load balancer token:||
    INFO[0012] lbBalancer: server list entry[1]: ipStr:|127.0.0.1|, port:|8010|, load balancer token:||
    2020/04/16 15:37:57 Greeting: Hello world from server-8020
    2020/04/16 15:37:58 Greeting: Hello world from server-8010
    2020/04/16 15:37:59 Greeting: Hello world from server-8020
    2020/04/16 15:38:00 Greeting: Hello world from server-8010
    2020/04/16 15:38:01 Greeting: Hello world from server-8020
    2020/04/16 15:38:02 Greeting: Hello world from server-8010
    2020/04/16 15:38:03 Greeting: Hello world from server-8020
    2020/04/16 15:38:04 Greeting: Hello world from server-8010
    2020/04/16 15:38:05 Greeting: Hello world from server-8020
    2020/04/16 15:38:06 Greeting: Hello world from server-8010
    INFO[0022] lbBalancer: processing server list: servers: servers:
    INFO[0022] lbBalancer: server list entry[0]: ipStr:|127.0.0.1|, port:|8021|, load balancer token:||
    INFO[0022] lbBalancer: server list entry[1]: ipStr:|127.0.0.1|, port:|8011|, load balancer token:||
    2020/04/16 15:38:07 Greeting: Hello world from server-8011
    2020/04/16 15:38:08 Greeting: Hello world from server-8021
    2020/04/16 15:38:09 Greeting: Hello world from server-8011
    

    結論


    クライアントはカスタムresolver解析を適用します」whatever:///this-gets-overwritten{Addr: "127.0.0.1:8888", Type: resolver.GRPCLB}を取得し、grpclbであることを知り、load_を押した.balancer.protoの定義クエリーjawlbは、バックエンドアドレスリストを取得します.
    JAwlbは10 sごとにサーバリストを更新し,複数のアドレスを出力する.クライアントは、複数のアドレス間で要求を交代します.

    その他のテスト

  • jawlbを開かないと、クライアントはjawlbが開くまで要求に成功できません.
  • jawlbを途中で閉じてもリクエストは成功しますが、最後のサーバリストに保持されます.
  • 同時にjawlbの再接続を試みますが、再接続に成功した後、サービスを切り替えていません.エラー
  • であるはずです.
  • Dial()grpcを付けない.WithBlock()パラメータ、エラー:all SubConns are in TransientFailure
  • λ client
    INFO[0000] parsed scheme: "whatever"
    INFO[0000] ccResolverWrapper: sending update to cc: {[{127.0.0.1:8888   1 }]  }
    INFO[0000] ClientConn switching balancer to "grpclb"
    INFO[0000] Channel switches to new LB policy "grpclb"
    INFO[0000] lbBalancer: UpdateClientConnState: {ResolverState:{Addresses:[{Addr:127.0.0.1:8888 ServerName: Attributes: Type:1 Metadata:}] ServiceConfig: Attributes:} BalancerConfig:}
    INFO[0000] parsed scheme: "grpclb-internal"
    INFO[0000] ccResolverWrapper: sending update to cc: {[{127.0.0.1:8888   0 }]  }
    INFO[0000] ClientConn switching balancer to "pick_first"
    INFO[0000] Channel switches to new LB policy "pick_first"
    INFO[0000] Subchannel Connectivity change to CONNECTING
    INFO[0000] blockingPicker: the picked transport is not ready, loop back to repick
    INFO[0000] pickfirstBalancer: HandleSubConnStateChange: 0xc00003fb10, {CONNECTING }
    INFO[0000] Channel Connectivity change to CONNECTING
    INFO[0000] Subchannel picks a new address "127.0.0.1:8888" to connect
    INFO[0000] CPU time info is unavailable on non-linux or appengine environment.
    INFO[0000] Subchannel Connectivity change to READY
    INFO[0000] pickfirstBalancer: HandleSubConnStateChange: 0xc00003fb10, {READY }
    INFO[0000] Channel Connectivity change to READY
    INFO[0000] lbBalancer: processing server list: servers: servers:
    INFO[0000] lbBalancer: server list entry[0]: ipStr:|127.0.0.1|, port:|8010|, load balancer token:||
    INFO[0000] lbBalancer: server list entry[1]: ipStr:|127.0.0.1|, port:|8020|, load balancer token:||
    INFO[0000] Subchannel Connectivity change to CONNECTING
    INFO[0000] Subchannel Connectivity change to CONNECTING
    INFO[0000] Channel Connectivity change to TRANSIENT_FAILURE
    INFO[0000] lbBalancer: handle SubConn state change: 0xc00008a220, CONNECTING
    INFO[0000] Channel Connectivity change to CONNECTING
    INFO[0000] lbBalancer: handle SubConn state change: 0xc00008a280, CONNECTING
    2020/04/16 16:40:06 could not greet: rpc error: code = Unavailable desc = all SubConns are in TransientFailure