Teljesítménnyel kapcsolatos ajánlott eljárások a gRPC-vel
Figyelmeztetés
A ASP.NET Core ezen verziója már nem támogatott. További információ: .NET és .NET Core támogatási szabályzat. A jelen cikk .NET 9-es verzióját lásd az aktuális kiadásért .
Fontos
Ezek az információk egy olyan előzetes termékre vonatkoznak, amelyet a kereskedelmi forgalomba kerülés előtt jelentősen módosíthatnak. A Microsoft nem vállal kifejezett vagy hallgatólagos szavatosságot az itt megadott információkra vonatkozóan.
A jelen cikk .NET 9-es verzióját lásd az aktuális kiadásért .
Írta: James Newton-King
A gRPC nagy teljesítményű szolgáltatásokhoz készült. Ez a dokumentum bemutatja, hogyan lehet a lehető legjobb teljesítményt elérni a gRPC-ből.
GRPC-csatornák újrafelhasználása
A gRPC-csatornákat gRPC-hívások esetén újra fel kell használni. A csatornák újrafelhasználásával a hívások egy meglévő HTTP/2-kapcsolaton keresztül multiplexelhetők.
Ha minden gRPC-híváshoz új csatorna jön létre, akkor a befejezéshez szükséges idő jelentősen megnőhet. Minden híváshoz több hálózati körút szükséges az ügyfél és a kiszolgáló között egy új HTTP/2-kapcsolat létrehozásához:
- Csatlakozó megnyitása
- TCP-kapcsolat létrehozása
- TLS kapcsolat kialakítása
- HTTP/2 kapcsolat indítása
- GRPC-hívás indítása
A csatornák biztonságosan megoszthatók és újra felhasználhatók a gRPC-hívások között:
- A gRPC klienseket csatornák segítségével hozzák létre. A gRPC-ügyfelek könnyű objektumok, nem szükséges őket gyorsítótárban tárolni vagy újra felhasználni.
- Egy csatornáról több gRPC-ügyfél is létrehozható, beleértve a különböző típusú ügyfeleket is.
- Több szál is biztonságosan használhatja a csatornát és az abból létrehozott klienseket.
- A csatornáról létrehozott ügyfelek több egyidejű hívást is kezdeményezhetnek.
A gRPC-ügyfél-előállító központosított módot kínál a csatornák konfigurálására. Automatikusan újra felhasználja a mögöttes csatornákat. További információért lásd: gRPC-ügyfélgyár integrációja a .NET-ben.
Kapcsolat párhuzamossága
A HTTP/2-kapcsolatok általában korlátozzák a kapcsolaton egyszerre egyidejű streamek (aktív HTTP-kérések) maximális számát. Alapértelmezés szerint a legtöbb kiszolgáló ezt a korlátot 100 egyidejű streamre állítja be.
A gRPC-csatornák egyetlen HTTP/2 kapcsolatot használnak, és az egyidejű hívások multiplexáltak ezen a kapcsolaton. Amikor az aktív hívások száma eléri a kapcsolat streamkorlátját, a rendszer további hívásokat is várólistára állít az ügyfélben. A várakozó hívások megvárják, amíg az aktív hívások befejeződnek, mielőtt továbbítják őket. A nagy terhelésű vagy hosszú ideig futó streamelési gRPC-hívásokkal rendelkező alkalmazások teljesítményproblémákat tapasztalhatnak, amelyeket a hívások sorban állása okoz a korlát miatt.
A .NET 5 bemutatja a SocketsHttpHandler.EnableMultipleHttp2Connections tulajdonságot. Ha true
értékre van állítva, a csatorna további HTTP/2-kapcsolatokat hoz létre az egyidejű streamkorlát elérésekor. A GrpcChannel
létrehozásakor a belső SocketsHttpHandler
automatikusan további HTTP/2-kapcsolatok létrehozására van konfigurálva. Ha egy alkalmazás saját kezelőt konfigurál, fontolja meg a EnableMultipleHttp2Connections
true
beállítását:
var channel = GrpcChannel.ForAddress("https://localhost", new GrpcChannelOptions
{
HttpHandler = new SocketsHttpHandler
{
EnableMultipleHttp2Connections = true,
// ...configure other handler settings
}
});
A gRPC-hívásokat kezdeményező .NET-keretrendszeralkalmazásokat WinHttpHandler
használatára kell konfigurálni. A .NET-keretrendszeralkalmazások a WinHttpHandler.EnableMultipleHttp2Connections tulajdonságot true
értékre állíthatják további kapcsolatok létrehozásához.
A .NET Core 3.1-alkalmazásokhoz számos áthidaló megoldás érhető el:
- Hozzon létre külön gRPC-csatornákat az alkalmazás nagy terhelésű területeihez. Előfordulhat például, hogy a
Logger
gRPC szolgáltatás nagy terheléssel rendelkezik. Hozzon létre egy külön csatornát az alkalmazásban aLoggerClient
számára. - Használjon gRPC-csatornák készletét, például hozzon létre egy listát a gRPC-csatornákról.
Random
minden alkalommal, amikor gRPC-csatornára van szükség, kiválaszt egy csatornát a listából. ARandom
véletlenszerűen osztja el a hívásokat több kapcsolaton keresztül.
Fontos
A probléma megoldásához egy másik módszer a kiszolgáló egyidejű streamkorlátjának növelése. A Kestrel ezzel van konfigurálva: MaxStreamsPerConnection.
Az egyidejű stream maximális korlátjának növelése nem ajánlott. Egy HTTP/2-kapcsolat túl sok streamje új teljesítményproblémákat vezet be:
- A kapcsolatra írni próbáló streamek közötti ütközés.
- A kapcsolati csomagvesztés miatt az összes hívás blokkolva lesz a TCP-rétegben.
ServerGarbageCollection
ügyfélalkalmazásokban
A .NET szemétgyűjtőnek két módja van: a munkaállomás szemétgyűjtése (GC) és a kiszolgálói szemétgyűjtés. Mindegyik különböző számítási feladatokhoz van hangolva. ASP.NET Core-alkalmazások alapértelmezés szerint kiszolgálói GC-t használnak.
A magas egyidejűségű alkalmazások általában jobban teljesítenek a kiszolgálói GC-vel. Ha egy gRPC-ügyfélalkalmazás egyszerre nagy számú gRPC-hívást küld és fogad, akkor az alkalmazás kiszolgálói GC használatára való frissítésének teljesítménybeli előnye lehet.
A szerver Garbage Collector (GC) engedélyezéséhez állítsa be a <ServerGarbageCollection>
az alkalmazás projektfájljában:
<PropertyGroup>
<ServerGarbageCollection>true</ServerGarbageCollection>
</PropertyGroup>
További információ a szemétgyűjtésről: Munkaállomás és kiszolgáló szemétgyűjtési.
Jegyzet
ASP.NET Core-alkalmazások alapértelmezés szerint kiszolgálói GC-t használnak. A <ServerGarbageCollection>
engedélyezése csak a nem kiszolgálói gRPC-ügyfélalkalmazásokban hasznos, például egy gRPC-ügyfélkonzol-alkalmazásban.
Aszinkron hívások az ügyfélalkalmazásokban
Inkább aszinkron programozást használjon aszinkronnal, és várja meg a gRPC-metódusok meghívásakor. Ha gRPC-hívásokat kezdeményez blokkolással, például Task.Result
vagy Task.Wait()
használatával, megakadályozza, hogy más feladatok használják a szálakat. Ez a szálkészlet éhezéséhez, teljesítményromláshoz vezethet, és az alkalmazás holtpontra juthat.
Minden gRPC-metódustípus aszinkron API-kat hoz létre a gRPC-ügyfeleken. A kivétel az unáris metódusok, amelyek aszinkron és blokkoló metódusokat generálnak.
Fontolja meg a következő gRPC szolgáltatást, amely egy .proto fájlban van definiálva:
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
A létrehozott GreeterClient
típusa két .NET-metódussal rendelkezik a SayHello
hívásához:
-
GreeterClient.SayHelloAsync
– aGreeter.SayHello
szolgáltatást aszinkron módon hívja meg. Lehet várni rá. -
GreeterClient.SayHello
– meghívja aGreeter.SayHello
szolgáltatást, és blokkolja a folyamatot a befejezésig.
A blokkoló GreeterClient.SayHello
metódus nem használható aszinkron kódban. Teljesítmény- és megbízhatósági problémákat okozhat.
Terheléselosztás
Egyes terheléselosztók nem működnek hatékonyan a gRPC-vel. Az L4 (átviteli) terheléselosztók kapcsolati szinten működnek a TCP-kapcsolatok végpontok közötti elosztásával. Ez a megközelítés jól működik a HTTP/1.1 használatával indított API-hívások terheléselosztásához. A HTTP/1.1 használatával egyidejűleg indított hívások különböző kapcsolatokon lesznek elküldve, így a hívások terhelése a végpontok között elosztható.
Mivel az L4 terheléselosztók kapcsolati szinten működnek, nem működnek jól a gRPC-vel. A gRPC HTTP/2-t használ, amely több hívást is multiplexel egyetlen TCP-kapcsolaton. A kapcsolaton keresztüli összes gRPC-hívás egy végpontra kerül.
A gRPC hatékony terheléselosztásának két lehetősége van:
- Ügyféloldali terheléselosztás
- L7 (alkalmazás) proxy terheléselosztása
Jegyzet
Csak a gRPC-hívások esetében lehet terheléselosztást végezni a végpontok között. Miután létrejött egy streamelési gRPC-hívás, a streamen keresztül küldött összes üzenet egy végpontra kerül.
Ügyféloldali terheléselosztás
Az ügyféloldali terheléselosztással az ügyfél ismeri a végpontokat. Minden gRPC-híváshoz kiválaszt egy másik végpontot a hívás elküldéséhez. Az ügyféloldali terheléselosztás akkor jó választás, ha fontos a késés. Az ügyfél és a szolgáltatás között nincs proxy, ezért a rendszer közvetlenül a szolgáltatásnak küldi a hívást. Az ügyféloldali terheléselosztás hátránya, hogy minden ügyfélnek nyomon kell követnie a használni kívánt elérhető végpontokat.
A Lookaside-ügyfél terheléselosztása egy olyan technika, amelyben a terheléselosztási állapot egy központi helyen van tárolva. Az ügyfelek rendszeres időközönként lekérdezik a központi helyet, hogy a terheléselosztási döntések meghozatalakor használandó információkat kereshessenek.
További információ: gRPC ügyféloldali terheléselosztási.
Proxy terhelés-kiegyenlítése
Az L7 (alkalmazás-) proxy magasabb szinten működik, mint egy L4 (átviteli) proxy. Az L7 proxyk megértik a HTTP/2-t. A proxy egy HTTP/2-kapcsolaton multiplexált gRPC-hívásokat fogad, és több háttérvégpont között osztja el őket. A proxy használata egyszerűbb, mint az ügyféloldali terheléselosztás, de további késést ad a gRPC-hívásokhoz.
Sok L7 proxy érhető el. Néhány lehetőség:
- Megbízott – Népszerű nyílt forráskódú proxy.
- Linkerd – A Kubernetes szolgáltatáshálója.
- YARP: Még egy fordított proxy – Nyílt forráskódú proxy, amely .NET-ben íródott.
Folyamatközi kommunikáció
Az ügyfél és a szolgáltatás közötti gRPC-hívásokat általában TCP-szoftvercsatornákon keresztül küldik el. A TCP kiválóan alkalmas a hálózaton keresztüli kommunikációra, de folyamatközi kommunikáció (IPC) hatékonyabb, ha az ügyfél és a szolgáltatás ugyanazon a gépen van.
Fontolja meg egy olyan átvitel használatát, mint a Unix tartományi szoftvercsatornák vagy a nevesített csövek az ugyanazon a gépen lévő folyamatok közötti gRPC-hívásokhoz. További információ: GRPCfolyamatközi kommunikációja.
Életben tartó pingek
A http/2-kapcsolatok életben tartására szolgáló pingek az inaktivitás időszakában is használhatók. Ha egy meglévő HTTP/2-kapcsolat készen áll, amikor egy alkalmazás folytatja a tevékenységet, lehetővé teszi a kezdeti gRPC-hívások gyors indítását, a kapcsolat újbóli megnyitása által okozott késés nélkül.
Az életben tartás pingjei a SocketsHttpHandler-en vannak konfigurálva.
var handler = new SocketsHttpHandler
{
PooledConnectionIdleTimeout = Timeout.InfiniteTimeSpan,
KeepAlivePingDelay = TimeSpan.FromSeconds(60),
KeepAlivePingTimeout = TimeSpan.FromSeconds(30),
EnableMultipleHttp2Connections = true
};
var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions
{
HttpHandler = handler
});
Az előző kód konfigurál egy csatornát, amely 60 másodpercenként küld élő pinget a kiszolgálónak inaktivitási időszakokban. A pingelés biztosítja, hogy a kiszolgáló és a használatban lévő proxyk inaktivitás miatt ne zárják be a kapcsolatot.
Jegyzet
A pingelések csak a kapcsolat életben tartását segítik. Előfordulhat, hogy a kapcsolaton futó, hosszan futó gRPC-hívásokat a kiszolgáló vagy a közvetítő proxyk inaktivitás miatt továbbra is leálltathatják.
Áramlásvezérlés
A HTTP/2 folyamatvezérlés egy olyan funkció, amely megakadályozza, hogy az alkalmazások túlterheltek legyenek az adatokkal. Folyamatvezérlés használata esetén:
- Minden HTTP/2 kapcsolat és kérés rendelkezik egy elérhető pufferablakkal. A pufferablak azt határozza meg, hogy az alkalmazás mennyi adatot fogadhat egyszerre.
- A folyamatvezérlő aktiválódik, ha a pufferablak ki van töltve. Aktiváláskor a küldő alkalmazás szünetelteti a további adatok küldését.
- Miután a fogadó alkalmazás feldolgozta az adatokat, a pufferablakban szabad hely áll rendelkezésre. A küldő alkalmazás folytatja az adatok küldését.
A folyamatvezérlés negatív hatással lehet a teljesítményre, ha nagy üzeneteket fogad. Ha a pufferablak kapacitása kisebb, mint a bejövő üzenetek hasznos adatainak mérete, vagy késés van az ügyfél és a kiszolgáló között, akkor az adatok szakaszos indítási és leállítási sorozatokban továbbíthatók.
A folyamatvezérlés teljesítményproblémái a pufferablak méretének növelésével javíthatók. Az alkalmazás indításakor a Kestrel-t InitialConnectionWindowSize és InitialStreamWindowSize segítségével konfigurálják.
builder.WebHost.ConfigureKestrel(options =>
{
var http2 = options.Limits.Http2;
http2.InitialConnectionWindowSize = 1024 * 1024 * 2; // 2 MB
http2.InitialStreamWindowSize = 1024 * 1024; // 1 MB
});
Ajánlások:
- Ha egy gRPC-szolgáltatás gyakran 768 KB-nál nagyobb üzeneteket fogad, Kestrela streamablak alapértelmezett méretét, akkor fontolja meg a kapcsolat és a streamablak méretének növelését.
- A kapcsolati ablak méretének mindig egyenlőnek vagy nagyobbnak kell lennie, mint a streamablak mérete. A stream a kapcsolat része, és a feladót mindkettő korlátozza.
További információ a folyamatvezérlés működéséről: HTTP/2 folyamatvezérlés (blogbejegyzés).
Fontos
A Kestrelablakméretének növelése lehetővé teszi, hogy Kestrel több adatot puffereljen az alkalmazás nevében, ami esetleg növeli a memóriahasználatot. Ne konfiguráljon szükségtelenül nagy méretű ablakokat.
A streaming hívások zökkenőmentes befejezése
Próbálja meg elegánsan befejezni a streamelési hívásokat. A hívások kecses végrehajtása elkerüli a szükségtelen hibákat, és lehetővé teszi a kiszolgálók számára a belső adatstruktúrák kérések közötti újrafelhasználását.
A hívás akkor fejeződik be, ha az ügyfél és a kiszolgáló befejezte az üzenetek küldését, és a társ elolvasta az összes üzenetet.
Ügyfélkérés streamje:
- Az ügyfél befejezte az üzenetek írását a kérési folyamra, és a folyamatot lezárja
call.RequestStream.CompleteAsync()
-val. - A kiszolgáló minden üzenetet beolvasott a kérelemstreamből. Az üzenetek olvasási módjától függően vagy a
requestStream.MoveNext()
visszatérfalse
-ként, vagy arequestStream.ReadAllAsync()
befejeződött.
Kiszolgáló válaszfolyama:
- A kiszolgáló befejezte az üzenetek írását a válaszfolyamba, és a kiszolgáló metódusa befejeződött.
- Az ügyfél elolvasta a válaszfolyam összes üzenetét. Az üzenetek olvasási módjától függően, vagy a
call.ResponseStream.MoveNext()
visszatér afalse
-hez, vagy acall.ResponseStream.ReadAllAsync()
befejeződik.
A kétirányú streamelési hívások kecses végrehajtására példa: kétirányú streamelési hívás.
A kiszolgáló streamelési hívásai nem rendelkeznek kérések adatfolyamával. Ez azt jelenti, hogy az ügyfél csak úgy tud kommunikálni a kiszolgálóval, hogy a streamnek le kell állnia, ha megszakítja azt. Ha a megszakított hívások többletterhelése hatással van az alkalmazásra, fontolja meg, hogy a kiszolgáló streamelési hívását kétirányú streamelési hívásra módosítsa. Kétirányú streamelési hívás esetén a kérésfolyamot befejező ügyfél jelzés lehet a kiszolgálónak a hívás befejezéséhez.
Adatfolyam-hívások eltávolítása
Ha már nincs rájuk szükség, mindig dobja el a streamelési hívásokat. Az a típus, amelyet streamelési hívások indításakor adunk vissza, implementálja a IDisposable
-t. Ha a hívásra már nincs szükség, akkor a rendszer leállítja, és az összes erőforrást megtisztítja.
Az alábbi példában a using deklaráció a AccumulateCount()
hívás során gondoskodik arról, hogy mindig megfelelően megsemmisüljön, ha váratlan hiba történik.
var client = new Counter.CounterClient(channel);
using var call = client.AccumulateCount();
for (var i = 0; i < 3; i++)
{
await call.RequestStream.WriteAsync(new CounterRequest { Count = 1 });
}
await call.RequestStream.CompleteAsync();
var response = await call;
Console.WriteLine($"Count: {response.Count}");
// Count: 3
Ideális esetben a streamelési hívásokat elegánsan kell befejezni. A hívás letiltása biztosítja, hogy az ügyfél és a kiszolgáló közötti HTTP-kérés váratlan hiba esetén megszakadjon. A véletlenül futó streamelési hívások nem csak a memóriát és az erőforrásokat szivárgják ki az ügyfélen, hanem a kiszolgálón is futnak. Sok kiszivárgott streamhívás befolyásolhatja az alkalmazás stabilitását.
Egy már sikeresen befejezett streamhívás törlése nem jár semmilyen negatív hatással.
Egyedi hívások cseréje streamelésre
A gRPC kétirányú streamelése használható az egyszeri gRPC-hívások helyett nagy teljesítményű helyzetekben. Ha egy kétirányú stream elindult, az üzenetek oda-vissza streamelése gyorsabb, mint az üzenetek küldése több egyirányú gRPC-hívással. A streamelt üzeneteket a rendszer egy meglévő HTTP/2-kérelem adataiként küldi el, és kiküszöböli az új HTTP/2-kérések létrehozásának többletterhelését minden egyes nem ütemezett híváshoz.
Példaszolgáltatás:
public override async Task SayHello(IAsyncStreamReader<HelloRequest> requestStream,
IServerStreamWriter<HelloReply> responseStream, ServerCallContext context)
{
await foreach (var request in requestStream.ReadAllAsync())
{
var helloReply = new HelloReply { Message = "Hello " + request.Name };
await responseStream.WriteAsync(helloReply);
}
}
Példaügyfél:
var client = new Greet.GreeterClient(channel);
using var call = client.SayHello();
Console.WriteLine("Type a name then press enter.");
while (true)
{
var text = Console.ReadLine();
// Send and receive messages over the stream
await call.RequestStream.WriteAsync(new HelloRequest { Name = text });
await call.ResponseStream.MoveNext();
Console.WriteLine($"Greeting: {call.ResponseStream.Current.Message}");
}
A váratlan hívások kétirányú streamelésre való cseréje teljesítménybeli okokból speciális technika, és sok esetben nem megfelelő.
A streamelési hívások használata akkor jó választás, ha:
- Nagy átviteli sebességre vagy alacsony késésre van szükség.
- A gRPC és a HTTP/2 teljesítménybeli szűk keresztmetszetként van azonosítva.
- Az ügyfél egy munkatársa rendszeres üzeneteket küld vagy fogad egy gRPC-szolgáltatással.
Vegye figyelembe a folyamatos hívások használatával járó további összetettséget és korlátokat, szemben az unáris hívások egyszerűségével.
- A streameket szolgáltatás- vagy csatlakozási hiba szakíthatja meg. Hiba esetén logikára van szükség a stream újraindításához.
-
RequestStream.WriteAsync
nem biztonságos a többszálas használatra. Egyszerre csak egy üzenet írható streambe. Amikor üzeneteket küld több szálból egyetlen streamen keresztül, egy gyártói/fogyasztói üzenetsorra van szükség, például Channel<T> az üzenetek összeállításához. - A gRPC-streamelési módszer egyetlen üzenettípus fogadására és egy üzenettípus küldésére korlátozódik.
rpc StreamingCall(stream RequestMessage) returns (stream ResponseMessage)
példáulRequestMessage
kap, ésResponseMessage
küld. A Protobuf által az ismeretlen vagy feltételes üzenetekAny
ésoneof
használatával történő támogatása megkerülheti ezt a korlátozást.
Bináris terhek
A Protobuf támogatja a bináris adatterheléseket a bytes
skaláris értéktípussal. A C#-ban létrehozott tulajdonság ByteString
használ tulajdonságtípusként.
syntax = "proto3";
message PayloadResponse {
bytes data = 1;
}
A Protobuf egy bináris formátum, amely hatékonyan szerializálja a nagy bináris hasznos adatokat minimális többletterheléssel. A JSON-hoz hasonló szöveges formátumokban meg kell, hogy történjen a bájtok base64 kódolása, ami 33%-t ad hozzá az üzenet méretéhez.
Nagy ByteString
terhelések kezelésénél az alábbiakban tárgyalt legjobb gyakorlatok segíthetnek elkerülni a felesleges másolatokat és memóriafoglalásokat.
Bináris adatcsomagok küldése
ByteString
példányok általában ByteString.CopyFrom(byte[] data)
használatával jönnek létre. Ez a módszer egy új ByteString
és egy új byte[]
foglal le. Az adatok át lesznek másolva az új bájttömbbe.
UnsafeByteOperations.UnsafeWrap(ReadOnlyMemory<byte> bytes)
alkalmazásával elkerülhetők a plusz foglalatok és másolatok a ByteString
példányok létrehozásakor.
var data = await File.ReadAllBytesAsync(path);
var payload = new PayloadResponse();
payload.Data = UnsafeByteOperations.UnsafeWrap(data);
A bájtok nem másolhatók UnsafeByteOperations.UnsafeWrap
, ezért nem módosíthatók, amíg a ByteString
használatban van.
UnsafeByteOperations.UnsafeWrap
Google.Protobuf 3.15.0-s vagy újabb verzióját igényli.
Bináris adatfolyamok olvasása
Az adatok hatékonyan olvashatók ByteString
példányokból ByteString.Memory
és ByteString.Span
tulajdonságok használatával.
var byteString = UnsafeByteOperations.UnsafeWrap(new byte[] { 0, 1, 2 });
var data = byteString.Span;
for (var i = 0; i < data.Length; i++)
{
Console.WriteLine(data[i]);
}
Ezek a tulajdonságok lehetővé teszik, hogy a kód közvetlenül olvasson be adatokat egy ByteString
-ból foglalások és másolatok nélkül.
A legtöbb .NET API ReadOnlyMemory<byte>
és byte[]
túlterhelt, ezért ByteString.Memory
ajánlott a mögöttes adatok használata. Vannak azonban olyan körülmények, amikor egy alkalmazásnak bájttömbként kell lekérnie az adatokat. Ha bájttömbre van szüksége, akkor a MemoryMarshal.TryGetArray metódussal mind az adatok új másolatának kiosztása nélkül is kaphat egy tömböt egy ByteString
-ból.
var byteString = GetByteString();
ByteArrayContent content;
if (MemoryMarshal.TryGetArray(byteString.Memory, out var segment))
{
// Success. Use the ByteString's underlying array.
content = new ByteArrayContent(segment.Array, segment.Offset, segment.Count);
}
else
{
// TryGetArray didn't succeed. Fall back to creating a copy of the data with ToByteArray.
content = new ByteArrayContent(byteString.ToByteArray());
}
var httpRequest = new HttpRequestMessage();
httpRequest.Content = content;
Az előző kód:
- Kísérlet egy tömb lekérésére
ByteString.Memory
-ból a MemoryMarshal.TryGetArraysegítségével. - Használja az
ArraySegment<byte>
-t, ha az sikerült lekérni. A szegmens hivatkozik a tömbre, az eltolásra és a darabszámra. - Ellenkező esetben visszatér ahhoz, hogy egy új tömböt allokáljon
ByteString.ToByteArray()
.
gRPC-szolgáltatások és nagy bináris terhelések
A gRPC és a Protobuf nagy bináris hasznos adatokat tud küldeni és fogadni. Bár a bináris Protobuf hatékonyabb, mint a szöveges JSON a bináris hasznos adatok szerializálásában, a nagy bináris hasznos adatok használatakor még mindig fontos teljesítményjellemzőket kell szem előtt tartani.
A gRPC egy üzenetalapú RPC-keretrendszer, amely a következőt jelenti:
- A rendszer a teljes üzenetet betölti a memóriába, mielőtt a gRPC elküldené.
- Az üzenet érkezésekor a rendszer a teljes üzenetet deszerializálja a memóriába.
A bináris terhelések bájttömbként vannak lefoglalva. Egy 10 MB-os bináris adat például 10 MB bájttömböt foglal le. A nagy bináris hasznos terhelésű üzenetek bájttömböket foglalhatnak el a nagy objektumhalmon. A nagy foglalások hatással vannak a kiszolgáló teljesítményére és méretezhetőségére.
Tanácsok nagy teljesítményű alkalmazások létrehozásához nagy mennyiségű bináris adattartalommal:
- Kerülje el a nagy bináris terheléseket a gRPC-üzenetekben. A 85 000 bájtnál nagyobb bájt méretű bájttömbök nagy objektumnak minősülnek. Az adott méret alatt maradva elkerüli a nagy objektumtömbbe történő allokálást.
- Fontolja meg a nagy bináris hasznos terhek felosztásátgRPC folyam használatával. A bináris adatok több üzeneten keresztül lesznek adattömbítve és streamelve. A fájlok streamelésére vonatkozó további információkért tekintse meg a grpc-dotnet adattár példáit:
- Fontolja meg, nem használja a gRPC-t nagy bináris adatokhoz. A ASP.NET Core-ban a webes API-k a gRPC-szolgáltatások mellett használhatók. A HTTP-végpontok közvetlenül hozzáférhetnek a kérés- és válaszstream törzséhez: