Задержка сокета Java TCP / IP - застрял на 50 мкс (микросекунд)?(используется для Java IPC) - PullRequest
10 голосов
/ 10 мая 2011

Мы профилировали и профилировали наше приложение, чтобы максимально снизить время ожидания. Наше приложение состоит из 3 отдельных процессов Java, все они выполняются на одном сервере и передают сообщения друг другу через сокеты TCP / IP.

Мы сократили время обработки в первом компоненте до 25 мкс, но мы видим, что запись сокета TCP / IP (на локальном хосте) в следующий компонент неизменно занимает около 50 мкс. Мы видим еще одно аномальное поведение в том, что компонент, который принимает соединение, может записывать быстрее (т. Е. <50 мкс). В настоящий момент все компоненты работают <100 мкс, за исключением связи через сокеты. </p>

Не будучи экспертом по TCP / IP, я не знаю, что можно сделать, чтобы ускорить это. Будут ли доменные сокеты Unix быстрее? MemoryMappedFiles? Какие другие механизмы могли бы быть более быстрым способом передачи данных из одного Java-процесса в другой?

ОБНОВЛЕНИЕ 21.06.2011 Мы создали 2 эталонных приложения, одно на Java и одно на C ++, для более точного сравнения TCP / IP и сравнения. Приложение Java использовало NIO (режим блокировки), а C ++ использовало библиотеку Boost ASIO tcp. Результаты были более или менее эквивалентны: приложение C ++ примерно на 4 мкс быстрее, чем Java (но в одном из тестов Java опередил C ++). Кроме того, обе версии показали большую изменчивость во времени на сообщение.

Я думаю, что мы согласны с основным выводом, что реализация с разделяемой памятью будет самой быстрой. (Хотя мы также хотели бы оценить продукт Informatica, если он соответствует бюджету.)

Ответы [ 5 ]

4 голосов
/ 10 мая 2011

Если использовать нативные библиотеки через JNI , это вариант, я бы рассмотрел реализацию IPC как обычно (поиск IPC, mmap, shm_open и т. Д.).

Существует много накладных расходов, связанных с использованием JNI, но, по крайней мере, это немного меньше, чем полные системные вызовы, необходимые для выполнения чего-либо с сокетами или каналами. Скорее всего, вы сможете сократить одностороннюю задержку до 3 микросекунд, используя реализацию IPC с общей памятью через JNI. (Обязательно используйте опцию -Xcomp JVM или настройте порог компиляции тоже; в противном случае ваши первые 10000 семплов будут ужасны. Это имеет большое значение.)

Я немного удивлен, что запись в сокет TCP занимает 50 микросекунд - большинство операционных систем в некоторой степени оптимизируют петлю TCP. Солярис на самом деле неплохо справляется с этим с помощью функции TCP Fusion . И если в была какая-либо оптимизация для обратной связи вообще, это обычно было для TCP. UDP имеет тенденцию пренебрегать - поэтому я бы не стал беспокоиться об этом в этом случае. Я также не стал бы беспокоиться о каналах (stdin / stdout или ваших собственных именованных каналах и т. Д.), Потому что они будут еще медленнее.

И, как правило, большая задержка, которую вы видите, связана с передачей сигналов - либо ожиданием селектора ввода-вывода, такого как select () в случае сокетов, либо ожиданием семафора, либо ожиданием чего-либо. Если вы хотите наименьшую возможную задержку, вам придется сжечь ядро ​​в тесном цикле опроса новых данных.

Конечно, всегда есть коммерческий готовый маршрут - который, как я знаю, наверняка решит вашу проблему в спешке - но, конечно, он стоит денег. И в интересах полного раскрытия информации: я работаю для Informatica над их программным обеспечением для обмена сообщениями с низкой задержкой. (И мое честное мнение, как инженера, это то, что это довольно фантастическое программное обеспечение - безусловно, стоит проверить этот проект.)

2 голосов
/ 26 октября 2011

«Книга О'Рейли о NIO (Java NIO, стр. 84), кажется, неопределенной остается ли отображение памяти в памяти. Может быть, это просто говорит что, как и в другой памяти, если у вас заканчивается физическое, это обменивается вернуться на диск, а иначе нет? "

Linux. mmap () вызов распределяет страницы в области кэша страниц ОС (которые периодически записываются на диск и могут быть удалены на основе Clock-PRO, который является приближением алгоритма LRU?). Итак, ответ на ваш вопрос - да. Отображенный в память буфер может быть удален (теоретически) из памяти, если он не является mlocke'd ( mlock () ). Это в теории. На практике, я думаю, что это вряд ли возможно, если ваша система не обменивается В этом случае первыми жертвами являются буферы страниц.

1 голос
/ 11 сентября 2013

Выезд https://github.com/pcdv/jocket

Это замена с малой задержкой для локальных сокетов Java, которые используют общую память.

Задержка RTT между двумя процессами значительно ниже 1us на современном процессоре.

1 голос
/ 10 октября 2011

MemoryMappedFiles вообще не является жизнеспособным решением для IPC с малой задержкой - если обновленный сегмент памяти обновляется, он в конечном итоге синхронизируется с диском, что приводит к непредсказуемой задержке, которая измеряется по крайней мере в миллисекундах. Для малой задержки можно использовать комбинации из общей памяти + очереди сообщений (уведомлений) или совместно используемой памяти + семафоров. Это работает на всех Unix, особенно на версии System V (не на POSIX), но если вы запускаете приложение в Linux, вы довольно безопасно используете POSIX IPC (большинство функций доступно в ядре 2.6). Да, для этого вам понадобится JNI.

UPD: я забыл, что это JVM - JVM IPC, и у нас уже есть GC, которые мы не можем полностью контролировать, поэтому может быть допустимо добавление дополнительных нескольких мс пауз из-за буферизации файлов ОС на диске.

1 голос
/ 21 июня 2011

См. Мой ответ на самый быстрый (низкая задержка) метод для межпроцессного взаимодействия между Java и C / C ++ - с отображенными в память файлами (разделяемая память) задержка java-to-java может быть уменьшена до 0,3 микросекунды

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...