В этой статье мы поговорим о текущих рабочих процессах, реализованных в Manticore Search, и о том, как настроить параметры рабочих процессов.
В Manticore Search в настоящее время есть два режима многопроцессорной обработки, управляемых директивой workers . По умолчанию MPM в настоящее время - это thread_pool, с альтернативой threads.
Потоки
В режиме многопроцессорной обработки ' threads ' создается новый выделенный поток для каждого входящего сетевого соединения. Поток активен до тех пор, пока клиент не отключится - то есть, пока соединение активно. В это время поток будет выполнять входящие запросы из соединения.
По умолчанию движок будет создавать неограниченное количество потоков - если это позволяет операционная система. Хотя это может выглядеть хорошо, на самом деле разрешение создания неограниченного количества потоков имеет свои издержки. Во-первых, создание/уничтожение потока имеет затраты на ЦП. Хотя это низко по сравнению с форками, это все же существует.
Создание сотен или тысяч потоков в секунду может повлиять на производительность системы, в зависимости от доступных ядер ЦП. Наличие гораздо большего количества потоков, чем доступных ядер, приводит к тому, что эти потоки борются за ресурсы - одно из которых - это ядра ЦП, второе может быть хранилище.
Например, если у нас есть система с 16 ядрами, но мы позволяем создать 160 потоков поиска, это означает 10 потоков на ядро ЦП. Потоки не будут работать одновременно, но будут ждать в очереди, чтобы ядро ЦП выделило циклы для них. С точки зрения хранилища, у нас может быть 160 потенциальных запросчиков на чтение данных из него. Если хранилище не может продолжать обслуживать потоки без задержек (латентности), задержки могут повлиять на выделение ядер ЦП, так как поток может получить зеленый свет для выполнения своих вычислений на ядре ЦП, но должен ждать данные.
max_children настройка позволяет установить лимит на то, сколько потоков может быть активно одновременно. Когда лимит достигнут, движок начнет отклонять входящие соединения с ошибкой 'maxed out'. При установке max_children необходимо помнить, что поток убивается, когда клиент закрывает соединение. Если соединение бездействует, поток останется активным и будет учитываться в max_children. max_children можно увеличить до предела, который зависит от возможностей сервера обрабатывать количество активных запросов. Это включает в себя вычислительные возможности (ЦП) и операции ввода-вывода (хранилище). Частой ошибкой является увеличение max_children до очень высоких значений. Существует момент, в зависимости от возможностей системы, когда создание слишком большого количества потоков приводит только к замедлению запросов. Если нет ничего больше в плане оптимизации индексов и запросов, следует рассмотреть возможность создания нового сервера поиска для распределения нагрузки.
Thread_pool
В предыдущем разделе мы говорили о том, что потоки имеют свои издержки и что соединения могут поддерживать потоки активными, даже если они не используются.
Другой стратегией управления потоками является не создание потока на каждое соединение, а использование пула потоков для обработки работы. В этом случае рабочие потоки не связаны с входящими соединениями, так как соединения обрабатываются другим классом потоков. Когда демон запускается, он создает определенное количество потоков. Входящие сетевые соединения обрабатываются так называемыми сетевыми потоками, их задача - получать запросы из соединений и направлять их в потоки пула.
Если пул слишком занят (все рабочие обрабатывают запросы), новые запросы отправляются в ожидающую очередь. Сервер будет 'max out', если ожидающая очередь заполнится. По умолчанию лимит не установлен, однако слишком долгое добавление в очередь ничего не дает, кроме получения запросов, которые требуют много времени. Хорошей идеей является установка лимита на очередь, чтобы сигнализировать, что сервер получает больше запросов, чем может обработать. Это можно установить с помощью директивы queue_max_length . По сравнению с max_children в модели потоков, где maxing out начинается после определенного количества открытых соединений, в случае thread_pool демон начнет 'max out', когда активные запросы превышают max_children (количество потоков в пуле) + queue_max_length.
В случае thread_pool директива max_children определяет количество потоков в пуле, которые создаются при запуске демона. По умолчанию используется значение 1.5x от количества ядер ЦП. Установка max_children на высокие значения не увеличит производительность или емкость сервера. Поскольку эти потоки просто обрабатывают, им необходимо получить доступ к ЦП как можно скорее.
Установка высоких значений приведет, как и в предыдущем разделе, к конкуренции за ЦП и более медленной производительности, а также к более медленному запуску демона. По сравнению с режимом потоков, где max_children может быть установлен в несколько раз больше количества ядер ЦП и значения в несколько сотен могут иметь смысл, в случае thread_pool имеет мало смысла увеличивать количество в 2-3 раза от количества ядер.
По умолчанию для обработки сетевых соединений используется один выделенный поток. Работа потока, как правило, проста, так как он только выступает в качестве прокси для thread_pool и, как правило, может выдерживать хорошее количество трафика. Количество сетевых потоков можно увеличить с помощью net_workers директивы. Увеличение сетевых потоков показало прирост для настроек с экстремальными значениями запросов в секунду.
Сетевой поток(и) также имеют несколько настроек тонкой настройки. Сетевой поток может не всегда быть загружен, так как могут быть моменты (в субсекундных терминах), когда он не получает запросы. Поток будет засыпать и терять приоритет к ЦП. Время, затраченное на пробуждение или возвращение на место в ЦП, невелико, но для высокопроизводительных систем каждая миллисекунда имеет значение.
Чтобы преодолеть это, можно активировать занятый цикл с помощью net_wait_tm директивы. Если значение net_wait_tm положительное, поток будет 'тикать' ЦП каждые 10*net_wait_tm (где значение net_wait_tm представляет миллисекунды). Если net_wait_tm равно нулю, занятый цикл работает непрерывно - следует отметить, что это приведет к дополнительному использованию ЦП, даже если сетевой поток не получает много трафика. Чтобы отключить занятый цикл, следует использовать отрицательное значение -1. По умолчанию net_wait_tm имеет значение 1, что означает, что занятый цикл тикает каждые 10 мс.
Сетевой поток также может быть ограничен. Опция net_throttle_accept устанавливает лимит на то, сколько клиентов сетевой поток может принять одновременно, а net_throttle_action уточняет, сколько запросов обрабатывать за итерацию. По умолчанию лимит не устанавливается. Ограничение сетевого потока имеет смысл в случаях высокой нагрузки.
Аспект, который часто неправильно понимается, это связь между max_children и dist_threads . dist_threads отвечает за многопоточность некоторых операций, таких как локальный распределенный индекс, фрагменты с load_files или команду CALL PQ . Однако это подсистемные потоки, и они не учитываются в директиве max_children , которая учитывает только основные потоки запросов.