Мне нужны рекомендации по увеличению пропускной способности и минимизации задержки для унарных вызовов gRPC. Мне нужно добиться около 20 000 QPS, ‹50 мс каждое. На умеренном оборудовании (4-ядерный ЦП) я смог достичь только около 15 000 запросов в секунду при средней задержке 200 мс. Я использую клиент и сервер Java. Сервер ничего не делает, кроме как возвращает ответ. Клиент отправляет несколько одновременных запросов, используя асинхронную заглушку. Количество одновременных запросов ограничено. ЦП остается в диапазоне ~ 80%. Для сравнения, используя Apache Kafka, я могу достичь гораздо более высокой пропускной способности (100 тысяч запросов в секунду), а также задержки в диапазоне 10 мс.
Рекомендации по унарным вызовам с высокой пропускной способностью и малой задержкой в gRPC
Ответы (1)
Если вы используете grpc-java 1.21 или новее и grpc-netty-shaded
, вы уже должны использовать транспорт Netty Epoll. Если вы используете grpc-netty
, добавьте зависимость времени выполнения от io.netty:netty-transport-native-epoll
(правильную версию можно найти, просмотрев файл pom.xml grpc-netty
или таблица версий в SECURITY.md).
Исполнителем по умолчанию для обратных вызовов является «кэшированный пул потоков». Если вы не блокируете (или знаете пределы блокировки), указание пула потоков фиксированного размера может повысить производительность. Вы можете попробовать как Executors.newFixedThreadPool
, так и ForkJoinPool
; мы видели, что «оптимальный» выбор варьируется в зависимости от рабочей нагрузки. Вы указываете собственного исполнителя через ServerBuilder.executor()
и ManagedChannelBuilder.executor()
.
Если у вас высокая пропускная способность (~ Гбит / с + на клиента с TLS; выше, если используется открытый текст), использование нескольких каналов может повысить производительность за счет использования нескольких соединений TCP. Каждое TCP-соединение закреплено за потоком, поэтому наличие большего количества TCP-соединений позволяет использовать больше потоков. Вы можете создать несколько каналов, а затем выполнять циклический переход по ним; выбор другого для каждого RPC. Обратите внимание, что вы можете легко реализовать интерфейс Channel
, чтобы «скрыть» эту сложность от остальной части вашего приложения. Похоже, что это даст вам именно большой выигрыш, но я ставлю это последним, потому что обычно в этом нет необходимости.