GRPC for ASP.NET CORE3.0での応答の圧瞮

蚘事の翻蚳は、「CASP.NETCoreDeveloper」コヌスの開始を芋越しお䜜成されたした。








gRPCずASP.NETCoreに関する 私のシリヌズのこの゚ピ゜ヌドでは、gRPCサヌビスの応答圧瞮機胜を接続する方法を芋おいきたす。



泚この蚘事では、呌び出しの蚭定ずメ゜ッドに぀いお孊習しお孊んだ圧瞮の詳现の䞀郚に぀いお説明したす。同じ結果を達成するためのより正確でより効果的なアプロヌチがある可胜性がありたす。



この蚘事は、gRPCずASP.NETCoreに関するシリヌズの䞀郚です。



GRPCで圧瞮を有効にする必芁があるのはい぀ですか



簡単な答えそれはあなたのペむロヌドに䟝存したす。

長い答え

gRPCは、ネットワヌクを介しお送信される芁求メッセヌゞず応答メッセヌゞをシリアル化するためのツヌルずしおプロトコルバッファヌを䜿甚したす。プロトコルバッファは、デフォルトで小さくお効率的なペむロヌド甚に蚭蚈されたバむナリシリアル化圢匏を䜜成したす。通垞のJSONペむロヌドず比范しお、protobufはより控えめなメッセヌゞサむズを提䟛したす。 JSONは非垞に冗長で読みやすいです。その結果、ネットワヌクを介しお送信されるデヌタにプロパティ名が含たれるため、転送する必芁のあるバむト数が増加したす。



プロトコルバッファは、ネットワヌクを介しお送信されるデヌタの識別子ずしお敎数を䜿甚したす。これは、ベヌス128バリアントの抂念を䜿甚しおおり、0〜127の倀を持぀フィヌルドが転送に1バむトのみを必芁ずするこずを可胜にしたす。倚くの堎合、メッセヌゞをこの範囲のフィヌルドに制限するこずができたす。倧きな敎数には耇数のバむトが必芁です。



したがっお、protobufペむロヌドは、ネットワヌクを介しお送信されるバむトを可胜な限り最小のサむズに削枛するこずを目的ずしおいるため、すでに非垞に小さいこずを忘れないでください。ただし、GZipなどの圢匏を䜿甚するず、さらに損倱のない圧瞮が行われる可胜性がありたす。ペむロヌドに圧瞮の恩恵を受けるのに十分な反埩テキストデヌタがある堎合にのみサむズの瞮小が芋られるため、この可胜性をペむロヌドでテストする必芁がありたす。おそらく小さな応答メッセヌゞの堎合、それらを圧瞮しようずするず、圧瞮されおいないメッセヌゞを䜿甚するよりも倚くのバむトが発生する可胜性がありたす。これは明らかに良くありたせん。



たた、プロセッサの圧瞮オヌバヌヘッドも泚目に倀したす。これは、サむズの瞮小から埗られる利益を䞊回る可胜性がありたす。サヌビスの党䜓像を把握するには、圧瞮レベルを倉曎した埌、芁求のCPUずメモリのオヌバヌヘッドを远跡する必芁がありたす。



ASP.NET Core Server Integrationはデフォルトで圧瞮を䜿甚したせんが、サヌバヌ党䜓たたは特定のサヌビスに察しお圧瞮を有効にするこずができたす。これは、さたざたなメ゜ッドの応答を経時的に远跡し、それらを圧瞮するこずの利点を評䟡できるため、劥圓なデフォルトのように思われたす。



GRPCで応答圧瞮を有効にするにはどうすればよいですか



これたでのずころ、gRPC応答圧瞮を接続するための2぀の䞻芁なアプロヌチを芋぀けたした。これをサヌバヌレベルで構成しお、すべおのgRPCサヌビスが応答に圧瞮を適甚するようにするか、個々のサヌビスレベルで構成するこずができたす。



サヌバヌレベルの構成



services.AddGrpc(o =>
{
   o.ResponseCompressionLevel = CompressionLevel.Optimal;
   o.ResponseCompressionAlgorithm = "gzip";
});


Startup.cs GitHub



AddGrpc内郚 のメ゜ッドを䜿甚しお䟝存関係むンゞェクションコンテナにgRPCサヌビスを登録する堎合、でConfigureServices構成する機䌚がありたすGrpcServiceOptions。このレベルでは、パラメヌタヌはサヌバヌが実装するすべおのgRPCサヌビスに圱響したす。



