Мы замечаем проблемы с производительностью при попытке использовать вызов API двунаправленного потока для потоковой передачи данных со скоростью 2000–4000 обновлений в секунду. Мы включили ведение журнала отладки и видим, что идентификатор потока одинаков для всех исходящих и входящих сообщений.
Вопрос. Использует ли один вызов двунаправленной потоковой передачи RPC только один поток для отправки данных с клиента или с сервера? Если да, означает ли это, что 2000–4000 обновлений будут передаваться последовательно, а не одновременно?
Что мы пробовали:
Мы используем один двунаправленный поток RPC-вызова для публикации обновлений со скоростью 2000–4000 обновлений в секунду.
Чего мы не ожидали:
Проблемы с задержкой (~ 50 мс), даже если клиент и сервер работали на одном хосте.
Сообщения, отправляемые в потоке, образуют последовательность и упорядочены. Из Основные понятия gRPC:
Двунаправленные потоковые RPC, в которых обе стороны отправляют последовательность сообщений, используя поток чтения и записи. ... Порядок сообщений в каждом потоке сохраняется.
Потоки двунаправленного текста реализованы с использованием одного потока HTTP/2, который необходим для связи между одним клиентом и сервером.
Мало того, что потоки двунаправленного текста передаются последовательно по сети, обратные вызовы grpc-java в приложении ограничены одним потоком для этого потока. Это гарантирует упорядоченную доставку и предотвращает необходимость потокобезопасности вашего обратного вызова.
потоковые данные со скоростью 2000-4000 обновлений в секунду
Текущие тесты gRPC, в частности «Потоковая передача безопасной пропускной способности QPS (8-ядерный клиент на 8-ядерный сервер)», показывают, что gRPC Java может осуществлять потоковую передачу со скоростью 600 км/с с использованием TLS между отдельными хостами. Однако эти сообщения невелики. Размер сообщения может повлиять на видимую производительность, а обработка вашего приложения определенно повлияет на доступную производительность.
Проблемы с задержкой (~ 50 мс), даже если клиент и сервер работали на одном хосте.
Тест «Средняя задержка безопасной потоковой передачи в пинг-понге» показывает задержку около 125 мкс для незагруженного потока. 50 мс — это достаточно много, поэтому на самом деле это может быть только потому, что поток перегружен, особенно если вы не наблюдаете за управлением потоком (ServerCallStreamObserver
и ClientCallStreamObserver.isReady()
), вызывающим длинную очередь, или из-за обработки приложения.
Судя по grpc.io/docs/guides/benchmarking/#scenarios-under-test, я думаю, что это 2*64 канала/потока. Это дает производительность на поток, близкую к той, которую вы видите, но, вероятно, лучше сравнивать производительность на ядро, а у него было 8 ядер. Это 75 км/с.
В grpc-java есть простой тест JMH TransportBenchmark.streamingCallsMessageThroughput. Обычно он использует 10 потоков на одном локальном хосте, текстовый канал. Я модифицировал его, чтобы использовать один поток и видеть на своем рабочем столе скорость 95 км/с.
хорошо. Мы планируем увеличить количество нет. каналов, используемых нашим grpc-клиентом для повышения производительности путем параллельной потоковой передачи обновлений по нескольким каналам, а на другом конце мы передадим сообщение, полученное в обратном вызове grpc, в пул потоков приложения для обработки.
Обновление: мы пробовали использовать несколько каналов на стороне клиента и на стороне сервера, мы обрабатывали обновления, используя пул потоков (чтобы не блокировать поток grpc). Мы видим значительное улучшение пропускной способности. Спасибо за ваш вклад, Эрик
Ценю ваш ответ, Эрик. Использует ли тест один канал или несколько каналов?