Подтвердить что ты не робот

Accept() с сокетами, разделяемыми между несколькими процессами (на основе предпродажа Apache)

Я работаю над некоторым кодом Python, смоделированным на сервере Prefork Apache MPM. Я больше программист приложений, чем сетевой программист, и прошло уже 10 лет с тех пор, как я прочитал "Стивенс", поэтому я стараюсь ускорить понимание кода.

Я нашел краткое описание как работает код предпродажа Apache, Sander Temme.

Родительский процесс, который обычно запускается как root, привязывается к сокету (обычно порт 80 или 443). Он порождает детей, которые наследуют открытый файловый дескриптор для сокета и изменить uid и gid на непривилегированный пользователь и группа. Дети строят опрос дескрипторов файла прослушивателя (если имеется более одного слушателя) и следите за действиями на нем/их. Если действие найдено, ребенок вызывает accept() в активном сокете и обрабатывает соединение. Когда он является с этим, он возвращается к просмотру pollset (или файла прослушивателя дескриптор).

Поскольку несколько детей активны, и все они унаследованы одинаково дескриптор файла сокета, они будут наблюдать за тем же самым опросом. Мьютекс accept позволяет только одному ребенку фактически наблюдать за опросом, и как только он найдет активный сокет, он откроет мьютекс, чтобы следующий ребенок может начать наблюдать за опросом. Если есть только один слушатель, который принимает мьютекс, не используется, и все дети будут принимаем().

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

1) В чем разница между "ребенком" и "слушателем"? Я думал, что каждый ребенок является слушателем, что верно для кода, на который я смотрю, но в описании Temme может быть "один слушатель" и "дети". Когда у ребенка будет несколько слушателей?

2) (Связано с 1) Является ли это мьютексом для каждого процесса или мьютексом системы? В этом отношении, почему есть мьютекс? Не принимает (2) делать свои собственные мьютексы для всех слушателей? Мои исследования говорят, что мне нужен мьютекс и что мьютекс должен быть через всю систему. (стадо, семафор и т.д.)

Далее Temme говорит:

Запись детей в общей памяти (табло), когда они в последний раз подал запрос. Неработающие дети могут быть убитым родительским процессом до удовлетворяют требованиям MaxSpareServers. Если слишком мало дети простаивают, родитель порождать детей, чтобы удовлетворить MinSpareServers.

3) Есть ли хороший код для этой реализации (желательно на Python)? Я нашел Perl Net:: Server:: Prefork, в котором вместо таковой используются каналы вместо общей памяти. Я нашел статью Рэндала Шварца, которая только делает предпродак, но не делает табло.

Пример pre-fork из Perl Cookbook не имеет какой-либо блокировки для выбора и Пример Python Chris Siebenmann говорит, что он основан на Apache, но использует парные сокеты для табло, а не разделяемую память, и использует сокеты для элементов управления, включая элемент управления для данного дочернего элемента 'a' ccept. Это совсем не совпадает с описанием Apache.

4b9b3361

Ответ 1

В отношении (1) слушатель является просто ссылкой на существование сокета, на котором можно принимать соединения. Так как Apache может одновременно принимать соединения на нескольких сокетах, например, 80/443, то есть несколько сокетов-слушателей. Каждый дочерний процесс должен будет прослушивать все эти сокеты, когда наступит его время. Поскольку accept() может выполняться только по одному гнезду за раз, ему предшествует опрос/выбор, поэтому известно, на каком гнезде слушателя должен быть выполнен прием.

В отношении (2) это глобальный или взаимный мутекс. То есть, один процесс, блокирующий его, блокирует другие процессы, пытающиеся получить один и тот же замок. Хотя accept() будет технически сериализовать процессы, наличие нескольких сокетов-слушателей означает, что вы не можете полагаться на это, так как вы не знаете, перед каким сокетом выполнить accept. Даже там, где один сокет-слушатель, причина принятия мьютекса заключается в том, что если есть большое количество процессов, обрабатывающих запросы, то это может быть довольно дорого, если операционная система просыпает все процессы, чтобы увидеть, что затем возвращает accept(). Так как Apache в режиме предпродак может иметь более 100 процессов, это может вызвать проблемы.

Итак, если у вас есть только один сокет-слушатель, и вы знаете, что у вас есть только несколько процессов, которые хотят выполнить вызов accept(), тогда вы можете покончить с перекрестным процессом accept mutex.