gRPC info
							parent
							
								
									d5e80d2c92
								
							
						
					
					
						commit
						1b1ddd9835
					
				| @ -20,6 +20,8 @@ Most communications between microservices are decoupled using the EventBus and t | ||||
| 
 | ||||
| For those explicit communications gRPC is used (instead of HTTP/JSON). gRPC is a RPC-based protocol that have great performance and low bandwidth usage, making it the best candidate for internal microservices communication. | ||||
| 
 | ||||
| More information about gRPC and eShopOnContainers can be found [here](./gRPC.md) | ||||
| 
 | ||||
| ## API Gateways | ||||
| 
 | ||||
| The architecture also includes an implementation of the API Gateway pattern and Backend-For-Front-End (BFF), to publish simplified APIs and include additional security measures for hiding/securing the internal microservices from the client apps or outside consumers.  | ||||
|  | ||||
							
								
								
									
										140
									
								
								gRPC.md
									
									
									
									
									
								
							
							
								
								
								
								
								
								
									
										
										
									
									
								
							
						
						
									
										140
									
								
								gRPC.md
									
									
									
									
									
								
							| @ -2,6 +2,16 @@ | ||||
| 
 | ||||
| One of the big news on netcore 3.0 is the native support for gRPC. eShopOnContainers makes use of gRPC for internal microservice-to-microservice synchronous communication. Note that, in eShop most of the communication between microservices is decoupled and asynchronous using an Event Bus (we support RabbitMQ or Azure Service Bus). | ||||
| 
 | ||||
| gRPC is a high-perfomance communication protocol, based on HTTP/2 and protocol buffers. It should be the primary choice for direct communication between services (as oposed to other protocols like AMQP used for decoupled communication like queues or pub/sub). | ||||
| 
 | ||||
| Its benefits over using directly HTTP with JSON are: | ||||
| 
 | ||||
| * Protocol buffers are a binary, high-perfomance serialization mechanism. Depending on the language implementation protocol buffers can be up to 8x faster than JSON serialization while the messages can be around 60%-80% smaller. | ||||
| * Supports streaming of data | ||||
| * Contract between service and client is explicit (by using _proto_ files) | ||||
| 
 | ||||
| ## gRPC usage in eShopOnContainers | ||||
| 
 | ||||
| In current implementation use of gRPC is limited to the communication between aggregators and micro services. We have following synchronous communications between services in eShop: | ||||
| 
 | ||||
| 1. External clients (i. e. Xamarin App or Browser) to Api Gateways (BFFs): Use HTTP/REST | ||||
| @ -22,4 +32,132 @@ Following microservices expose gRPC endpoints: | ||||
| And following BFFs are gRPC clients: | ||||
| 
 | ||||
| * Mobile Shopping | ||||
| * Web Shopping | ||||
| * Web Shopping | ||||
| 
 | ||||
| ## gRPC implementation in eShopOnContainers | ||||
| 
 | ||||