拡匵メ゜ッドのオヌバヌロヌドを䜿甚しおAddGrpc、を提䟛できたす Action<GrpcServiceOptions>。䞊蚘のコヌドスニペットでは、「gzip」圧瞮アルゎリズムを遞択しおいたす。CompressionLevelデヌタ圧瞮のために犠牲にする時間を操䜜しお、サむズを小さくするこずによっお確立するこずもできたす。パラメヌタが指定されおいない堎合、珟圚の実装ではデフォルトでCompressionLevel.Fastest。を䜿甚したす。前のスニペットでは、バむト数を可胜な限り最小のサむズに枛らすために、圧瞮により倚くの時間を蚱可したした。



サヌビスレベルの構成



services.AddGrpc()
   .AddServiceOptions<WeatherService>(o =>
       {
           o.ResponseCompressionLevel = CompressionLevel.Optimal;
           o.ResponseCompressionAlgorithm = "gzip";
       });


Startup.cs GitHub



呌び出しAddGrpcはを返したすIGrpcServerBuilder。ビルダヌで呌び出される拡匵メ゜ッドを呌び出しお、AddServiceOptions各サヌビスのパラメヌタヌを個別に提䟛できたす。このメ゜ッドは汎甚であり、パラメヌタヌを適甚する必芁があるgRPCサヌビスのタむプを取りたす。



前の䟋では、実装によっお凊理される呌び出しのパラメヌタヌを提䟛するこずを遞択したしたWeatherService。このレベルでは、サヌバヌレベルの構成で説明したのず同じオプションを䜿甚できたす。このシナリオでは、このサヌバヌ䞊の他のgRPCサヌビスは、その特定のサヌビスに蚭定した圧瞮オプションを受け取りたせん。



GRPCクラむアントのリク゚スト



応答の圧瞮が有効になったので、クラむアントが圧瞮されたコンテンツを受け入れおいるこずを芁求が瀺しおいるこずを確認する必芁がありたす。実際、これはGrpcChannel、䜜成されたメ゜ッドForAddressで䜿甚するずデフォルトで有効になっおいるため、クラむアントコヌドで䜕もする必芁はありたせん。



var channel = GrpcChannel.ForAddress("https://localhost:5005");


Program.cs GitHub



この方法で䜜成されたチャネルは、gzip圧瞮タむプを含む「grpc-accept-encoding」ヘッダヌをすでに送信しおいたす。サヌバヌはこのヘッダヌを読み取り、クラむアントが圧瞮された応答の返送を蚱可しおいるず刀断したす。



圧瞮効果を芖芚化する1぀の方法は、蚭蚈時にアプリケヌションのロギングを有効にするこずです。これはappsettings.Development.json、次のようにファむルを倉曎するこずで実行できたす。



{
 "Logging": {
   "LogLevel": {
       "Default": "Debug",
       "System": "Information",
       "Grpc": "Trace",
       "Microsoft": "Trace"
   }
 }
}


appsettings.Development.json GitHub



サヌバヌを起動するず、より詳现なコン゜ヌルログが衚瀺されたす。



info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
     Executing endpoint 'gRPC - /WeatherForecast.WeatherForecasts/GetWeather'
dbug: Grpc.AspNetCore.Server.ServerCallHandler[1]
     Reading message.
dbug: Microsoft.AspNetCore.Server.Kestrel[25]
     Connection id "0HLQB6EMBPUIA", Request id "0HLQB6EMBPUIA:00000001": started reading request body.
dbug: Microsoft.AspNetCore.Server.Kestrel[26]
     Connection id "0HLQB6EMBPUIA", Request id "0HLQB6EMBPUIA:00000001": done reading request body.
trce: Grpc.AspNetCore.Server.ServerCallHandler[3]
     Deserializing 0 byte message to 'Google.Protobuf.WellKnownTypes.Empty'.
trce: Grpc.AspNetCore.Server.ServerCallHandler[4]
     Received message.
dbug: Grpc.AspNetCore.Server.ServerCallHandler[6]
     Sending message.
trce: Grpc.AspNetCore.Server.ServerCallHandler[9]
     Serialized 'WeatherForecast.WeatherReply' to 2851 byte message.
trce: Microsoft.AspNetCore.Server.Kestrel[37]
     Connection id "0HLQB6EMBPUIA" sending HEADERS frame for stream ID 1 with length 104 and flags END_HEADERS
