gRPC One-Pager
- Introduction
- Key steps
- gRPC methods
- Protobuf messages
- Versioning gRPC services
- Testing services
- gRPC clients and channels
- gRPC client factory integration
- gRPC client deadlines and cancellations
- gRPC client transient fault handling
- gRPC client-side load balancing
- .Net standard support
- Authentication and Authorization
- Interceptors
- Logging and Diagnostics
- Security considerations in gRPC for aspnet core
- Performance best practices
- Inter-process communication
- Code-first gRPC services and clients
- Health Checks
- dotnet-grpc
- Grpc vs WCF
- gRPC vs http apis
- Samples Repository
Introduction
-
Language agnostic, high-performance RPC framework.
-
Contract-first API development, using Protocol Buffers.
-
Supports client, server, and bi-directional streaming calls.
-
Reduced network usage using Protobuf binary serialization.
Key steps
-
The 5 key steps to using gRPC.
-
app.MapGrpcService<GreeterService>();
- Add the service to the pipeline.
gRPC methods
-
The gRPC method types are
-
Unary
-
Server Streaming
-
Client Streaming
-
Bi-directional Streaming
-
-
gRPC methods always have one message argument for the incoming request data.
-
Multiple values can still be sent to a gRPC service by making them fields on the request message.
-
-
A unary call is complete when the response is returned.
-
-
-
Multiple messages can be streamed back to the caller.
-
A server streaming call is complete when the method returns.
-
Some streaming methods could run forever.
-
A client can cancel the call when it is no longer needed.
-
IServerStreamWriter<T>
is sent as the response.
-
-
-
A client streaming method starts without the method receiving a message.
-
A client streaming call is complete when a response message is returned.
-
IAsyncStreamReader<T>
is read from the request.
-
-
Bi-directional Streaming Method.
-
A bi-directional streaming method starts without the method receiving a message.
-
IAsyncStreamReader<T>
is used to read messages from the client. -
IAsyncStreamWriter<T>
is used to write messages to the client. -
A bi-directional streaming call is complete when the method returns.
-
It is possible to read a request and send a response simultaneously.
-
-
You can send request headers. Access gRPC request headers.
-
Multi-threading
-
Multiple threads cannot read new messages simultaneously and cannot write new messages simultaneously.
-
General advice - try to avoid multi-threading if not necessary.
-
Protobuf messages
-
It is recommended to use
underscore_seperated_names
for field names. -
.Net tooling automatically converts them to the .Net naming standard.
-
Each field is assigned a number which determines the order of serialization.
-
Date and times are not supported natively. You need to use Protobuf’s
Well known types
extension. Using DateTime, TimeSpan. -
Nullable types are not supported natively. You need to use Protobuf’s
Well known types
extension. Using Nullable Types. -
Bytes are supported. C# uses
ByteString
as the property type. Using Bytes. -
Decimals are not natively supported, just
double
andfloat
. There is also nowell known type
for decimal types. There is a custom implementation that you can copy. Creating a decimal type for protobuf. -
Lists are supported. Use the
repeated
keyword on the field. In C#, it is converted toRepeatedField<T>
.RepeatedField<T>
implementsIList<T>
. Using Lists -
Dictionaries are represented using maps.
map<key-type,value-type>-type
. Maps to IDictionary. Using Dictionaries -
The Any type lets you use messages as embedded types without having their
.proto
definitions. It is useful when you would like to use a field withany
message. Using the Any type. -
OneOf type is useful when you would like to use conditional messages. For example, when the response could be a success result or an error result. Using the OneOf type.
-
The Value type represents a dynamically typed value. It can be either a
null
, a number, a string, a boolean, a dictionary of values(Struct
), or a list of values(ValueList
). Value is a Protobuf Well-Known Type. Using the Value type
Versioning gRPC services
-
Additions to gRPC services and methods are non-breaking.
-
Changing or deleting gRPC services are breaking changes.
-
When gRPC services have breaking changes, clients using that service have to be updated and redeployed.
-
A way to maintain backwards compatibility while making breaking changes is to publish multiple versions of a service.
-
An optional
package
modifier functions much like a .Net namespace. -
The package can be used to specify a version number for your service and its messages.
Testing services
-
Unit test gRPC services directly from a unit testing library.
-
Integration testing can be done by hosting the grpc app inside a TestServer
-
You do some adhoc testing using Postman or gRPCurl.
-
Sample code that shows how to test a simple greeter service using unit tests and integration tests.
gRPC clients and channels
-
gRPC clients are concrete client types generated from .proto files.
-
A service called
Greeter
generates aGreeterClient
type with methods to call the service. -
A grpc client is created from a channel. Configure gRPC client.
-
A channel represents a long-lived connection to a gRPC service.
-
You can configure a channel with options. For example, which Httpclient to use, the maximum size of messages and logging.
-
A grpc client must use the same connection-level security as the called service. So, if the service uses
http
the client must usehttp
, if the service uses 'https' the client must usehttps
. Configure TLS -
Performance considerations
-
Reuse channels as they are an expensive operation.
-
gRPC clients are lightweight and don’t need to be cached or reused.
-
One channel can be used for multiple gRPC clients.
-
Channels and clients can safely be used in multiple threads.
-
Clients can make multiple simultaneous calls.
-
-
Each unary service method on the service results in 2 methods in the client. An asynchronous call and a blocking call. Unary call.
-
A server streaming method call is complete when
ResponseStream.MoveNext()
returnsfalse
. Server Streaming call -
A client streaming method call starts without the client sending a message. The client can choose to send messages with
RequestStream.WriteAsync
.CompleteAsync
notifies the service that sending messages is complete. Client Streaming call. -
A bi-directional streaming call starts without the client sending a message.
WriteAsync
to write messages.CompleteAsync
to complete sending messages.ResponseStream.MoveNext()
orResponseStream.ReadAllAsync()
to read the messages from the server. The call is complete when there are no more messages in theResponseStream
. Bi-directional streaming call. -
Headers are accessible using
ResponseHeadersAsync
. Access gRPC headers. -
Grpc trailers provide similar functionality as Headers but are returned at the end of the call.
GetTrailers()
returns a key-value pair of the trailers. Trailers are returned only after the response is complete. Access gRPC trailers.
gRPC client factory integration
-
Offers a centralized way to create gRPC clients with HttpClientFactory.
-
Manages the lifetime of the underlying
HttpClientMessageHandler
. -
Automatic propagation of deadline and cancellation in an aspnetcore gRPC service.
-
To register a gRPC client, the generic
AddGrpcClient
extension can be used. Register a gRPC client. -
You can configure the HttpMessageHandler used by the gRPC client. Configure HttpHandler.
-
gRPC interceptors can be added to clients. By default, one interceptor is created and is shared among clients. However, you can create one interceptor per client by using the
InterceptorScope.Client
option. Configure Interceptors. -
Additional configuration can be applied to a channel using the
Configure Channel
method. Configure Channel. -
EnableCallContextPropagation()
automatically propagates the deadline and cancellation token to child calls. Configure propagation -
You can have seperate clients pointing to the same service with different configurations. Named Clients
gRPC client deadlines and cancellations
-
A deadline allows a gRPC client to specify how long it will wait for a call to complete.
-
When a call is made the deadline can be configured using
CallOptions.Deadline
. -
There is no default deadline value. If unspecified, it can be infinite.
-
Deadlines are tracked by both the client and service. It is possible for a gRPC call to complete on one machine, but by the time the response is returned the client deadline has exceeded.
-
The client immediately aborts and throws a
DeadlineExceeded
error. -
The server aborts the HttpRequest and raises a ServerCallContext.CancellationToken. Passing a cancellation token allows the cancelled call to complete quickly and free up resources.
-
If a deadline exceeds, then gRPC skips any remaining retries.
-
EnableCallContextPropagation
automatically propagates deadlines and cancellation tokens to child calls. -
Cancellation allows a gRPC client to cancel long running calls that are no longer needed.
-
A call can be cancelled by passing a cancellation token with
CallOptions.CancellationToken
or callingDispose
on the call. -
A gRPC service that can be cancelled should
-
Pass
ServerCallContext.CancellationToken
to async methods. -
Propagate the cancellation token to child calls.
-
gRPC client transient fault handling
-
gRPC retries is a feature that allows gRPC clients to automatically retry failed calls.
-
Duplicating retry logic throughout an app is verbose and error prone.
-
A retry policy is configured once when a gRPC channel is created. Configure a gRPC retry policy.
-
Retry policies can be configured per-method and methods are matched using the
Names
property.MethodName.Default
applies to all gRPC methods. -
Hedging is an alternative retry strategy. Hedging enables aggressively sending multiple copies of a single gRPC call without waiting for a response. Configure a Hedging policy
gRPC client-side load balancing
-
Client-side load balancing allows gRPC clients to distribute load optimally across available servers.
-
Client-side load balancing is configured in the channel.
-
There are two components that are involved:
-
The resolver, which resolves the addresses of the channel.
-
The load balancer, which creates connections and picks the address that a gRPC call will use.
-
-
A channel must be reused when making gRPC calls for load balancing to work correctly.
-
The resolver is configured using the address a channel is created with. Configure resolver.
-
A
DnsResolverFactory
creates a resolver designed to get addresses from an external source. -
DNS resolution is commonly used to load balance over pod instances that have a kubernetes headless service. See DnsResolverFactory.
-
The latency of resolving addresses is eliminated from gRPC calls by caching the addresses.
-
By default, a DNS resolver is refreshed if a connection is interrupted. It can also refresh itself on periodic intervals. See DNS address caching.
-
StaticResolverFactory
is a resolver that:-
does not call an external source. The client app configures the addresses.
-
Is designed for situations where an app already knows the addresses it calls.
-
-
A load balancer is specified in the service config.
-
There are two types of Load Balancers:-
PickFirstLoadBalancerFactory
andRoundRobinLoadBalancerFactory
-
Credentials must be configured on channel options when using load balancing. Configure Channel credentials.
-
Try and avoid writing your own custom load balancer and resolver. Write your own custom resolvers and load balancers.
.Net standard support
-
.Net implementations that do not support Http/2, such as UWP, Xamarin, and Unity, can use gRPC-Web as an alternative. HttpHandler configuration.
-
.Net framework has limited support for gRPC over Http/2. To enable support, configure the channel to use WinHttpHandler. .Net Framework
Authentication and Authorization
-
Always call
UseAuthentication
andUseAuthorization
afterUseRouting
and beforeUseEndpoints
. -
Once authentication has been setup, the user can be accessed in a gRPC service methods via the ServerCallContext.
-
Bearer Token Authentication
-
Bearer tokens can be sent using the
Metadata
collection. -
You can also send tokens by configuring the
ChannelCredentials
. -
ChannelCredentials
can includeCallCredentials
, which provide a way to automatically setMetadata
. -
CallCredentials
is run each time a gRPC call is made, which avoids the need to write code in multiple places to pass the token yourself. -
CallCredentials are only applied if the channel is secured with TLS.
-
An app can configure a channel to ignore this behavior and always use
CallCredentials
by settingUnsafeUseInsecureChannelCallCredentials
on a channel.
-
-
With Client factory
-
gRPC client factory can create clients that send a bearer token using
AddCallCredentials
. -
Available in
Grpc.Net.ClientFactory
. -
Dependency injection (DI) can be combined with
AddCallCredentials
. An overload passesIServiceProvider
to the delegate.
-
-
With Certificates
-
A client could provide a certificate for authentication
-
Certificate authentication happens at the TLS level, long before it ever gets to ASP.NET Core.
-
The client certificate is added to
HttpClientHandler
.
-
-
To require authentication, apply the
[Authorize]
attribute to the service. -
You can use the constructor arguments and properties of the [Authorize] attribute to restrict access to only users matching specific authorization policies.
-
Individual service methods can have the
[Authorize]
attribute applied as well.
Interceptors
-
Interceptors offer a way to enrich the request processing pipeline.
-
Interceptors are configured for a channel or a service.
-
They are executed automatically for each gRPC call.
-
Excellent solution for logging, monitoring, authentication and authorization.
-
Interceptors can be implemented for both gRPC servers and clients by creating a class that inherits from the
Interceptor
type. -
Client Interceptors
-
gRPC client interceptors intercept outgoing RPC invocations.
-
They provide access to the sent request, the incoming response, and the context for a client-side call.
-
An interceptor can await the response in unary and client streaming calls by updating the
AsyncUnaryCall<TResponse>.ResponseAsync
orAsyncClientStreamingCall<TRequest, TResponse>.ResponseAsync
value. -
gRPC client interceptors are configured on a channel.
-
The Intercept extension method can be chained to configure multiple interceptors for a channel.
-
Alternatively, there is an Intercept overload that accepts multiple interceptors.
-
Interceptors are invoked in reverse order of the chained Intercept extension methods.
-
-
Server Interceptors
-
gRPC server interceptors intercept incoming rpc requests.
-
They provide access to incoming requests, the outgoing response, and the context for a server-side call.
-
You can configure gRPC on startup using the
AddGrpc
method. -
An interceptor can also be configured for a specific service.
-
Interceptors are run in the order that they are added to the
InterceptorCollection
. -
Globally-configured interceptors are run before single service interceptors.
-
gRPC server interceptors have a per-request lifetime. Overriding this behaviour is possible.
-
-
Interceptors vs Middleware
-
Interceptors provide access to the deserialize message sent to a call.
-
The message returned to the call before it’s serialized.
-
Handles exceptions thrown for gRPC services.
-
Middleware runs for all HTTP requests.
-
Runs before gRPC interceptors.
-
Can only access bytes from the request and response streams.
-
Logging and Diagnostics
-
gRPC services and gRPC client write logs using .Net Core logging.
-
gRPC logs minimal information, but logging can be configured.
-
gRPC adds logs under the Grpc Category.
-
Logging can be configured in
Program.cs
withConfigureLogging
. -
When not using JSON-based configuration, use
Logging:LogLevel:Grpc=Debug
. -
When using env variables, two
_
characters are used instead of the:
. -
For client-side logging, set the
GrpcChannelOptions.LoggerFactory
property when the client’s channel is created. -
You can also enable client logging using the gRPC client factory logging.
-
The client factory will automatically be resolved by DI.
-
If the client is not using DI, then create a new
ILoggerFactory
instance usingLogger.Create
. -
The gRPC client adds logging scope to logs made during a gRPC call.
-
gRPC services and the gRPC client provide information about gRPC calls using
DiagnosticSource
andActivity
. -
.Net gRPC uses an activity to represent a gRPC call.
-
Tracing events are writted at the start and stop of a gRPC call.
-
Tracing does not capture information about when messages are sent over the lifetime of gRPC streaming calls.
-
Metrics is a representation of data measures over intervals of time, for example, requests per second.
-
Metrics data allows observation of the state of an app at a high level.
-
.Net gRPC metrics are emitted using
EventCounter
. -
dotnet counters is a performance monitoring tool for ad-hoc health monitoring and first-level performance investigation.
Security considerations in gRPC for aspnet core
-
gRPC messages are sent and received using HTTP/2.
-
TLS should be used to secure messages in production gRPC apps.
-
gRPC services should only listen and respond over secured ports.
-
A TLS termination proxy can be combined with TLS.
-
By default, gRPC does not send the details of an exception thrown by a gRPC service to a client.
-
This can be overridden in development with
EnableDetailedErrors
inAddGrpc
. -
Incoming messages to gRPC clients and services are loaded into memory.
-
Message size limits are a mechanism to help prevent gRPC from consuming excessive resources.
-
By default, gRPC limits incoming messages to 4MB. There is no limit to outgoing messages.
-
On the server, gRPC limits can be configured with AddGrpc.
-
Limits can also be configured for individual services using
AddServiceOptions<TService>
. -
It is recommended that gRPC services secured by client certificates use the
Microsoft.AspNetCore.Authentication.Certificate
package. -
AspNetCore will perform addition validation on a client certificate, including
-
Valid Extended Key Use
-
Is within its validity period.
-
Check certificate revocation.
-
Performance best practices
-
-
Http/2 has a limit on the number of concurrent streams (active Http requests) on one connection at a time.
-
Most servers have a limit of 100. It is not recommended to increase it.
-
A gRPC channel creates one connection and concurrent calls are multiplexed on that connection.
-
If the limit is reached, the calls are queued.
-
In .Net5, you can set the
SocketsHttpHandler.EnableMultipleHttp2Connections
property to create additional connections once the limit is reached.
-
-
.Net GC has 2 modes - workstation GC and server GC. By default, aspnetcore gc uses server GC. Enable server GC if a client app sends a high number of calls. It may improve performance. Using server GC.
-
Use client-side load balancing and server side load balancing. Using Load balancers.
-
Http/2 flow control prevents apps from being overwhelmed with data. See Flow Control.
-
Flow control can have a negative impact on performance when receiving large messages.
-
Flow control performance issues can be fixed by increasing buffer window size.
-
-
Streaming messages back and forth is faster than sending messages with multiple unary gRPC calls. As a general rule, follow this only if required. For more details.
-
Avoid large binary payloads in gRPC messages. Binary payloads.
Inter-process communication
-
Apps on the same machine can be designed to communicate with each other.
-
IPC offers performance benefits when the client and server are on the same machine.
Code-first gRPC services and clients
-
Code-first gRPC uses .NET types to define services and message contracts.
-
It is a good-choice when an entire system is .NET.
-
.Net service and contracts can be shared between server and clients.
-
Avoids .proto files and code generation.
-
protobuf-net.Grpc is a community project that makes this possible.
Health Checks
-
Add a package
Grpc.AspNetCore.HealthChecks
. -
AddGrpcHealthChecks
to register services that enable health checks. -
MapGrpcHealthChecksService
to add a health checks service endpoint. -
Add health checks by implementing
IHealthCheck
or using theAddCheck
method.
dotnet-grpc
-
It is a global tool that can be used to manage protobuf references within a .Net gRPC project.
-
dotnet tool install -g dotnet-grpc
.
Grpc vs WCF
-
Performance
-
Interoperability
-
Streaming
-
Deadlines, timeouts and cancellation
-
Security
gRPC vs http apis
-
Required contract (.proto)
-
http/2 protocol
-
Small binary payload
-
Strict specification
-
Streaming
-
No Browser support (requires grpc-web)
-
Client Code generation