| gRPC is language agnostic: all services are defined using _proto_ files (usually with the `.proto` extension). These files are based on the [protobuffer language](https://developers.google.com/protocol-buffers/docs/proto), and define the interface of the service. Based on the _proto_ file, a code for creating the server and the client can be generated for every language. The canonical tool is _protoc_ which supports generate C# code. | ||||
| 
 | ||||
| Starting from netcore3, gRPC is deeply integrated in both, the tooling and the framework, to make the experience of using gRPC as seamless as possible. | ||||
| 
 | ||||
| ### Generating server or client stubs from proto file in Net Core 3 | ||||
| 
 | ||||
| The tooling, integrated in msbuild (so it can be used by Visual Studio but also by the `dotnet build` SDK command), allows the generation of the code needed to create a gRPC server or client based on a _proto_ file. The _proto_ file has to be referenced in the `csproj` using a `<ProtoBuf>` tag (inside a `<ItemGroup>`): | ||||
| 
 | ||||
| ```xml | ||||
|   <ItemGroup> | ||||
|     <Protobuf Include="Protos\catalog.proto" GrpcServices="Client" /> | ||||
|   </ItemGroup> | ||||
| ``` | ||||
| 
 | ||||
| The `GrpcServices` attributes is for specifying if a `Server` stub has to be generated, or a `Client` one. | ||||
| 
 | ||||
| >**Note** You can include as many `<Protobuf>` tags as you need.  | ||||
| 
 | ||||
| When you compile the code (either by running _Build_ from Visual Studio or `dotnet build`) all code will be generated and placed in the `obj` folder. This is intentionally: this code should never be in the source control repository. | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| ### Creating the gRPC server | ||||
| 
 | ||||
| The server stub generated code, defines an abstract base class with a set of abstract methods, that you have to implement. You will have one abstract method for every rpc method defined in the _proto_ file. | ||||
| 
 | ||||
| So, given a _proto_ file that define the following methods: | ||||
| 
 | ||||
| ``` | ||||
| service Catalog { | ||||
|   rpc GetItemById (CatalogItemRequest) returns (CatalogItemResponse) {} | ||||
|   rpc GetItemsByIds (CatalogItemsRequest) returns (PaginatedItemsResponse) {}  | ||||
| ``` | ||||
| 
 | ||||
| A `CatalogBase` abstract class will be generated: | ||||
| 
 | ||||
| ```cs | ||||
| public class CatalogService : CatalogBase | ||||
| { | ||||
|     public CatalogService() | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     public override async Task<CatalogItemResponse> GetItemById(CatalogItemRequest request, ServerCallContext context) | ||||
|     { | ||||
|         // Code | ||||
|     } | ||||
| 
 | ||||
|     public override async Task<PaginatedItemsResponse> GetItemsByIds(CatalogItemsRequest request, ServerCallContext context) | ||||
|     { | ||||
|         // Code | ||||
|     } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| All needed C# types for parameters and return values will be generated automatically. | ||||
| 
 | ||||
| ### Adding the gRPC pipeline into ASP.NET Core | ||||
| 
 | ||||
| ASP.NET Core supports direct integration of the gRPC pipeline. Only need to use the method `MapGrpcService` of the `IEndpointRouteBuilder` in your `Startup` class: | ||||
| 
 | ||||
| ```cs | ||||
| app.UseEndpoints(endpoints => | ||||
| { | ||||
|     endpoints.MapDefaultControllerRoute(); | ||||
|     endpoints.MapControllers(); | ||||
|     endpoints.MapGrpcService<CatalogService>(); | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| ### Creating the gRPC client | ||||
| 
 | ||||
| If you are creating a gRPC client instead of a server, you need to create a `GrpChannel` and then a gRPC client using this channel: | ||||
| 
 | ||||
| ```cs | ||||
| var channel = GrpcChannel.ForAddress(UrlOfService); | ||||
| var client = new Basket.BasketClient(channel); | ||||
| ``` | ||||
| 
 | ||||
| The class `Basket.BasketClient` is the stub generated from the _proto_ file. Then you can call the methods of the `BasketClient` class. | ||||
| 
 | ||||
| ### Using gRPC without TLS | ||||
| 
 | ||||
| gRPC works with HTTP/2 only. Usually when a client connects to a server, the connection is done using HTTP1.1 and promoted to HTTP/2 only if both, server and client, support HTTP/2. This promotion is performed using a protocol negotiation, usually implemented using ALPN protocol which requires TLS. | ||||
| 
 | ||||
| **That means, that by default, you need to have a TLS endpoint enabled to be able to use gRPC.** | ||||
| 
 | ||||
| However in internal microservices, maybe you don't have a TLS enabled endpoints (because those endpoints are internal). In this case you have two options: | ||||
| 
 | ||||
| * Open a single Kestrel endpoint, listening on HTTP/2 | ||||
| * Open two Kestrel endpoints, one listening on HTTP1.1 the other listening on HTTP/2 | ||||
| 
 | ||||
| The second option is the one needed if your server must support HTTP1.1 clients other than gRPC clients. Following C# code (in `Program.cs`) shows the second approach: | ||||
| 
 | ||||
| ```cs | ||||
| WebHost.CreateDefaultBuilder(args) | ||||
|     .ConfigureKestrel(options => | ||||
|     { | ||||
|         options.Listen(IPAddress.Any, ports.httpPort, listenOptions => | ||||
|         { | ||||
|             listenOptions.Protocols = HttpProtocols.Http1AndHttp2; | ||||
|         }); | ||||
|         options.Listen(IPAddress.Any, ports.grpcPort, listenOptions => | ||||
|         { | ||||
|             listenOptions.Protocols = HttpProtocols.Http2; | ||||
|         }); | ||||
| 
 | ||||
|     }) | ||||
| ``` | ||||
| 
 | ||||
| But, this is not enough. We need to tell the gRPC client, that can connect directly to a HTTP/2 endpoint, without the need to have TLS. By default netcore don't allow a gRPC client connect to a non-TLS endpoint. | ||||
| 
 | ||||
| Following lines are needed on the client: | ||||
| 
 | ||||
| ```cs | ||||
| AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); | ||||
| AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", true); | ||||
| ``` | ||||
| 
 | ||||
| Those settings could be set only once at the beginning of the client. | ||||
| 
 | ||||
| ## More information | ||||
| 
 | ||||
| * [gRPC](https://grpc.io/) | ||||
| * [Introduction to gRPC services](https://docs.microsoft.com/en-us/aspnet/core/grpc/?view=aspnetcore-3.0) | ||||
							
								
								
									
										
											BIN
										
									
								
								images/grpc/grpc-1.png
									
									
									
									
									
										Normal file
									
								
							
							
								
									
								
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								images/grpc/grpc-1.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 52 KiB | 
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user