У меня есть сервис, который передает сообщения с довольно высокой скоростью.
В настоящее время он обслуживается akka-tcp и составляет 3,5 миллиона сообщений в минуту. Я решил попробовать grpc. К сожалению, это привело к гораздо меньшей пропускной способности: ~ 500 тыс. Сообщений в минуту и даже меньше.
Не могли бы вы порекомендовать, как его оптимизировать?
Моя настройка
Аппаратное обеспечение : 32 ядра, куча 24 Гб.
версия grpc: 1.25.0
Формат сообщения и конечная точка
Сообщение в основном двоичный двоичный объект. Клиент направляет 100K - 1M и более сообщений в один и тот же запрос (асинхронно), сервер не отвечает ни на что, клиент использует неоперативный наблюдатель
service MyService {
rpc send (stream MyMessage) returns (stream DummyResponse);
}
message MyMessage {
int64 someField = 1;
bytes payload = 2; //not huge
}
message DummyResponse {
}
Проблемы: Скорость передачи сообщений низкая по сравнению с реализацией akka. Я наблюдаю низкую загрузку процессора, поэтому я подозреваю, что вызов grpc фактически блокируется внутри, несмотря на то, что он говорит об обратном. призваниеonNext()
действительно не сразу возвращается, но на столе также есть GC.
Я пытался породить больше отправителей, чтобы смягчить эту проблему, но не получил большого улучшения.
Мои выводы Grpc фактически выделяет 8-килобайтный буфер байтов для каждого сообщения при его сериализации. Смотрите трассировку стека:
java.lang.Thread.State: BLOCKED (на мониторе объекта) на com.google.common.io.ByteStreams.createBuffer (ByteStreams.java:58) на com.google.common.io.ByteStreams.copy (ByteStreams.java: 105) в io.grpc.internal.MessageFramer.writeToOutputStream (MessageFramer.java:274) в io.grpc.internal.MessageFramer.writeKnownLengthUncompressed (MessageFramer.java:230) в io.grpc.internal.javaFramerFramer.wmer.Fmer : 168) в io.grpc.internal.MessageFramer.writePayload (MessageFramer.java:141) в io.grpc.internal.AbstractStream.writeMessage (AbstractStream.java:53) в io.grpc.internal.ForwardingClientStream.writeMessageStreaming. Forward. Java: 37) в io.grpc.internal.DelayedStream.writeMessage (DelayedStream.java:252) в io.grpc.internal.ClientCallImpl.sendMessageInternal (ClientCallImpl.java:473) по адресу io.grpc.internal.ClientCallImpl.sendMessage (ClientCallImpl.java:457) по адресу io.grpc.ForwardingClientCall.sendMessage (ForwardingClioCall.Force.IcCent.dll) (ForwardingClientCall.java:37) в io.grpc.stub.ClientCalls $ CallToStreamObserverAdapter.onNext (ClientCalls.java:346)
Любая помощь с лучшими практиками по созданию высокопроизводительных клиентов GRPC приветствуется.
scalapb
. Вероятно, эта трассировка стека действительно была от сгенерированного скальпом кода. Я удалил все, что связано с scalapb, но это не сильно повлияло на производительность.