Хотя этот вопрос помечен как EventMachine, мы также приветствуем общие решения для сокетов BSD на любом языке.


Немного предыстории:

У меня есть приложение, которое прослушивает TCP-сокет. Он запускается и завершается с помощью обычного сценария инициализации в стиле System V.

Моя проблема в том, что ему нужно некоторое время для запуска, прежде чем он будет готов обслуживать сокет TCP. Это не слишком долго, возможно, всего 5 секунд, но это на 5 секунд больше, если перезапуск необходимо выполнить в течение рабочего дня. Также важно, чтобы существующие соединения оставались открытыми и завершались нормально.

Причины перезапуска приложения - исправления, обновления и тому подобное. К сожалению, я оказываюсь в положении, когда время от времени мне приходится делать такие вещи в продакшене.


Вопрос:

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

Есть ли какой-нибудь проверенный способ сделать это с помощью BSD-сокетов? (Бонусные баллы за решение EventMachine.)

Возможно, существуют библиотеки с открытым исходным кодом, реализующие это, которые я могу использовать как есть или использовать в качестве справочника? (Опять же, приветствуются и решения, не связанные с Ruby и EventMachine!)

8
Stéphan Kochen 5 Фев 2010 в 14:52
Если вы используете сокеты в простом стиле и запуск занимает 5 секунд, вы делаете что-то не так. Время между возвратом accept () и доступностью данных в сокете бесконечно мало.
 – 
KevinDTimm
5 Фев 2010 в 14:57
Нет-нет, это просто мое приложение делает другое разное. запускать. Настройка ActiveRecord для ORM, выполнение некоторых начальных запросов и т. Д. Я знаю, что вызовы простых сокетов выполняются быстро, поэтому я хотел бы использовать их для быстрой передачи, когда мое приложение будет готово.
 – 
Stéphan Kochen
5 Фев 2010 в 15:06

2 ответа

Лучший ответ

Есть несколько способов сделать это без простоев, с соответствующими изменениями в серверной программе.

Один из них - реализовать возможность перезапуска на самом сервере, например, при получении определенного сигнала или другого сообщения. Затем программа выполнит свою новую версию, передав ей номер файлового дескриптора прослушивающего сокета, например. как аргумент. У этого сокета должен быть снят флажок FD_CLOEXEC ( значение по умолчанию), чтобы он был унаследован. Поскольку другие сокеты будут продолжать обслуживаться исходным процессом и не должны передаваться новому процессу, флаг должен быть установлен на них, например. используя fcntl(). После разветвления и выполнения нового процесса исходный процесс может продолжить и закрыть прослушивающий сокет без какого-либо прерывания службы, поскольку новый процесс теперь прослушивает этот сокет.

Альтернативный метод, если вы не хотите, чтобы старому серверу приходилось разветвлять и запускать сам новый сервер, было бы использование сокет домена Unix для связи между старым и новым серверным процессом. При запуске новый серверный процесс может проверять наличие такого сокета в хорошо известном месте файловой системы. Если присутствует, новый сервер подключится к этому сокету и запросит, чтобы старый сервер передал свой слушающий сокет в качестве вспомогательных данных с помощью SCM_RIGHTS. Пример этого приведен в конце cmsg. (3).

8
mark4o 5 Фев 2010 в 19:57
Уловка SCM_RIGHTS звучит аккуратно. Я попробую завтра.
 – 
Stéphan Kochen
6 Фев 2010 в 02:38
1
Для справки, Ruby представляет это как UNIXSocket#send_io. Он отправляет единственный файловый дескриптор и нулевой байт. По-видимому, другого пути нет, и получение класса UNIXSocket из EventMachine также невозможно. (Возможно, я взломаю это.) Таким образом, в EventMachine это можно сделать с помощью ручной магии сокетов и EventMachine::watch. Спасибо за указатель.
 – 
Stéphan Kochen
8 Фев 2010 в 14:26

Жан-Поль Кальдероне написал подробную презентацию в 2004 году о комплексном решении вашей проблемы с использованием Twisted, включая миграцию сокетов и другие проблемы.

1
Glyph 29 Май 2010 в 18:03