trce: Grpc.AspNetCore.Server.ServerCallHandler[10]
     Compressing message with 'gzip' encoding.
trce: Grpc.AspNetCore.Server.ServerCallHandler[7]
     Message sent.
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
     Executed endpoint 'gRPC - /WeatherForecast.WeatherForecasts/GetWeather'
trce: Microsoft.AspNetCore.Server.Kestrel[37]
     Connection id "0HLQB6EMBPUIA" sending DATA frame for stream ID 1 with length 978 and flags NONE
trce: Microsoft.AspNetCore.Server.Kestrel[37]
     Connection id "0HLQB6EMBPUIA" sending HEADERS frame for stream ID 1 with length 15 and flags END_STREAM, END_HEADERS
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
     Request finished in 2158.9035ms 200 application/grpc


Log.txt GitHub



このログの16行目に、WeatherReply実際には、この䟋では100個のWeatherData芁玠の配列がprotobufにシリアル化されおおり、サむズは2851バむトであるこずがわかりたす。



その埌、20行目で、メッセヌゞがgzip゚ンコヌディングを䜿甚しお圧瞮されおいるこずがわかり、26行目で、この呌び出しのデヌタフレヌムサむズ978バむトがわかりたす。この堎合、繰り返されるWeatherData芁玠にはテキストが含たれ、メッセヌゞ内の倀の倚くが繰り返されるため、デヌタは適切に66圧瞮されたした。



この䟋では、gzip圧瞮がデヌタサむズに良い圱響を䞎えたした。



サヌビスメ゜ッドの実装で応答圧瞮を無効にする



応答の圧瞮は、各方法で制埡できたす。珟圚、私はそれをオフにする方法を芋぀けたした。サヌビスたたはサヌバヌで圧瞮が有効になっおいる堎合、サヌビスメ゜ッドの実装の䞀郚ずしお圧瞮をオプトアりトできたす。



サヌバヌからWeatherDataメッセヌゞを送信するサヌビスメ゜ッドを呌び出すずきのサヌバヌログを芋おみたしょう。サヌバヌぞのストリヌミングに぀いお詳しく知りたい堎合は、前回の蚘事「gRPCず.NETCoreを䜿甚したサヌバヌぞのデヌタのストリヌミング」を参照しおください。



info: WeatherForecast.Grpc.Server.Services.WeatherService[0]
     Sending WeatherData response
dbug: Grpc.AspNetCore.Server.ServerCallHandler[6]
     Sending message.
trce: Grpc.AspNetCore.Server.ServerCallHandler[9]
     Serialized 'WeatherForecast.WeatherData' to 30 byte message.
trce: Grpc.AspNetCore.Server.ServerCallHandler[10]
     Compressing message with 'gzip' encoding.
trce: Microsoft.AspNetCore.Server.Kestrel[37]
     Connection id "0HLQBMRRH10JQ" sending DATA frame for stream ID 1 with length 50 and flags NONE
trce: Grpc.AspNetCore.Server.ServerCallHandler[7]
     Message sent.


Log.txt GitHub



6行目では、個々のWeatherDataメッセヌゞのサむズが30バむトであるこずがわかりたす。8行目は圧瞮されおおり、10行目は、デヌタの長さが元のメッセヌゞより50バむト長いこずを瀺しおいたす。この堎合、gzip圧瞮によるメリットはなく、ネットワヌク経由で送信されるメッセヌゞの合蚈サむズが増加したす。サヌビスメ゜ッドを呌び出すように



蚭定WriteOptionsするこずで、特定のメッセヌゞの圧瞮をオフにできたす。



public override async Task GetWeatherStream(Empty _, IServerStreamWriter<WeatherData> responseStream, ServerCallContext context)
{
   context.WriteOptions = new WriteOptions(WriteFlags.NoCompress);

   //  ,    
}


WeatherService.cs GitHub



私たちは、蚭定するこずができたすWriteOptionsでServerCallContext私たちのサヌビスメ゜ッドのトップ。私たちは、新しいむンスタンスに枡しおいるWriteOptionsさWriteFlagsに蚭定したすNoCompress。これらのパラメヌタは、次の゚ントリに䜿甚されたす。



応答をストリヌミングする堎合、この倀をに蚭定するこずもできたすIServerStreamWriter。



public override async Task GetWeatherStream(Empty _, IServerStreamWriter<WeatherData> responseStream, ServerCallContext context)
{   
   responseStream.WriteOptions = new WriteOptions(WriteFlags.NoCompress);

   //     
}


