一/检查grpc安装

后端服务之间的通信使用gRPC是常规方案,通过proto文件定义交互接口,通过工具生成gRPC

原始proto文件(截取自 grpc/example/helloworld.proto)

 21 package helloworld;
 22
 23 // The greeting service definition.
 24 service Greeter {
 25   // Sends a greeting
 26   rpc SayHello (HelloRequest) returns (HelloReply) {}
 27 }
 28
 29 // The request message containing the user's name.
 30 message HelloRequest {
 31   string name = 1;
 32 }
 33
 34 // The response message containing the greetings
 35 message HelloReply {
 36   string message = 1;
 37 }

首先检查grpc安装是否有问题,测试运行grpc example 是否正常

$ pwd    
$GOPATH/src/google.golang.org/grpc/examples/helloworld
$ go run greeter_server/main.go

//另一个窗口  another terminal
$ pwd
$GOPATH/src/google.golang.org/grpc/examples/helloworld
$ go run greeter_client/main.go
2019/04/03 10:53:00 Greeting: Hello world

如果以上步骤 都正常 ,那么grpc本身安装是没有问题的,如果出现故障,那么请参考grpc安装的文档。

二/配置准备

2.1 安装GOOGLEAPIS包

$ pwd
  $GOPATH/src/github.com/googleapis/
$ git clone https://github.com/googleapis/googleapis
  GOOGLEAPIS_DIR=<your-local-googleapis-folder>
$ echo $GOOGLEAPIS_DIR
  $GOPATH/src/github.com/googleapis/googleapis

配置环境变量 export GOOGLEAPIS_DIR= $GOPATH/src/github.com/googleapis/googleapis

2.2 修改proto文件

 14
 15 syntax = "proto3";
 16
 17 option java_multiple_files = true;
 18 option java_package = "io.grpc.examples.helloworld";
 19 option java_outer_classname = "HelloWorldProto";
 20 import "google/api/annotations.proto";   // #add
 21
 22 package helloworld;
 23
 24 // The greeting service definition.
 25 service Greeter {
 26   // Sends a greeting
 27   rpc SayHello (HelloRequest) returns (HelloReply) {
 28        option (google.api.http) = {        // #add
 29                    post: "/say"            // #add
 30                     body: "*"              // #add
 31
 32            };                              // #add
 33       }
 34
 35 }
 36


增加了 import “google/api/annotations.proto”;

增加了 option (google.api.http) 部分,主要作用是http请求路径

三/ Envoy配置与运行

3.1 envoy yml配置 s2s-grpc-envoy.yaml


static_resources:
  listeners:
  - name: listener1
    address:
      socket_address: { address: 0.0.0.0, port_value: 51051 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          stat_prefix: grpc_json
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route: { cluster: grpc, timeout: { seconds: 60 } }
          http_filters:
          - name: envoy.grpc_json_transcoder
            config:
              proto_descriptor: "/data/envoy/proto.pb"     #
              services: ["helloworld.Greeter"]             #
              print_options:
                add_whitespace: true
                always_print_primitive_fields: true
                always_print_enums_as_ints: false
                preserve_proto_field_names: false
          - name: envoy.router

  clusters:
  - name: grpc
    connect_timeout: 1.25s
    type: logical_dns
    lb_policy: round_robin
    dns_lookup_family: V4_ONLY
    http2_protocol_options: {}
    load_assignment:
      cluster_name: grpc
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                  address:  127.0.0.1  # host.docker.internal
                  port_value: 50051

3.2 docker 脚本

   protoc -I$GOOGLEAPIS_DIR -I. --include_imports --include_source_info   --descriptor_set_out=proto.pb  helloworld.proto
   echo "---------------------"
  
   docker run -it --rm --name envoy   --network="host"   \
    -v "$(pwd)/proto.pb:/data/envoy/proto.pb:ro" \
      -v "$(pwd)/s2s-grpc-envoy.yaml:/etc/envoy/envoy.yaml:ro" \
      envoyproxy/envoy

作用含义:

1/解析 helloworld.proto 输出为 proto.pb

2/ docker运行脚本 以host模式运行,可以访问本地服务 同时load proto.pb .yml

输出日志中有: starting main dispatch loop 基本说明配置ok

3.3 运行grpc client

开一个 terminal 运行

$ pwd    
$GOPATH/src/google.golang.org/grpc/examples/helloworld
$ go run greeter_server/main.go

四 测试http 访问grpc接口

curl -X POST \
  http://localhost:51051/say \
  -H 'Content-Type: application/json' \
  -d '{
	"name":"banana"
}'

正常返回值

 "message": "Hello banana"

五/错误处理

5.1 http header里面 关注以下两个

**grpc-status

**grpc-message

根据报错信息处理

5.2 no healthy upstream 错误

原因是 无法 访问到 上一级服务 gRPC server

主要检查yml中的 ip port是否正确 容器内是否能访问到gRPC server

         clusters: 
        socket_address:
              address:  127.0.0.1  # host.docker.internal
              port_value: 50051 本文使用的模式 是 

参考文档:

A Guide to Envoy’s Backpressure