High-performance services with gRPC: What's new in .NET 7 | .NET Conf 2022

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
>> Hello, everyone. My name is James Newton-King. Today I'm excited to talk to you about gRPC on.Net. The agenda for today's talk, first will give a quick introduction to gRPC for anyone who is new to it. As part of that, I'll demo testing gRPC app using a testing tool such as Postman. Then we'll take a look at what's new on.Net 7 and then we'll include performance improvements and new feature called gRPC JSON transcoding and gRPC support on Azure and how it's approved in the past year. What is gRPC? It's a popular open-source remote procedure called framework. RPC frameworks make it easy for apps to talk to each other. Now, gRPC is run by the Cloud Native Computing Foundation the CNCF. What Microsoft and.Net team has done, is we've written a new implementation of job essay that uses the latest and greatest features on.Net and we have contributed to the CNCF. gRPC is cross-platform. It's supported by every major programming language, be it C++, Java, Go, Node, Ruby, Python, C-Sharp, Rust, you name it, there's an implementation for it. These are all interoperable with each other. You could have an Xbox game version and C++ call a gRPC server, and the Cloud version on.Net. They can happily talk to each other. gRPC is contract first. That means the messages and methods and services, how to find in a contract known as a Protofile, and that is then used to drive code generation using tolling that the gRPC project provides. gRPC it's not new, it was originally open-source in 2015. But it's a union of two modern technologies, HTTP/2 at the protocol and transport layer and then Protobuf as it serialization technologies for producing very small fast binary messages and also the contract format. Part of Office is the language neutral syntax that you will find in protofiles. With that, let's demo build on our very first gRPC app. What I'm going to do is come to Visual Studio and we'll add a new project. We'll choose to create a gRPC app from a template. We include a basic Hello World gRPC template in the.Net ACK. This will create add posted in ASP.Net Core with an example so it's setup, ready for us to use. We'll create this, and the first thing I'll do is I'll just update the LogLevel, so we get a bit more logging while I'm demoing stuff to you. Let's take a look at what we can find in solution. We've got this greet.proto file this is the contract I mentioned to you earlier, this is where messages are defined, services are defined. You can think of the contract is an interface, and then there's an implementation for that interface. The implementation is found in GreeterService. This will use all the types defined to make greet.proto. This is where you place your business logic. This is where you place the logic to handle an incoming message. You can respond to it, you can validate it, you can use it to cool off to a database, set files to disk, and then eventually return a response. Then finally we've got program.cs, this is a standard startup location where everything's wide up. Let's start off by taking a look at our GreeterService file. This is a standard C-Sharp class. We've got to construct a head, we doing a bit of DI to initiate a logger, and we're not going to use that today. Then we've got this SayHello method. You can think of a service as a controller and NBC and then a method, gRPC method was I can action. This particular method takes a request and returns HelloReply, so on that requests, we have a nine property. We're concatenating that with hello, we sending that back to a message and we're returning it to the client. It's HelloWorld. We give it a name, it'll say hello to that name. But looking at this type of this file, we have some types so that never defined anywhere on our solution. We've got GreeterBase, HelloReply, HelloRequest. Where are these types coming from? The answer to that is code generation. If we go into the definition of this GreeterBase file, we can see we've got an abstract base class being generated for us. It's got this SayHello method, which is virtual, so we can override it. Then we've got a whole bunch of code to wire up route some serialization. It all looks ugly, but the beauty of code generation it's writing this code so you don't have to. We can confirm that it's still coming from code generation by looking at the header. We can save this as auto-generated. It's coming from the greet.proto file and has been generated by the Google Protobuf compiler. Where is this being driven from? The answer to that is this greet.proto file. This is where we're defining the contract for the APIs that our apps going to provide. In this case, we're saying we're going to provide a service called Greeter. On that service we've got to SayHello method, which takes request or returns reply. Then we've got our name and message properties and these are typed to be strings. But how does Visual Studio and the compilation know to do the code generation? Let's wide up in our csproj file. I've got this Protobuf element that references greet.proto, and then with specifying, we want server code generation. We want a service base type that we can then implement and I create a Service. An alternative value here could be client. In case you want a strongly typed client to call the gRPC service. Then we've also got this package reference. This is bringing in the gRPC server implementation along with the serialized and the tooling. If we run the set and then browse to it, we'll see what happens. Let's just open up our console app. This is standard kestrel login to let everything know it's running, and is launched on this port 7160. If we browse to this, we get this message saying communication with gRPC endpoints must be made through a gRPC client. Unlike Rust where you can just navigate to a URL into a path and some wrap parameters, maybe some query string values and get back some JSON. With gRPC, both the client and server need know about that greet.proto file, because it's contract first and our browser doesn't know anything about it. Now there are a couple of ways we could taste our server that we've just created. We could create a.Net client using that greet.proto file. But what I'm going to show you today is using a testing tool called Postman to invoke our server. Postman is probably or pretty familiar to a lot of you, as always had great support for invoking RESTful HTTP APIs and has all kinds of advanced features. But recently it's added support for gRPC requests. In Postman we can say as new gRPC request, we can then specify a URL that we want. This is what we just entered up here on our browser. We're using HTTPS, so click the lock. Then if we chose select method, we don't get the methods you get. We don't have SayHello on this drop-down and that's because Postman store doesn't know about that pesky contract file. We need to let it know about greet.proto. Now we could choose to import the greet.proto file. But what I'm going to do is I'm going to set up something called gRPC server reflection. Server reflection is open API for RESTful APIs. Open API is a JSON file. It's located on your server and it has definitions about all the services that your server provides. >> gRPC Server Reflection does the exact same thing except other gRPC servers providing information about other gRPC services. We want to set that up on our server. There is excellent support for a built-into gRPC in.NET, and I will show it off to you right now. First thing we're going to do is we're going to add a new package. This is the "Server.Reflection" package. Then in our "Program.cs" file, which we haven't looked at yet, we're going to add a service. We're going to register some services with DI. Just like we're registering gRPC, now we're registering some additional services with gRPC reflection. Finally, we're going to register a map gRPC service in our HTTP pipeline. Previously, GreeterService was registered, so we were able to call our implementation here. We also want to register our reflection service. That's what we need to do. If we now run our app again, and we go back to Postman, we can click "Try Again", and when we click that, Postman client goes off to the server and downloads the available information about potential services. We've got one service here, and then one method. We can now start using those to invoke our gRPC service from our client. We can verify that by taking a look at the logs that get written by our Kestrel app. We can say a bunch of HTTP requests have gone off to this "ServerReflection/Servers" and it's downloaded Reflection Info, and then Postman has used that information and the client to make a call available. Postman knows about the messages that we send and receive, so we can click "Generate Example Message" and then enter message we want to send. Lets say,.NET Conf 2022. Although I'm entering Jason here, this is just a visual representation, and Postman will convert it to Protobuf when it sends it off to the server. We just click "Invoke", and we can see our name specified here, went off to the server and was concatenated with hello, and our server was invoked. Again, we can verify that by taking a look at our server logs, we can see that our say hello method was invoked, and it called off to this "SayHello" server, so we got a result back. The great thing about gRPC and Server Reflection is, once you have it set up, it's very productive to work with it. If we want to add a new gRPC method, lets call it gRPC NewMethod. Click "Save" there. Code generation will automatically run, so we just need to override our new method, and we'll just "Copy and Paste" the previous implementation, and we'll just modify that slightly, "Say hello new method. Cool name" equals this. We "Run" our app. We go back to Postman, and we choose "Refresh". Our new method is immediately available. We can choose it and we can invoke it. That's how fast and iterative and productive gRPC can be by combining features like contract first, code generation, and tooling with gRPC Server Reflection. A quick overview of what we just did. We created a server. We set up server reflection, only took a couple of seconds. Then, we configured our testing tool to use that reflection. Usually this is just as simple as entering that address. The endpoint for server reflection is known, so tooling will just go off and kick servers available, and if it is, it will just automatically use it. Now, I demoed using Postman. Now, Postman has a lot of features, some of them are commercial, so keep that in mind if you want to use it. An alternative free open source tool is something called gRPC Web UI. If you want to use the command line, gRPCurl lets you invoke gRPC services from the command line and get responses back. Let's talk about what's new in gRPC for.NET 7. Every year we try to make gRPC faster, and we've made some great improvements in.NET 7. Now, gRPC runs on HTTP/2, so high performance and Kestrel's HTTP/2 stack is critical. A long known issue to the ASP.NET Core team is a bottleneck when writing a HTTP/2 result or response on a busy connection. Now the way HTTP/2 works is there are multiple requests running in parallel simultaneously on one TCP connection, and this is called multiplexing. However, only one thread can write to a connection at a time. That means we need to limit access to one thread, which was previously done with a simple C# lock. Now, locks are a great choice for thread safety a lot of the time, but in this situation, the lock had a lot of contention, there were dozens of threads fighting over it, and this was hurting performance. The way I like to imagine it is perhaps there's a small door, and there are dozens of people who are trying to get through it simultaneously, and they're all pushing and shoving each other out of the way, knocking each other down. That's a very inefficient and wasteful process. What we did in.NET 7 is we switched that lock to unset the IQ. Instead of fighting over a lock, threads would now line up in an orderly fashion, place some work on the queue, potentially go off and do other work while they're waiting, and then get notified that the write is complete and they can resume working with the request. This CPU re-architecture saved CPU cycles from fighting over that lock and better utilize machine resources. Now in a server streaming benchmark, we saw an 800 percent increase in request per second and after this change. Now this particular benchmark really stresses that lock is probably a worst case scenario, but even in more typical gRPC and HTTP/2 usage, we still notice a nice improvements after this change in.NET 7. Another improvement is HTTP/2 upload speeds, they're now much faster when uploading large messages and there is latency. HTTP/2 back-pressure was limiting upload speeds when there's latency. The reason for that, is the client would send a burst to database server, the server would say, hey, slow down, I can only handle so much data. The server will then process that data and then send a notification to the client that they can resume sending. Unfortunately because of latency, that means there is a pause when sending or receiving data. You can imagine your data being sent in bursts and the start-stop fashion. What we did in.NET 7 is we increased the buffer sizes to find a bit of balance between memory usage and throughput. Previously, uploading 100 megabyte file in.NET 6 would take about 27 seconds. In.NET 7 there is a six-fold improvement, now it's just a bit over four seconds. Finally, I'd like to talk about a.NET gRPC perfomance results benchmark from a community run benchmark. Thanks to the great improvements in.NET 7 from low-level API improvements and the BCL improvements, to JIT improvements, to profile guided optimization, all the way up to major re-architectures in our HTTP/2 layer,.NET performance now meets and even exceeds really fast frameworks like Go, C++, and Rust when it comes to gRPC performance. I think this is the real testament to the performance you can get out of.NET and also the quality of.NET's gRPC implementation. >> gRPC JSON transcoding is a major new productivity feature in.NET 7. It's an extension for gRPC that allows a service to act as both a gRPC API and as a RESTful API at the same time. JSON transcoding is useful for anyone who wants to provide both types of APIs to their clients without having to build them twice. You don't want all that duplication of building things once with REST, once we've gRPC and then having to maintain them forever, wouldn't it be great if you could just do it once and it worked for both. That is what gRPC JSON transcoding allows. Let me demo this amazing feature. We'll take our previous app and we'll extend it to include gRPC JSON transcoding. Again, we're going to add a new package to our csproj file. We're going to add the gRPC JSON transcoding package. Then in our program.cs file we're going to add a new service. Then we're going to add a couple of new proto-files to our solution. The reason why I'm adding these new proto-files and these are located and this are annotation.proto and http.proto. The reason we're adding these new profiles, as we want to add some annotations to say hello method. To specify how it maps to a RESTful API. Like we need to specify a route to be able to call this. After including these files, we then want to import one of them. We're going to call import Google APIs, annotations.proto. Then finally after that, we'll just comment out the previous method. We're going to add the annotation to it. The annotation as this particular bit of code down here, you can think of an annotation like an attribute, and.NET as met data we're adding to the call. In this case, the metadata were adding is we're saying, if you want to invoke this call with HTTP, this is the route you use to call it. It is a get route as V1 greeter, then this route perimeter of name. This name route parameter, it maps to the request property. Name down on hello requests. Whatever value we enter here, will get mapped down to here and it will be used when we invoke gRPC service by REST. Theoretically, if I've done everything just right, we'll compile our app. That succeeded. Lets launch it again. We'll come back to our browser. Previously, we got this warning saying we need to use a gRPC Client. Let's see if we can now use REST. We'll type in V1 greeter and then.NET conf 2022. Success, we can say our git request as now returning JSON from our protobuf gRPC endpoint. We can verify that by taking a look at the logs. Our requests came in. It was a get request to that URL we just specified at, got mapped to that gRPC endpoint. Then it returned a response, in this case the response was JSON rather than protobuf. That's pretty cool. This is just a very simple example of an annotation. You can also support post, you can support route parameters, you can support binding query parameters, incoming JSON bodies, all kinds of verbs. Get, PUT, post, delete, you name it, you can do it. Once you have JSON transcoding setup, it's very easy to add new methods. We can just add greeter new method and we're already set up and ready to go. REST is great. The thing which takes RESTful APIs to the next level is open API. What I'm going to show now is heading open API to our transcoded methods. Again, coming back to Csproj will add a new NuGet package. This one has gRPC.Swagger. We'll add some new services to our startup file, our program cs file. We'll add some swagger middleware, some swashbuckle middleware. This middleware will be familiar to anyone using swashbuckle. We're going to register UseSwagger and then UseSwaggerUI. Now if I launch this and come back to it with the browser, I can now navigate to swagger and I get the Swagger UI experience. I can see my two endpoints are showing up. I can come in here and I can invoke it just like you usually would. Flow.net and click "Execute" and we get back our message. Also if we take a look at swagger.JSON. As just standard swagger except instead of talking to a restful endpoint Russian with minimal API or MBC, in this case we've got a RESTful API version with gRPC. That's gRPC dress and transcoding. It's a very cool feature, but also very powerful, simple, easy to use and a great productivity bone if you want to serve both gRPC and REST at the same time. Let's do a quick overview of how it works. Imagine we've got a gRPC client that's talking protobuf. We use a Google.protobuf, deserialize to our hello request. Then we invoke that method metronome. We've got a RESTful API. Client that's got a custom route, which has got a route parameter. We bind that hello request, we invoke the same method, and we're good to go. Even though I just showed off invoking it with wrist, there's no reason you can't still keep using protobuf to use it at the same time. It's not one or the other, it's both at the same time. All right, finally, I like to talk about gRPC and Azure. I'm happy to say gRPC is now fully supported on Azure App Service. This request was ASP.Net because most commented on and voted on issue. It's great to be able to get that data market is closed. At the actual work to do this was a joint project between the Azure Service tame and adult knit team. What we did together was we replaced one pops of the Azure App Service infrastructure, this thing called a app service front-end role. We replaced it with a Yap, which is a proxy toolkit that runs on top of ASP.NET Core and in this case we're using Kestrel, it means that we can fully support gRPC because Kestrel has great support for HB2. There was an 80 percent throughput improvement, which is great to potentially, we can decommission the number of proxies we have create greener data centers by using less resources and energy. Also, because Kestrel has great support for HB3, provides a gateway for future features get added to Azure App Service. That's all I have time to talk to you about today. There's great documentation available for gRPC on our Docs website. Everything I've talked about, including testing with gRPC, civil reflection and JSON transcoding as documented here. There are also many examples available on the gRPC.net repository, including gRPC reflection and transcoding. Thank you everyone for joining us today. I hope you are all excited about gRPC on.NET, and I can't wait to see what kind of apps you make. Back to the studio.
Info
Channel: dotnet
Views: 24,937
Rating: undefined out of 5
Keywords: .NET, ASP.NET, Open Source, Microservices, Azure, Web, Modernization, Practices, group-modernization
Id: et_2NBk4N4Y
Channel Id: undefined
Length: 25min 17sec (1517 seconds)
Published: Sat Nov 12 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.