Saya memiliki layanan yang mentransfer pesan pada tingkat yang cukup tinggi.
Saat ini dilayani oleh akka-tcp dan menghasilkan 3,5 juta pesan per menit. Saya memutuskan untuk mencoba grpc. Sayangnya itu menghasilkan throughput yang jauh lebih kecil: ~ 500rb pesan per menit bahkan lebih sedikit.
Bisakah Anda merekomendasikan cara mengoptimalkannya?
Pengaturan saya
Perangkat keras : 32 core, tumpukan 24Gb.
versi grpc : 1.25.0
Format pesan dan titik akhir
Pesan pada dasarnya adalah gumpalan biner. Klien melakukan stream 100K - 1M dan lebih banyak pesan ke permintaan yang sama (asinkron), server tidak menanggapi apa pun, klien menggunakan pengamat no-op
service MyService {
rpc send (stream MyMessage) returns (stream DummyResponse);
}
message MyMessage {
int64 someField = 1;
bytes payload = 2; //not huge
}
message DummyResponse {
}
Masalah: Tingkat pesan rendah dibandingkan dengan implementasi akka. Saya mengamati penggunaan CPU yang rendah jadi saya curiga bahwa panggilan grpc sebenarnya memblokir secara internal meskipun dikatakan sebaliknya. Memanggil onNext()
memang tidak segera kembali tetapi ada juga GC di atas meja.
Saya mencoba menelurkan lebih banyak pengirim untuk mengurangi masalah ini tetapi tidak mendapatkan banyak perbaikan.
Temuan saya, Grpc, sebenarnya mengalokasikan buffer byte 8KB pada setiap pesan ketika membuat serialisasi. Lihat stacktrace:
java.lang.Thread.State: BLOCKED (pada objek monitor) di com.google.common.io.ByteStreams.createBuffer (ByteStreams.java:58) di com.google.common.io.ByteStreams.copy (ByteStreams.java: 105) di io.grpc.internal.MessageFramer.writeToOutputStream (MessageFramer.java:74) di io.grpc.internal.MessageFramer.writeKnownLengthUncompressed (MessageFramer.java.w30) di io.grpc.internal.MessageFramer.writeUnter : 168) di io.grpc.internal.MessageFramer.writePayload (MessageFramer.java:141) di io.grpc.internal.AbstrakStream.writeMessage (AbstractStream.java:53) di io.grpc.internal.ForwardingClientStream.writeMessage (ForwardingClientStream. java: 37) di io.grpc.internal.DelayedStream.writeMessage (DelayedStream.java:252) di io.grpc.internal.ClientCallImpl.sendMessageInternal (ClientCallImpl.java:473) di io.grpc.internal.ClientCallImpl.sendMessage (ClientCallImpl.java:457) di io.grpc.ForwardingClientCall.sendMessage (forwardingClient.call. (ForwardingClientCall.java:37) di io.grpc.stub.ClientCalls $ CallToStreamObserverAdapter.onNext (ClientCalls.java:346)
Setiap bantuan dengan praktik terbaik untuk membangun klien grpc throughput tinggi dihargai.
scalapb
. Mungkin stacktrace ini memang dari ke kode yang dihasilkan scalapb. Saya menghapus semua yang berhubungan dengan scalapb tetapi itu tidak membantu banyak kinerja.Jawaban:
Saya memecahkan masalah dengan membuat beberapa
ManagedChannel
instance per tujuan. Meskipun artikel mengatakan bahwaManagedChannel
dapat menelurkan cukup banyak koneksi itu sendiri sehingga satu contoh sudah cukup itu tidak benar dalam kasus saya.Performanya setara dengan implementasi akka-tcp.
sumber
Pertanyaan menarik. Paket-paket jaringan komputer dikodekan menggunakan setumpuk protokol , dan protokol tersebut dibangun di atas spesifikasi yang sebelumnya. Oleh karena itu kinerja (throughput) protokol dibatasi oleh kinerja yang digunakan untuk membangunnya, karena Anda menambahkan langkah-langkah pengkodean / dekode tambahan di atas yang mendasarinya.
Misalnya
gRPC
dibangun di atasHTTP 1.1/2
, yang merupakan protokol pada lapisan Aplikasi , atauL7
, dan karenanya kinerjanya terikat oleh kinerjaHTTP
. SekarangHTTP
itu sendiri dibangun di atasTCP
, yang pada lapisan Transport , atauL4
, jadi kita dapat menyimpulkan bahwagRPC
throughput tidak boleh lebih besar dari kode setara yang disajikan diTCP
lapisan.Dengan kata lain: jika server Anda dapat menangani
TCP
paket mentah , bagaimana menambahkan lapisan kompleksitas baru (gRPC
) akan meningkatkan kinerja?sumber
gRPC
Anda juga membayar satu kali untuk membuat koneksi, tetapi Anda telah menambahkan beban tambahan parsing protobuf. Bagaimanapun sulit untuk membuat dugaan tanpa terlalu banyak informasi, tetapi saya berani bertaruh bahwa, secara umum, karena Anda menambahkan langkah-langkah pengkodean / penguraian tambahan dalam pipa Anda,gRPC
implementasinya akan lebih lambat daripada soket web yang setara.Saya cukup terkesan dengan seberapa baik Akka TCP telah dilakukan di sini: D
Pengalaman kami sedikit berbeda. Kami sedang mengerjakan contoh yang jauh lebih kecil menggunakan Akka Cluster. Untuk remoting Akka, kami mengubah dari Akka TCP ke UDP menggunakan Artery dan mencapai tingkat respons yang jauh lebih tinggi + lebih rendah dan lebih stabil. Bahkan ada konfigurasi di Artery yang membantu menyeimbangkan antara konsumsi CPU dan waktu respons dari awal yang dingin.
Saran saya adalah menggunakan beberapa kerangka kerja berbasis UDP yang juga menjaga keandalan transmisi untuk Anda (mis. Artery UDP), dan hanya membuat serial menggunakan Protobuf, alih-alih menggunakan gRPC daging lengkap. Saluran transmisi HTTP / 2 tidak benar-benar untuk keperluan waktu respons rendah throughput tinggi.
sumber