Eu tenho um serviço que transfere mensagens a uma taxa bastante alta.
Atualmente, é atendido pelo akka-tcp e gera 3,5 milhões de mensagens por minuto. Decidi experimentar o grpc. Infelizmente, resultou em uma taxa de transferência muito menor: ~ 500 mil mensagens por minuto e até menos.
Você poderia recomendar como otimizá-lo?
Minha configuração
Hardware : 32 núcleos, pilha de 24 GB.
versão grpc: 1.25.0
Formato da mensagem e ponto final
A mensagem é basicamente um blob binário. O cliente transmite de 100K a 1M e mais mensagens na mesma solicitação (de forma assíncrona), o servidor não responde com nada, o cliente usa um observador não operacional
service MyService {
rpc send (stream MyMessage) returns (stream DummyResponse);
}
message MyMessage {
int64 someField = 1;
bytes payload = 2; //not huge
}
message DummyResponse {
}
Problemas: a taxa de mensagens é baixa em comparação com a implementação do akka. Observo baixo uso da CPU e, portanto, suspeito que a chamada grpc esteja realmente bloqueando internamente, apesar de dizer o contrário. Ligar de onNext()
fato não retorna imediatamente, mas também há GC na mesa.
Tentei gerar mais remetentes para mitigar esse problema, mas não obtive muitas melhorias.
Minhas descobertas O Grpc realmente aloca um buffer de 8 KB em cada mensagem quando o serializa. Veja o stacktrace:
java.lang.Thread.State: BLOCKED (no monitor de objeto) em com.google.common.io.ByteStreams.createBuffer (ByteStreams.java:58) em com.google.common.io.ByteStreams.copy (ByteStreams.java: 105) em io.grpc.internal.MessageFramer.writeToOutputStream (MessageFramer.java:274) em io.grpc.internal.MessageFramer.writeKnownLengthUncompressed (MessageFramer.java:230) em io.grpc.internal.MessageFramer.writeUncom : 168) em io.grpc.internal.MessageFramer.writePayload (MessageFramer.java:141) em io.grpc.internal.AbstractStream.writeMessage (AbstractStream.java:53) em io.grpc.internal.ForwardingClientStream.writeMessage (ForwardingClientStream. java: 37) em io.grpc.internal.DelayedStream.writeMessage (DelayedStream.java:252) em io.grpc.internal.ClientCallImpl.sendMessageInternal (ClientCallImpl.java:473) em io.grpc.internal.ClientCallImpl.sendMessage (ClientCallImpl.java:457) em io.grpc.ForwardingClientCall.sendMessage (ForwardingClientCall.java:c.): (ForwardingClientCall.java:37) em io.grpc.stub.ClientCalls $ CallToStreamObserverAdapter.onNext (ClientCalls.java:346)
Qualquer ajuda com as melhores práticas na criação de clientes grpc de alto rendimento é apreciada.
scalapb
. Provavelmente, esse rastreamento de pilha foi realmente do código gerado pelo scalapb. Eu removi tudo relacionado ao scalapb, mas não ajudou muito no desempenho.