我们已经知道gRpc 是基于HTTP2.0 协议。然而,连接的建立,默认并不是一步到位直接基于HTTP2.0建立连接的。客户端是先基于HTTP1.1进行协议协商,协商成功后,确认服务端支持HTTP2.0后,才会建立HTT2.0连接,协议协商需要TLS的ALPN协议来实现。流程如下:
这意味着,默认情况下,您需要启用TLS协议才能完成HTTP2.0协议协商,进而才能使用gRPC。
然而,在微服务架构中,并不是所有服务都需要启用安全传输层协议,尤其是微服务间的内部调用。那么在微服务内部如何使用gRPC进行通信呢?
客户端绕过协议协商,直连HTTP2.0(前提是:服务端必须支持HTTP2.0)。
服务端配置如下:
WebHost.CreateDefaultBuilder(args) .ConfigureKestrel(options => { options.Listen(IPAddress.Any, ports.httpPort, listenOptions => { listenOptions.Protocols = HttpProtocols.Http1AndHttp2; //同时监听协议HTTP1,HTTP2 }); options.Listen(IPAddress.Any, ports.gRPCPort, listenOptions => { listenOptions.Protocols = HttpProtocols.Http2; // gRPC端口仅监听HTTP2.0 }); })客户端需要添加以下设置,这些设置只能在客户端开始时设置一次:
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", true);知道了这些,再回过来看GrpcCallerService的实现,就一目了然了。
public static class GrpcCallerService { public static async Task<TResponse> CallService<TResponse>(string urlGrpc, Func<GrpcChannel, Task<TResponse>> func) { AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", true); var channel = GrpcChannel.ForAddress(urlGrpc); /* using var httpClientHandler = new HttpClientHandler { ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; } }; */ Log.Information(@"Creating gRPC client base address urlGrpc ={@urlGrpc}, BaseAddress={@BaseAddress} ", urlGrpc, channel.Target); try { return await func(channel); } catch (RpcException e) { Log.Error("Error calling via gRPC: {Status} - {Message}", e.Status, e.Message); return default; } finally { AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", false); AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", false); } } public static async Task CallService(string urlGrpc, Func<GrpcChannel, Task> func) { AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", true); /* using var httpClientHandler = new HttpClientHandler { ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; } }; */ var channel = GrpcChannel.ForAddress(urlGrpc); Log.Debug("Creating gRPC client base address {@httpClient.BaseAddress} ", channel.Target); try { await func(channel); } catch (RpcException e) { Log.Error("Error calling via gRPC: {Status} - {Message}", e.Status, e.Message); } finally { AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", false); AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", false); } } } 最后本文简要介绍了 eShopOnContainers 如何通过集成 gRPC 来完善服务间同步通信机制,希望对你在对微服务进行RPC相关技术选型时有一定的启示和帮助。
参考资料:
HTTP2.0笔记之连接建立
eShopOnContainers/wiki/gRPC
Google Protocol Buffer 的使用和原理