Below you will find pages that utilize the taxonomy term “GRPC”
Posts
Jaeger - Tracing with gRPC service
要使用 Jaeger 追蹤 gRPC service 程式,可先加入 Jaeger 與 OpenTracing.Contrib.Grpc 套件。
... <PackageReference Include="Jaeger" Version="0.3.6" /> <PackageReference Include="OpenTracing.Contrib.Grpc" Version="0.2.0" /> </ItemGroup> ... 修改 Startup.ConfigureServices,加入 Jaeger tracer、註冊 GlobalTracer、設定 gRPC 攔截器。
... services.AddGrpc(options => { var serviceName = AppDomain.CurrentDomain.FriendlyName; var tracer = new Tracer.Builder(serviceName) .WithSampler(new ConstSampler(true)) .Build(); GlobalTracer.Register(tracer); services.AddSingleton<ITracer>(tracer); var interceptors = options.Interceptors; interceptors.Add<ServerTracingInterceptor>(tracer); ... }); ... 實際運行程式。
選取 Service 與 Operator 下去查詢。
可看到找到的 Trace,上半部可看到時間與耗時的分佈,下半部就是簡易的列表,可看出 Trace 名稱、識別碼、是什麼時間點觸發的、耗時多久、有多少 Span。
點選感興趣的 Trace,會進入 Trace 細部資訊頁面,會將 Trace 及其組成的 Span 以圖形的方式呈現,便於找到相對耗時的操作。
read morePosts
gRPC - Custom error over RpcException
在做系統時,免不了可能會要定義自己的狀態碼供判斷系統的問題。在 gRPC 下,我們可能會為 Message 增加 StatusCode 這樣的欄位做傳遞與判讀。
這樣的做法在一般的呼叫方式並無問題,但是在用 Streaming 傳達多個小 Message 時,使用上就會有點奇怪。這邊筆者試著透過 gRPC 本身的例外機制嘗試解決這樣的問題。
先造一個自定義的例外,支援帶入 StatusCode,這邊筆者先簡單的用字串型態來做 StatusCode 的定義,實際運用時改用列舉會比較好。
Server 端透過自定義的例外拋出例外。
using System.Threading.Tasks; using Greet; using Grpc.Core; namespace GrpcService_CSharp1 { public class GreeterService : Greeter.GreeterBase { public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context) { throw new MyException("ERROR2020"); } } } Server 端掛載攔截器處理例外,將例外轉為 RpcException 拋出,gRPC 支援的狀態碼較少所以筆者拿 StatusCode.Internal 狀態碼來用,Detail 這邊就帶我們自定義的狀態碼,若有額外資訊要帶入可放在 MetaData。
using System; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Interceptors; namespace GrpcService_CSharp1 { public class ExceptionInterceptor: Interceptor { public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation) { try { return await base.
read morePosts
gRPC - Unable to start ASP.NET Core gRPC app on macOS
使用 ASP.NET Core 3.0 範本建立 gPRC 程式, 在 MAC 的環境下直接運行起來會發生 HTTP/2 over TLS is not supported on macOS due to mis sing ALPN support 錯誤。
System.IO.IOException: Failed to bind to address https://localhost:5001. ---> System.AggregateException: One or more errors occurred. (HTTP/2 over TLS is not supported on macOS due to missing ALPN support.) (HTTP/2 over TLS is not supported on macOS due to missing ALPN support.) ---> System.NotSupportedException: HTTP/2 over TLS is not supported on macOS due to missing ALPN support.
read morePosts
gRPC - Services logging
gRPC Service 內建的 log 可透過 appsettings.json 控制 log 層級。
預設為 Information 層級。
{ "Logging": { "LogLevel": { "Default": "Debug", "System": "Information", "Grpc": "Information", "Microsoft": "Information" } } } 所以 gRPC service 運行起來會看到 Info 或是 Warn 層級的 Log 輸出。
若是調整為 Debug 層級,可看到像是哪個 gRPC method 被調用,以及是哪個 Method type 這樣的細部資訊。
除了用 appsettings.json 設定,也可以在建立 HostBuilder 時設定。
... public class Program { ... public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureLogging(logging => { logging.AddFilter("Grpc", LogLevel.Debug); }) .
read morePosts
gRPC - Logging with interceptor in gRPC service
要紀錄每次 gRPC 的呼叫,可以使用 gRPC interceptor 來做。
建立一個 Interceptor 類別繼承自 gRPC 的 Interceptor,建立個建構子允許注入 Logger,接著覆寫掉會用到的方法,像是 UnaryServerHandler,然後在內部將要記錄的資訊透過 Logger 寫入 Log 即可。
像是下面這邊筆者實作了一個 Interceptor,希望能紀錄每次 gRPC 的調用。
using System.Linq; using System.Text.Json.Serialization; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Interceptors; using Microsoft.Extensions.Logging; using Newtonsoft.Json; namespace GrpcServiceInterceptor { public class LoggerInterceptor : Interceptor { private readonly ILogger<LoggerInterceptor> _logger; public LoggerInterceptor(ILogger<LoggerInterceptor> logger) { _logger = logger; } public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>( TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation) { var response = await base.
read morePosts
gRPC - Global exception handling with interceptor in gRPC service
要做 gRPC 的全域攔截,可以使用 gRPC interceptor 來做。
建立一個 Interceptor 類別繼承自 gRPC 的 Interceptor,覆寫掉會用到的方法,像是 UnaryServerHandler,然後在內部調用基底的方法並用 try/catch 去攔截錯誤做對應的處理即可。
像是下面這邊筆者實作了一個 Interceptor,希望能在錯誤發生時顯示錯誤,並回傳錯誤訊息。
using System; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Interceptors; using Microsoft.Extensions.Logging; namespace GrpcServiceInterceptor { public class ExceptionInterceptor : Interceptor { public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation) { try { return await base.UnaryServerHandler(request, context, continuation); } catch (Exception e) { Console.WriteLine(e.ToString()); var obj = (TResponse) Activator.CreateInstance(typeof(TResponse)); var prop = typeof(TResponse).
read morePosts
gRPC - Streaming
gRPC 的 Streaming 可用來做大量資料的傳輸,不論是 Client 傳到 Service,或是 Service 回給 Client。
使用上就是在 proto 檔用 stream 去定義要使用 Streaming 的地方,看是用在傳入還是回傳。
... service Greeter { ... rpc SayHellos (stream HelloRequest) returns (stream HelloReply) {} } ... 然後 Service 與 Client 透過 IServerStreamWriter 寫資料、透過 IAsyncStreamReader 讀取資即可。
以寫入來說,可透過迴圈搭配 WriteAsync() 將資料逐筆寫入,最後透過 CompleteAsync() 告知寫入完成。
foreach (var item in data) { await stream.WriteAsync(item); } await stream.CompleteAsync(); 或是引用 Grpc.Core.Utils,直接透過 WriteAllAsync() 將所有資料寫入。
... await stream.WriteAllAsync(data); ... 以讀取來說,可用迴圈搭配 MoveNext() 移至下筆可用的資料,再用 Current 取出資料做處理。
read morePosts
gRPC - Setup singleton service
ASP.NET Core 的 gRPC service 預設是沒有 Singleton 的,所以如果今天 gRPC client 發送多次訊息給 gRPC server。
gRPC server 會建多次 gRPC service 實體。
為避免這樣的情況,可在 Startup 的 ConfigureServices 內透過 services.AddSingleton 將 Service 的實體帶入。
... public class Startup { public void ConfigureServices(IServiceCollection services) { ... services.AddGrpc(); services.AddSingleton(service); ... } ... } gRPC server 就只會用指定的 gRPC service 實體去做事。
read morePosts
gRPC - Setup service options with ASP.NET Core
在 ASP.NET Core 支援設定的 gRPC service option 有:
Option Default Description SendMaxMessageSize null 最大訊息大小可以從伺服器傳送的位元組數。 嘗試傳送的訊息長度超過設定的最大訊息大小會導致例外狀況。 ReceiveMaxMessageSize 4 MB 最大訊息大小可以由伺服器接收的位元組數。 如果伺服器收到的訊息超過此限制,它會擲回例外狀況。 增加此值可讓伺服器接收較大的訊息,但可能會造成負面影響記憶體耗用量。 EnableDetailedErrors false 如果true詳細服務方法擲回例外狀況時,將會傳回給用戶端的例外狀況訊息。 預設為 false。 這個設定設為true可能會導致洩漏機密資訊。 可在 Startup 的 ConfigureServices 內透過 services.AddGrpc 針對所有 Service 下去設定。
... public class Startup { public void ConfigureServices(IServiceCollection services) { ... services.AddGrpc(options => { options.ReceiveMaxMessageSize = receiveMsgLimit; options.SendMaxMessageSize = sendMsgLimit; }); ... } ... } 也可以透過 services.AddGrpc().AddServiceOptions 針對特定 Service 下去設定。
... public class Startup { public void ConfigureServices(IServiceCollection services) { .
read morePosts
gRPC - Create service with ASP.NET Core
在 .NET Core 3.0 後,我們可透過 gRPC Service 範本建立方案或是專案,如果是用方案範本,除了 gRPC 的 Server 專案外,還會有 Client 的專案。
像是筆者這邊直接透過範本建立一個 gRPC 方案。
方案建立完會看到內含 Server 與 Client 兩個專案,需參考的套件以及要使用的 Proto 檔設定都已經設好了。
編譯檔案時會將 Proto 編譯成對應的程式碼,產生在 obj 下。
{% asset_img 5.png%}
另外是 .NET Core 3.0 的 gRPC Service 已經被整進 ASP.NET Core 去了,只要在 Startup.cs 中的 ConfigServices 將 gRPC 服務開啟。
... public void ConfigureServices(IServiceCollection services) { services.AddGrpc(); } ... 並設定 gRPC 服務對應的處理類別,gRPC Server 就好了。
... public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { .
read morePosts
'gRPC - Create C# gRPC client'
要建立 gRPC 的 Client,須先將 GRPC.Tools、GRPC.Core、Google.Protobuf 這三個 NuGet 套件加入參考。
... <ItemGroup> <PackageReference Include="Google.Protobuf" Version="3.7.0" /> <PackageReference Include="Grpc.Core" Version="1.20.0" /> <PackageReference Include="Grpc.Tools" Version="1.20.0" /> </ItemGroup> ... 然後設定從 Proto 檔產生需要的程式部分。
<ItemGroup> <Protobuf Include="../../proto/*.proto" GrpcServices="Client" /> <Content Include="@(Protobuf)" LinkBase="" /> </ItemGroup> 編譯後可在 obj 下看到產出的檔案。
接著開始實作 Client。
然後帶入 Server 位置建立 Channel 物件。
... var channel = new Channel($"{host}:{port}", ChannelCredentials.Insecure); ... 接著帶入 Channel 建立 Service 的 Client 物件。
... var client = new HelloService.HelloServiceClient(channel); ... 透過 Service 的 Client 物件調用對應的方法。
read morePosts
'gRPC - Create C# gRPC server'
要建立 gRPC 的 Server,須先將 GRPC.Tools、GRPC.Core、Google.Protobuf 這三個 NuGet 套件加入參考。
... <ItemGroup> <PackageReference Include="Google.Protobuf" Version="3.7.0" /> <PackageReference Include="Grpc.Core" Version="1.20.0" /> <PackageReference Include="Grpc.Tools" Version="1.20.0" /> </ItemGroup> ... 然後設定從 Proto 檔產生需要的程式部分。
<ItemGroup> <Protobuf Include="../../proto/*.proto" GrpcServices="Server" /> <Content Include="@(Protobuf)" LinkBase="" /> </ItemGroup> 編譯後可在 obj 下看到產出的檔案。
接著開始實作 Service。
繼承產出的 Service 基底類別。
... public class HelloServiceImpl:HelloService.HelloServiceBase ... 並覆寫該服務的方法即可。
... public override Task<HelloResponse> SayHello(HelloRequest request, ServerCallContext context) { ... } ... 程式寫起來會像下面這樣 (這邊筆者只是簡單的將調用時送進來的人名做些加工回傳而已):
using System.Threading.Tasks; using Grpc.Core; public class HelloServiceImpl:HelloService.
read morePosts
gRPC - Protocol Buffers/gRPC Integration Into .NET Build
Grpc.Tools 在 1.17 後我們可以將 proto 檔的編譯動作直接整到 dotnet build。使用上只要在專案檔中加上 設定即可。
像是筆者這邊準備了一個 GRPC.Message 專案。加入 Grpc/Grpc.Tools/Google.Protobuf NuGet 套件參考。
proto 檔放在上上層的 proto 目錄下。
. |___ proto | |___ message.proto | |___ service.proto |___ src |___ GRPC.Message 那在 GRPC.Message 的專案檔中可以像下面這樣加入 設定,會用 Include 指定 proto 檔、ProtoRoot 指定 proto 檔中 import 語法的參考位置、OutputDir 指定輸出位置、GrpcService 指定要編譯 gRPC 的 server 還是 client…等。
... <ItemGroup> <Protobuf Include="../../**/*.proto" OutputDir="%(RelativePath)" CompileOutputs="false" GrpcService="both" /> </ItemGroup> ... 像是如果只要產生 Server 需要使用的類別就可以像這樣設定。
... <ItemGroup> <Protobuf Include="../../proto/*.proto" GrpcServices="Server" /> </ItemGroup> .
read more