gRPC ile en iyi performans uygulamaları
Uyarı
ASP.NET Core'un bu sürümü artık desteklenmiyor. Daha fazla bilgi için bkz . .NET ve .NET Core Destek İlkesi. Geçerli sürüm için bu makalenin .NET 9 sürümüne bakın.
Yayınlayan James Newton-King
gRPC, yüksek performanslı hizmetler için tasarlanmıştır. Bu belgede gRPC'den mümkün olan en iyi performansın nasıl elde edilir açıklanmaktadır.
gRPC kanallarını yeniden kullanma
gRPC çağrıları yapılırken gRPC kanalı yeniden kullanılmalıdır. Kanalı yeniden kullanmak, aramaların var olan bir HTTP/2 bağlantısı üzerinden çoğullama yapmasına olanak tanır.
Her gRPC çağrısı için yeni bir kanal oluşturulursa tamamlanması gereken süre önemli ölçüde artabilir. Her çağrı, yeni bir HTTP/2 bağlantısı oluşturmak için istemci ile sunucu arasında birden çok ağ gidiş dönüşleri gerektirir:
- Soket açma
- TCP bağlantısı oluşturma
- TLS Anlaşması
- HTTP/2 bağlantısını başlatma
- gRPC çağrısı yapma
Kanalların gRPC çağrıları arasında paylaşılıp yeniden kullanılması güvenlidir:
- gRPC istemcileri kanallarla oluşturulur. gRPC istemcileri basit nesnelerdir ve önbelleğe alınması veya yeniden kullanılması gerekmez.
- Farklı istemci türleri dahil olmak üzere bir kanaldan birden çok gRPC istemcisi oluşturulabilir.
- Kanaldan oluşturulan bir kanal ve istemciler birden çok iş parçacığı tarafından güvenle kullanılabilir.
- Kanaldan oluşturulan istemciler birden çok eşzamanlı arama yapabilir.
gRPC istemci fabrikası, kanalları yapılandırmak için merkezi bir yol sunar. Temel alınan kanalları otomatik olarak yeniden kullanır. Daha fazla bilgi için bkz .NET'te gRPC istemci fabrikası tümleştirmesi.
Bağlantı eşzamanlılığı
HTTP/2 bağlantıları genellikle bir kerede bir bağlantıdaki en fazla eşzamanlı akış (etkin HTTP istekleri) sayısı sınırına sahiptir. Varsayılan olarak, çoğu sunucu bu sınırı 100 eşzamanlı akış olarak ayarlar.
GRPC kanalı tek bir HTTP/2 bağlantısı kullanır ve bu bağlantıda eşzamanlı çağrılar çoğullanır. Etkin çağrı sayısı bağlantı akışı sınırına ulaştığında, istemcide ek çağrılar kuyruğa alınır. Kuyruğa alınan çağrılar, gönderilmeden önce etkin çağrıların bitmesini bekler. Yüksek yük veya uzun süre çalışan gRPC çağrılarına sahip uygulamalar, bu sınır nedeniyle çağrıların kuyruğa alınmasından kaynaklanan performans sorunları yaşayabilir.
.NET 5, SocketsHttpHandler.EnableMultipleHttp2Connections özelliğini getiriyor. olarak ayarlandığında, eş zamanlı akış sınırına true
ulaşıldığında kanal tarafından ek HTTP/2 bağlantıları oluşturulur. bir GrpcChannel
oluşturulduğunda iç SocketsHttpHandler
otomatik olarak ek HTTP/2 bağlantıları oluşturacak şekilde yapılandırılır. Bir uygulama kendi işleyicisini yapılandırıyorsa, EnableMultipleHttp2Connections
’yi true
olarak ayarlamayı göz önünde bulundurun.
var channel = GrpcChannel.ForAddress("https://localhost", new GrpcChannelOptions
{
HttpHandler = new SocketsHttpHandler
{
EnableMultipleHttp2Connections = true,
// ...configure other handler settings
}
});
gRPC çağrıları yapmak için kullanılan .NET Framework uygulamaları WinHttpHandler
şeklinde yapılandırılmalıdır. .NET Framework uygulamaları ek bağlantılar oluşturmak için özelliğini WinHttpHandler.EnableMultipleHttp2Connections olarak ayarlayabilirtrue
.
.NET Core 3.1 uygulamaları için birkaç geçici çözüm vardır:
- Uygulamanın yüksek yüke sahip alanları için ayrı gRPC kanalları oluşturun. Örneğin gRPC
Logger
hizmetinin yükü yüksek olabilir. UygulamadaLoggerClient
oluşturmak için ayrı bir kanal kullanın. - gRPC kanallarının havuzunu kullanın; örneğin, gRPC kanallarının listesini oluşturun.
Random
, her gRPC kanalı gerektiğinde listeden bir kanal seçmek için kullanılır. KullanarakRandom
, çağrıları birden çok bağlantı üzerinden rastgele dağıtır.
Önemli
Bu sorunu çözmenin başka bir yolu da sunucuda eşzamanlı akış sınırının üst sınırını artırmaktır. Bu Kestrel, MaxStreamsPerConnection ile yapılandırılır.
Eşzamanlı akış üst sınırının artırılması önerilmez. Tek bir HTTP/2 bağlantısında çok fazla akış yeni performans sorunlarına neden olur:
- Bağlantıya yazmaya çalışan akışlar arasındaki iş parçacığı çekişmesi.
- Bağlantı paketi kaybı, TCP katmanında tüm çağrıların engellenmesine neden olur.
ServerGarbageCollection
istemci uygulamalarında
.NET çöp toplayıcısının iki modu vardır: iş istasyonu çöp toplama (GC) ve sunucu çöp toplama. Her biri farklı iş yükleri için ayarlanmıştır. ASP.NET Core uygulamaları varsayılan olarak sunucu GC'lerini kullanır.
Yüksek oranda eş zamanlı uygulamalar genellikle sunucu GC ile daha iyi performans gösterir. Bir gRPC istemci uygulaması aynı anda çok sayıda gRPC çağrısı gönderiyor ve alıyorsa, uygulamayı sunucu GC'sini kullanacak şekilde güncelleştirmenin bir performans avantajı olabilir.
Sunucu GC'yi etkinleştirmek için uygulamanın proje dosyasında ayarlayın <ServerGarbageCollection>
:
<PropertyGroup>
<ServerGarbageCollection>true</ServerGarbageCollection>
</PropertyGroup>
Çöp toplama hakkında daha fazla bilgi için İş istasyonu ve sunucu çöp toplama bölümüne bakın.
Not
ASP.NET Core uygulamaları varsayılan olarak sunucu GC'lerini kullanır.
<ServerGarbageCollection>
Etkinleştirme yalnızca sunucu dışı gRPC istemci uygulamalarında, örneğin bir gRPC istemci konsol uygulamasında kullanışlıdır.
İstemci uygulamalarında eşzamansız çağrılar
zaman uyumsuz programlamayı zaman uyumsuz olarak kullanmayı tercih edin ve gRPC yöntemlerini çağırırken bekleyin.
Task.Result
veya Task.Wait()
gibi bloklama yöntemleri kullanarak gRPC çağrıları yapmak, diğer görevlerin bir iş parçacığını kullanmasını önler. Bu, iş parçacığı havuzu yetersizliğine, düşük performansa ve uygulamanın bir kilitlenme nedeniyle takılıp kalmasına neden olabilir.
Tüm gRPC yöntem türleri gRPC istemcilerinde zaman uyumsuz API'ler oluşturur. İstisna, hem zaman uyumsuz hem de engelleme yöntemleri oluşturan üniter yöntemlerdir.
.proto dosyasında tanımlanan aşağıdaki gRPC hizmetini göz önünde bulundurun:
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
Oluşturulan GreeterClient
türü, SayHello
çağırmak için iki .NET yöntemine sahiptir:
-
GreeterClient.SayHelloAsync
-Greeter.SayHello
hizmetini asenkron olarak çağırır. Beklenebilir. -
GreeterClient.SayHello
-Greeter.SayHello
hizmetini çağırır ve tamamlanana kadar bloke eder.
Engelleme GreeterClient.SayHello
yöntemi zaman uyumsuz kodda kullanılmamalıdır. Performans ve güvenilirlik sorunlarına neden olabilir.
Yük dengeleme
Bazı yük dengeleyiciler gRPC ile etkili bir şekilde çalışmaz. L4 (aktarım) yük dengeleyicileri, TCP bağlantılarını uç noktalar arasında dağıtarak bağlantı düzeyinde çalışır. Bu yaklaşım, HTTP/1.1 ile yapılan dengeleme API çağrılarını yüklemek için iyi çalışır. HTTP/1.1 ile yapılan eşzamanlı çağrılar farklı bağlantılarda gönderilerek çağrıların uç noktalar arasında yük dengelemesine olanak tanır.
L4 yük dengeleyiciler bağlantı düzeyinde çalıştığından gRPC ile iyi çalışmaz. gRPC, tek bir TCP bağlantısında birden çok çağrıyı çoğullayan HTTP/2 kullanır. Bu bağlantı üzerinden yapılan tüm gRPC çağrıları bir uç noktaya gider.
gRPC'yi etkili bir şekilde yük dengelemek için iki seçenek vardır:
- İstemci tarafı yük dengeleme
- L7 (uygulama) ara sunucu yük dengelemesi
Not
Yalnızca gRPC çağrıları uç noktalar arasında yük dengelenebilir. Bir akış gRPC çağrısı oluşturulduktan sonra, akış boyunca gönderilen tüm iletiler tek bir uç noktaya gider.
İstemci tarafı yük dengeleme
İstemci tarafı yük dengeleme ile istemci uç noktaları bilir. Her gRPC çağrısı için çağrıyı göndermek için farklı bir uç nokta seçer. gecikme süresi önemli olduğunda istemci tarafı yük dengeleme iyi bir seçimdir. İstemci ile hizmet arasında ara sunucu olmadığından çağrı doğrudan hizmete gönderilir. İstemci tarafı yük dengelemenin dezavantajı, her istemcinin kullanması gereken kullanılabilir uç noktaları izlemesi gerekir.
Lookaside istemci yük dengelemesi, yük dengeleme durumunun merkezi bir konumda depolandığı bir tekniktir. İstemciler, yük dengeleme kararları alırken kullanılacak bilgiler için merkezi konumu düzenli aralıklarla sorgular.
Daha fazla bilgi için bkz . gRPC istemci tarafı yük dengeleme.
Ara sunucu yük dengeleme
L7 (uygulama) ara sunucusu, L4 (aktarım) proxy'sinden daha yüksek bir düzeyde çalışır. L7 proxy'leri HTTP/2'i anlar. Ara sunucu, bir HTTP/2 bağlantısı üzerinden çoğullanmış gRPC çağrıları alır ve bunları birden çok arka uç uç noktasına dağıtır. Ara sunucu kullanmak, istemci tarafı yük dengelemeden daha basittir, ancak gRPC çağrılarına ek gecikme süresi ekler.
Birçok L7 proxy'leri mevcuttur. Bazı seçenekler şunlardır:
- Envoy - Popüler bir açık kaynak ara sunucusu.
- Linkerd - Kubernetes için hizmet ağı.
- YARP: Bir Başka Ters Proxy - .NET'te yazılmış bir açık kaynak proxy.
İşlemler arası iletişim
İstemci ve hizmet arasındaki gRPC çağrıları genellikle TCP yuvaları üzerinden gönderilir. TCP bir ağ üzerinden iletişim kurmak için mükemmeldir, ancak istemci ve hizmet aynı makinede olduğunda işlemler arası iletişim (IPC) daha verimlidir.
Aynı makinedeki işlemler arasında gRPC çağrıları için Unix etki alanı yuvaları veya adlandırılmış kanallar gibi bir aktarım kullanmayı göz önünde bulundurun. Daha fazla bilgi için bkz . gRPC ile işlemler arası iletişim.
Canlı pingleri tut
Etkin tutma pingleri, http/2 bağlantılarını etkin olmama dönemlerinde canlı tutmak için kullanılabilir. Bir uygulama etkinliği sürdürürken mevcut bir HTTP/2 bağlantısının hazır olması, bağlantının yeniden kurulmasından kaynaklanan gecikme olmadan ilk gRPC çağrılarının hızlı bir şekilde yapılmasını sağlar.
Canlı tutma pingleri SocketsHttpHandler üzerinde yapılandırılır.
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
});
Yukarıdaki kod, etkin olmayan süreler boyunca her 60 saniyede bir sunucuya canlı tutma pingi gönderen bir kanal yapılandırıyor. Ping, sunucunun ve kullanımdaki proxy'lerin işlem yapılmadığı için bağlantıyı kapatmamasını sağlar.
Not
Canlı tut pingleri yalnızca bağlantının canlı kalmasına yardımcı olur. Bağlantıda uzun süreli gRPC çağrıları, etkinlik olmadığı için sunucu veya ara proxyler tarafından hala sonlandırılabilir.
Akış denetimi
HTTP/2 akış denetimi, uygulamaların verilerle aşırı yüklenmesini engelleyen bir özelliktir. Akış denetimi kullanılırken:
- Her HTTP/2 bağlantısının ve isteğinin kullanılabilir bir arabellek penceresi vardır. Arabellek penceresi, uygulamanın anında alabileceği veri miktarıdır.
- Arabellek penceresi dolarsa akış kontrolü etkinleştirilir. Etkinleştirildiğinde, gönderen uygulama daha fazla veri göndermeyi duraklatır.
- Alıcı uygulama verileri işledikten sonra arabellek penceresinde boşluk kullanılabilir. Gönderen uygulama, veri göndermeye devam eder.
Akış denetimi, büyük iletileri alırken performansı olumsuz etkileyebilir. Arabellek penceresi gelen mesaj yüklerinden daha küçükse ya da istemci ile sunucu arasında gecikme varsa, veriler başlat/durdur dalgalanmaları şeklinde gönderilebilir.
Akış denetimi performans sorunları arabellek penceresi boyutu artırılarak düzeltilebilir. Kestrel içinde, bu InitialConnectionWindowSize ve InitialStreamWindowSize ile uygulama başlangıcında yapılandırılır.
builder.WebHost.ConfigureKestrel(options =>
{
var http2 = options.Limits.Http2;
http2.InitialConnectionWindowSize = 1024 * 1024 * 2; // 2 MB
http2.InitialStreamWindowSize = 1024 * 1024; // 1 MB
});
Öneriler:
- Bir gRPC hizmeti genellikle 768 KB'tan büyük iletiler alıyorsa, bu durumda Kestrel'nin varsayılan akış penceresi boyutunun yetersiz kalabileceğini göz önünde bulundurun ve bağlantı ile akış penceresi boyutunu artırmayı düşünün.
- Bağlantı penceresi boyutu her zaman akış penceresi boyutuna eşit veya bundan büyük olmalıdır. Akış, bağlantının bir parçasıdır ve gönderen her ikisiyle de sınırlıdır.
Akış denetiminin nasıl çalıştığı hakkında daha fazla bilgi için bkz. HTTP/2 Akış Denetimi (blog gönderisi).
Önemli
Pencere boyutunu artırmak Kestrel, uygulama adına daha fazla veri arabelleğe alınmasına olanak tanır Kestrel ve bu da bellek kullanımını artırır. Gereksiz büyük bir pencere boyutu yapılandırmaktan kaçının.
Akış çağrılarını düzgün bir şekilde tamamlama
Akış çağrılarını düzgün bir şekilde tamamlamayı deneyin. Çağrıların düzgün bir şekilde tamamlanması gereksiz hataları önler ve sunucuların istekler arasında iç veri yapılarını yeniden kullanmasına olanak sağlar.
İstemci ve sunucu iletileri göndermeyi bitirdiğinde ve eş tüm iletileri okuduğunda bir çağrı düzgün bir şekilde tamamlanır.
İstemci isteği akışı:
- İstemci, istek akışına ileti yazmayı bitirdi ve akışı
call.RequestStream.CompleteAsync()
ile tamamlar. - Sunucu, istek akışındaki tüm iletileri okudu. İletileri nasıl okuduğuna bağlı olarak,
requestStream.MoveNext()
döndürürfalse
veyarequestStream.ReadAllAsync()
tamamlanmıştır.
Sunucu yanıt akışı:
- Sunucu, yanıt akışına mesaj yazmayı bitirdi ve sunucu metodu sona erdi.
- İstemci, yanıt akışındaki tüm iletileri okudu. İletileri nasıl okuduğunuza bağlı olarak, ya
call.ResponseStream.MoveNext()
öğesifalse
döndürür ya dacall.ResponseStream.ReadAllAsync()
öğesi tamamlanmıştır.
Çift yönlü akış çağrısını düzgün bir şekilde tamamlama örneği olarak, bkz çift yönlü akış çağrısı yapma.
Sunucu üzerinden yapılan akış çağrılarında istek akışı bulunmaz. Bu, bir istemcinin sunucuyla akışın durdurulması gerektiğini iletişim kurmasının tek yolunun iptal etmek olduğu anlamına gelir. İptal edilen çağrıların ek yükü uygulamayı etkiliyorsa, sunucu akış çağrısını çift yönlü akış çağrısına değiştirmeyi göz önünde bulundurun. çift yönlü akış çağrısında istek akışını tamamlayan istemci, çağrıyı sonlandırmak için sunucuya bir sinyal olabilir.
Akış çağrılarını at
Artık gerekli olmadığında akış çağrılarını her zaman atabilirsiniz. Başlatılan akış çağrıları tarafından döndürülen tür, IDisposable
'yi uygular. Artık gerekli olmadığında bir çağrının sonlandırılması, çağrının durmasını ve tüm kaynakların temizlenmesini sağlar.
Aşağıdaki örnekte, using bildirimi çağrıda beklenmeyen bir hata oluşursa her zaman bertaraf edilmesini sağlar.
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
İdeal olarak akış çağrıları düzgün bir şekilde tamamlanmalıdır. Çağrının atılması, beklenmeyen bir hata oluşursa istemci ile sunucu arasındaki HTTP isteğinin iptal edilmesini sağlar. Yanlışlıkla açık kalan akış çağrıları sadece istemcideki bellek ve kaynak sızıntısına neden olmaz, aynı zamanda sunucuda da çalışmaya devam eder. Sızan birçok akış çağrısı uygulamanın kararlılığını etkileyebilir.
Zaten düzgün bir şekilde tamamlanmış bir akış çağrısının atılması olumsuz bir etkiye neden olmaz.
Tekil çağrıları akışa dönüştürme
gRPC çift yönlü akış, yüksek performanslı senaryolarda tek yönlü gRPC çağrılarının yerine kullanılabilir. Çift yönlü akış başladıktan sonra iletilerin ileri geri akışı, birden çok tek gRPC çağrısıyla ileti göndermekten daha hızlıdır. Akışlı iletiler mevcut bir HTTP/2 isteğinde veri olarak gönderilir ve her bir çağrı için yeni bir HTTP/2 isteği oluşturma yükünü ortadan kaldırır.
Örnek hizmet:
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);
}
}
Örnek müşteri
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}");
}
Performans nedeniyle tekli çağrıları çift yönlü akışa geçiş yapmak gelişmiş bir tekniktir ve birçok durumda uygun değildir.
Aşağıdaki durumlarda akış çağrılarını kullanmak iyi bir seçimdir:
- Yüksek aktarım hızı veya düşük gecikme süresi gereklidir.
- gRPC ve HTTP/2 performans sorunu olarak tanımlanır.
- İstemcideki bir çalışan gRPC hizmetiyle normal iletiler gönderiyor veya alıyor.
Unary yerine streaming çağrılarının getirdiği ek karmaşıklık ve sınırlamalara dikkat edin.
- Akış, bir hizmet veya bağlantı hatasıyla kesilebilir. Bir hata varsa akışı yeniden başlatmak için mantık gereklidir.
-
RequestStream.WriteAsync
çoklu iş parçacığı için güvenli değildir. Bir akışa aynı anda yalnızca bir ileti yazılabilir. Birden çok iş parçacığından tek bir akış üzerinden ileti göndermek için, iletileri düzenlemek üzere Channel<T> gibi bir üretici/tüketici kuyruğuna ihtiyaç vardır. - gRPC akış yöntemi, bir ileti türü alma ve bir ileti türü gönderme ile sınırlıdır. Örneğin,
rpc StreamingCall(stream RequestMessage) returns (stream ResponseMessage)
alırRequestMessage
ve gönderirResponseMessage
. Protobuf'un,Any
veoneof
kullanarak bilinmeyen veya koşullu iletileri desteklemesi, bu sınırlamanın üstesinden gelebilir.
İkili yükler
Protobuf'ta skaler değer türüyle ikili yükler desteklenir. C# dilinde oluşturulan bir özellik, özellik türü olarak kullanır ByteString
.
syntax = "proto3";
message PayloadResponse {
bytes data = 1;
}
Protobuf, büyük ikili yükleri minimum ek yükle verimli bir şekilde seri hale getiren bir ikili biçimdir. JSON gibi metin tabanlı biçimler base64 için kodlama baytları gerektirir ve ileti boyutuna %33 ekler.
Büyük ByteString
yüklerle çalışırken, aşağıda açıklanan gereksiz kopyaları ve ayırmaları önlemeye yönelik bazı en iyi yöntemler vardır.
İkili veri yükü gönderme
ByteString
örnekleri normalde kullanılarak ByteString.CopyFrom(byte[] data)
oluşturulur. Bu yöntem, yeni bir ByteString
ve yeni bir byte[]
ayırır. Veriler yeni bayt dizisine kopyalanır.
UnsafeByteOperations.UnsafeWrap(ReadOnlyMemory<byte> bytes)
kullanılarak ByteString
örnekleri oluşturarak ek tahsisatlar ve kopyalar önlenebilir.
var data = await File.ReadAllBytesAsync(path);
var payload = new PayloadResponse();
payload.Data = UnsafeByteOperations.UnsafeWrap(data);
Baytlar, UnsafeByteOperations.UnsafeWrap
ile kopyalanmaz, bu yüzden ByteString
kullanımdayken değiştirilmemelidir.
UnsafeByteOperations.UnsafeWrap
Google.Protobuf sürüm 3.15.0 veya üzerini gerektirir.
İkili yükleri oku
ByteString.Memory
ve ByteString.Span
özellikleri kullanılarak ByteString
örneklerinden veriler verimli bir şekilde okunabilir.
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]);
}
Bu özellikler, kodun ayırmalar veya kopyalar olmadan doğrudan bir ByteString
veri okumasına olanak sağlar.
Çoğu .NET API'sinde ReadOnlyMemory<byte>
ve byte[]
aşırı yüklemeleri vardır, bu nedenle ByteString.Memory
temel alınan verileri kullanmanın önerilen yoludur. Ancak, bir uygulamanın verileri bayt dizisi olarak alması gerekebilecek durumlar vardır. Bayt dizisi gerekiyorsa MemoryMarshal.TryGetArray yöntemi, verilerin yeni bir kopyasını ayırmadan bir ByteString
diziden dizi almak için kullanılabilir.
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;
Yukarıdaki kod:
-
ByteString.Memory
'den MemoryMarshal.TryGetArray ile bir dizi almaya çalışır. - Başarıyla alındıysa
ArraySegment<byte>
kullanır. Segment, dizi, kaydırma ve adet için bir referans içerir. - Aksi takdirde,
ByteString.ToByteArray()
ile yeni bir dizi tahsis etmeye geri döner.
gRPC hizmetleri ve büyük ikili veri yükleri
gRPC ve Protobuf büyük ikili yük gönderip alabilir. İkili Protobuf, ikili yükleri seri hale getirmede metin tabanlı JSON'dan daha verimli olsa da, büyük ikili yüklerle çalışırken göz önünde bulundurulması gereken önemli performans özellikleri vardır.
gRPC, ileti tabanlı bir RPC çerçevesidir, yani:
- gRPC göndermeden önce iletinin tamamı belleğe yüklenir.
- İleti alındığında, iletinin tamamı bellekte seri durumdan çıkarılır.
İkili yükler bayt dizisi olarak tahsis edilir. Örneğin, 10 MB ikili yük, 10 MB bayt dizisi tahsis eder. Büyük ikili yükleri olan iletiler büyük nesne yığınında bayt dizileri ayırabilir. Büyük ayırmalar sunucu performansını ve ölçeklenebilirliğini etkiler.
Büyük ikili yüklerle yüksek performanslı uygulamalar oluşturmaya yönelik öneriler:
- gRPC iletilerinde büyük ikili yüklerden kaçının . 85.000 bayttan büyük bir bayt dizisi büyük bir nesne olarak kabul edilir. Bu boyutun altında tutmak, büyük nesne yığınına ayırmayı önler.
- gRPC akışını kullanarak büyük ikili yükleri bölmeyi göz önünde bulundurun. İkili veriler öbeklenir ve birden çok ileti üzerinden akışla iletilir. Dosyaların akışını yapma hakkında daha fazla bilgi için grpc-dotnet deposundaki örneklere bakın:
- Büyük ikili veriler için gRPC kullanmamayı göz önünde bulundurun . ASP.NET Core'da Web API'leri gRPC hizmetleriyle birlikte kullanılabilir. HTTP uç noktası istek ve yanıt akışı gövdesine doğrudan erişebilir:
ASP.NET Core