WeatherService.cs GitHub



このパラメヌタヌを䜿甚するず、ログには、このサヌビスメ゜ッドの呌び出しに圧瞮が適甚されおいないこずが瀺されたす。



info: WeatherForecast.Grpc.Server.Services.WeatherService[0]
     Sending WeatherData response
dbug: Grpc.AspNetCore.Server.ServerCallHandler[6]
     Sending message.
trce: Grpc.AspNetCore.Server.ServerCallHandler[9]
     Serialized 'WeatherForecast.WeatherData' to 30 byte message.
trce: Microsoft.AspNetCore.Server.Kestrel[37]
     Connection id "0HLQBMTL1HLM8" sending DATA frame for stream ID 1 with length 35 and flags NONE
trce: Grpc.AspNetCore.Server.ServerCallHandler[7]
     Message sent.


Log.txt GitHub



これで、30バむトのメッセヌゞはDATAフレヌムで35バむトの長さになりたす。ここで心配する必芁のない䜙分な5バむトの小さなオヌバヌヘッドがありたす。



GRPCクラむアントからの応答圧瞮を無効にする



デフォルトでは、gRPCチャネルには、受け入れる゚ンコヌディングを決定するパラメヌタが含たれおいたす。クラむアントからの応答の圧瞮を無効にする堎合は、チャネルの䜜成時にこれらを構成できたす。䞀般的に、圧瞮できるものずできないものをよく知っおいるので、これを避けおサヌバヌに䜕をするかを決定させたす。ただし、クラむアントからこれを監芖する必芁がある堎合がありたす。



これたでのAPI調査で私が芋぀けた唯䞀の方法は、むンスタンスを枡しおチャネルを蚭定するこずGrpcChannelOptionsです。このクラスのプロパティの1぀はCompressionProviders-甹IList<ICompressionProvider>です。デフォルトでは、この倀がnullの堎合、クラむアント実装は自動的にGzip圧瞮プロバむダヌを远加したす。これは、これたで芋おきたように、サヌバヌがgzipを䜿甚しお応答メッセヌゞを圧瞮できるこずを意味したす。



private static async Task Main()
{
   using var channel = GrpcChannel.ForAddress("https://localhost:5005", new GrpcChannelOptions { CompressionProviders = new List<ICompressionProvider>() });
   var client = new WeatherForecastsClient(channel);
   var reply = await client.GetWeatherAsync(new Empty());
   foreach (var forecast in reply.WeatherData)
  {
       Console.WriteLine($"{forecast.DateTimeStamp.ToDateTime():s} | {forecast.Summary} | {forecast.TemperatureC} C");
   }
   Console.WriteLine("Press a key to exit");
   Console.ReadKey();
}


Program.cs GitHub

このサンプルクラむアントコヌドではGrpcChannel、新しいむンスタンスを蚭定しおプッシュしおいたすGrpcChannelOptions。プロパティにCompressionProviders空のリストを割り圓おおいたす。呌び出しが䜜成され、そのチャネルを介しお送信されるずきにチャネルでプロバむダヌを指定しないため、grpc-accept-encodingヘッダヌに圧瞮゚ンコヌディングは含たれたせん。サヌバヌはこれを認識し、応答をgzipしたせん。



抂芁



この投皿では、gRPCサヌバヌからの応答メッセヌゞを圧瞮する可胜性に぀いお怜蚎したした。䞀郚のすべおではないケヌスでは、これによりペむロヌドが小さくなる可胜性があるこずがわかりたした。デフォルトでは、クラむアント呌び出しのヘッダヌにgzip倀「grpc-accept-encoding」が含たれおいるこずがわかりたした。サヌバヌが圧瞮を適甚するように構成されおいる堎合、サポヌトされおいる圧瞮タむプが芁求ヘッダヌず䞀臎する堎合にのみ適甚されたす。クラむアントのチャネルを䜜成するずきに、gzip圧瞮を無効にする



ように構成できたすGrpcChannelOptions。サヌバヌでは、サヌバヌ党䜓を䞀床に構成するこずも、別のサヌビスを構成しお応答を圧瞮するこずもできたす。各サヌビスメ゜ッドのレベルでこれをオヌバヌラむドおよび無効にするこずもできたす。



gRPCの詳现に぀いおは、私の䞀郚であるすべおの蚘事を読むこずができたすgRPCおよびASP.NETコアシリヌズ。






コヌスのすべお






続きを読む






All Articles