什麼是GRPC
gRPC是一種與語言無關的高效能遠端過程呼叫 (RPC) 框架。gRPC 的主要好處是:
- 現代、高效能、輕量級的 RPC 框架。
- 契約優先的 API 開發,預設使用協議緩衝區,與語言無關的實現。
- 可用於多種語言的工具來生成強型別伺服器和客戶端。
- 支援客戶端、伺服器和雙向流呼叫。
- 通過 Protobuf 二進位制序列化減少網路使用。
這些優勢使 gRPC 非常適合:
- 效率至關重要的輕量級微服務。
- 需要多種語言進行開發的多語言系統。
- 需要處理流請求或響應的點對點實時服務。
什麼是grpc-json轉碼器
grpc-json轉碼器是一個過濾器,它允許 RESTful JSON API 客戶端通過 HTTP 向 Envoy 傳送請求並代理到 gRPC 服務。下面我們來通過Envoy的grpc-json轉碼器實現grpc服務的代理
建立grpc服務
.NET中的grpc可以參考官方文件來實現。我們通過vs建立兩個預設的grpc server:GrpcService1與GrpcService2
修改GrpcService1的預設埠為6001
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseUrls("http://*:6001").UseStartup<Startup>(); });
修改GrpcService2的預設埠為6002
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseUrls("http://*:6002").UseStartup<Startup>(); });
修改GrpcService1的GreeterService.SayHello方法
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context) { return Task.FromResult(new HelloReply { Message = "Hello 1 " + request.Name }); }
修改GrpcService2的GreeterService.SayHello方法
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context) { return Task.FromResult(new HelloReply { Message = "Hello 2 " + request.Name }); }
下面我們啟動兩個GrpcService
Grpc服務描述符
Envoy必須知道GRPC服務的proto描述符才能轉碼,通過以下連結下載proto工具
https://github.com/protocolbuffers/protobuf/releases
通過以下命令生成描述符
protoc.exe --descriptor_set_out=C:\greet.pb --include_imports C:\greet.proto --proto_path=C://
配置Envoy
Grpc相關的配置可以參考官方文件,其中需要注意的是我們需要將dns_type改為static,因為我們grpc用的是ip而不是域名;並且需要指定auto_mapping: true,這樣就可以在我們沒有設定http method的情況下路由到我們的grpc服務中的方法。具體配置如下
admin: address: socket_address: {address: 0.0.0.0, port_value: 9901} static_resources: listeners: - name: listener1 address: socket_address: {address: 0.0.0.0, port_value: 10000} filter_chains: - filters: - name: envoy.filters.network.http_connection_manager typed_config: "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager stat_prefix: grpc_json codec_type: AUTO route_config: name: local_route virtual_hosts: - name: local_service domains: ["*"] routes: - match: {prefix: "/greet.Greeter"} route: {cluster: grpc, timeout: 60s} http_filters: - name: envoy.filters.http.grpc_json_transcoder typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder proto_descriptor: "/etc/envoy/greet.pb" services: ["greet.Greeter"] print_options: add_whitespace: true always_print_primitive_fields: true always_print_enums_as_ints: false preserve_proto_field_names: false auto_mapping: true - name: envoy.filters.http.router clusters: - name: grpc type: static lb_policy: ROUND_ROBIN dns_lookup_family: V4_ONLY typed_extension_protocol_options: envoy.extensions.upstreams.http.v3.HttpProtocolOptions: "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions explicit_http_config: http2_protocol_options: {} load_assignment: cluster_name: grpc endpoints: - lb_endpoints: - endpoint: address: socket_address: address: 192.168.43.94 port_value: 6001 - endpoint: address: socket_address: address: 192.168.43.94 port_value: 6002
啟動Envoy
需要主要的是,我們需要將envoy.yaml和描述檔案都對映到我們的容器內
docker run --rm -it -p 9902:9902 -p 10000:10000 -v D:/gateway/envoy/config/grpc/:/etc/envoy/ -v D:/gateway/envoy/logs:/logs envoyproxy/envoy-dev -c /etc/envoy/envoy.yaml
測試
轉碼器過濾器處理的請求路徑規則是/<package>.<service>/<method>,另外我們需要使用POST方法。
通過postman呼叫介面來看,我們成功利用GRPC-Json轉碼器實現了grpc的代理。