Как избежать ограничения реактора Boost ASIO одной активной зоной?

TL; DR: Возможно ли, что производительность моего реактора ограничена? Как мне сказать? Насколько дорого и масштабируемо (по потокам) реализация io_service?

У меня есть сильно параллельное приложение, работающее на гиперпоточном, двухъядерном четырехъядерном компьютере Xeon с тоннами ОЗУ и быстрым SSD RAID. Это разработано с использованием boost :: asio.

Это приложение принимает соединения примерно с 1000 других машин, считывает данные, декодирует простой протокол и перетасовывает данные в файлы, отображаемые с помощью mmap (). Приложение также предварительно выбирает «будущие» страницы mmap с помощью madvise (WILLNEED), так что вряд ли оно будет блокировать ошибки страниц, но на всякий случай я попытался создать до 300 потоков.

Это работает в Linux. ядро 2.6.32-27-generic (Ubuntu Server x64 LTS 10.04). Версия Gcc - 4.4.3, а версия boost :: asio - 1.40 (обе являются стандартным Ubuntu LTS).

Запустив vmstat, iostat и top, я вижу, что пропускная способность диска (как в TPS, так и в объеме данных) выражена однозначными числами. %. Точно так же длина дисковой очереди всегда намного меньше, чем количество потоков, поэтому я не думаю, что я привязан к вводу-выводу. Кроме того, RSS увеличивается, но затем стабилизируется на нескольких гигах (как и ожидалось), а vmstat не показывает разбиение на страницы, поэтому я полагаю, что я не привязан к памяти. ЦП постоянно на 0–1% пользователей, 6–7% на системе, а остальные - в режиме ожидания. Ключ к разгадке! Одно полное «ядро» (помните, гиперпоточность) составляет 6,25% от ЦП.

Я знаю, что система отстает, потому что клиентские машины блокируют TCP-отправку, когда невыполнено более 64 КБ, и сообщают об этом; все они продолжают сообщать об этом факте, и пропускная способность системы намного меньше, чем хотелось бы, предполагалось и теоретически возможно.

Я предполагаю, что я борюсь за какую-то блокировку. Я использую блокировку на уровне приложения для защиты таблицы поиска, которая может быть видоизменена, поэтому я разделил ее на 256 блокировок / таблиц верхнего уровня, чтобы сломать эту зависимость. Однако это, похоже, совсем не помогло.

Все потоки проходят через один глобальный экземпляр io_service. Запуск strace в приложении показывает, что большую часть времени оно тратит на вызовы futex, которые, как я полагаю, связаны с реализацией реактора io_service на основе событий.

Возможно ли, что у меня ограничена пропускная способность реактора? Как мне сказать? Насколько затратна и масштабируема (по потокам) реализация io_service?

РЕДАКТИРОВАТЬ: Я изначально не нашел этот другой поток, потому что он использовал набор тегов, которые не перекрывали мой: - / Вполне возможно, что мой Проблема заключается в чрезмерной блокировке, используемой при реализации реактора boost :: asio. См. Сервер сокетов C ++ - Невозможно загрузить ЦП Однако остается вопрос: как я могу это доказать? И как это исправить?

7
задан Community 23 May 2017 в 11:51
поделиться