(Проблема, по всей видимости, чрезвычайно экзотическая, но в плане «как оно внутри устроено» достаточно познавательная.)
Вот, допустим, работает у вас приложение, написанное на Эрланге (ну, скажем, тот же ejabberd). Давно работает, хорошо работает, но в один прекрасный день вы пытаетесь запустить управляющий скрипт (ejabberdctl, соответственно), а он вам выдает «nodedown» или еще что-нибудь страшное в этом духе, мол, не отзывается никто. При этом само приложение прекрасно отзывается на все клиентские запросы и слыхом не слыхивало о том, что оно down. По внезапному наитию вы запускаете
Программы на Эрланге используют для связи между собой нотацию
Что в такой ситуации делать? Можно, конечно, просто насильно перезапустить приложение, но, с одной стороны, клиенты отвалятся, с другой, такой красивый uptime жалко… Вот если б можно было как-нибудь восстановить реестр на живой системе, а?..
Never fear! Крохи информации, откопанные в интернетах, сообщают, что
С помощью
Узел обязательно должен быть анонимным, потому что мы сейчас будем вручную регистрировать имя, а это (см. код все того же
… но, поскольку узел все же анонимный, сначала надо руками запустить ген-сервер. Теперь вызываем нашу волшебную функцию:
Теперь мы снова можем общаться с потерянным узлом. Для проверки запускаем еще раз
Так, стоп, не радуемся. Все дело в том, что, хоть
Элементарно, Ватсон (когда уже знаешь, как). Запускаем второй эмулятор, на этот раз с именем:
… и пингуем узел с приложением:
(Если получили pong, все по плану. Если получили pang, закрываем ставшую бесполезной статью и начинаем с криками бегать по комнате.)
А вот теперь фокус. Заключается он в том, что соединение между узлами, будучи установленным — что мы только что сделали — остается открытым и дальше, и для общения по нему реестр
Что мы только что сделали? Мы, помимо прочего, закрыли соединение к
Теперь по нашему открытому соединению, оставшемуся висеть под потолком без страховки, мы можем, пользуясь прекрасным модулем
И усе. Закрываем терминалы и делаем то, ради чего в самом начале вообще полезли в систему.
Вопросы, уточнения, исправления приветствуются.
Вот, допустим, работает у вас приложение, написанное на Эрланге (ну, скажем, тот же ejabberd). Давно работает, хорошо работает, но в один прекрасный день вы пытаетесь запустить управляющий скрипт (ejabberdctl, соответственно), а он вам выдает «nodedown» или еще что-нибудь страшное в этом духе, мол, не отзывается никто. При этом само приложение прекрасно отзывается на все клиентские запросы и слыхом не слыхивало о том, что оно down. По внезапному наитию вы запускаете
epmd -names
и — о, ужас! — получаете пустой список.Программы на Эрланге используют для связи между собой нотацию
node@host
, физически же каждый узел (читай — системный процесс) открывает для этого случайный высокий порт. Задача сервиса epmd
— связать между собой логическую адресацию по имени и физическую адресацию по номеру порта. Своего рода аналог DNS, с той разницей, что без реестра epmd
кластер на Эрланге разваливается на кучку отдельных глухонемых узлов — что у нас только что по какой-то загадочной причине и произошло. Можно, конечно, начать искать виновных, но сначала все-таки неплохо бы поднять систему на место.Что в такой ситуации делать? Можно, конечно, просто насильно перезапустить приложение, но, с одной стороны, клиенты отвалятся, с другой, такой красивый uptime жалко… Вот если б можно было как-нибудь восстановить реестр на живой системе, а?..
Never fear! Крохи информации, откопанные в интернетах, сообщают, что
epmd
якобы достаточно кинуть один-единственный правильный пакет; скажем, накропать быстренько программку на С… Ну, на низкий уровень нам идти совсем не обязательно, с сокетами и на самом Эрланге неплохо работается, но хотелось бы еще проще. Хочется — пожалуйста: натыкаемся на модуль erl_epmd
и видим в нем — слава открытым исходникам! — волшебную функцию register_node/2
, принимающую имя узла и номер порта.С помощью
netstat
узнаем, какой порт используется нашим приложением — пусть будет 23456 — и запускаем в терминале эмулятор:$ erl
Узел обязательно должен быть анонимным, потому что мы сейчас будем вручную регистрировать имя, а это (см. код все того же
erl_epmd
) можно сделать только один раз за запуск.> erl_epmd:start().
… но, поскольку узел все же анонимный, сначала надо руками запустить ген-сервер. Теперь вызываем нашу волшебную функцию:
> erl_epmd:register_node( ejabberd, 23456 ).
Теперь мы снова можем общаться с потерянным узлом. Для проверки запускаем еще раз
epmd -names
и радуе…Так, стоп, не радуемся. Все дело в том, что, хоть
epmd
и принимает без лишних вопросов регистрацию любого свободного имени на любой используемый эрлом порт, он также запоминает, с какого соединения пришел этот запрос на регистрацию, и как только соединение отвалится, имя опять освободится. Поэтому сейчас для корректной работы системы придется оставить запущенным никому не нужный временный эмулятор. Непорядок? Непорядок. Надо бы как-то пробраться внутрь приложения и вызвать register_node
оттуда…Элементарно, Ватсон (когда уже знаешь, как). Запускаем второй эмулятор, на этот раз с именем:
$ erl -sname repair
… и пингуем узел с приложением:
repair@hostname> net_adm:ping( ejabberd@hostname ).
(Если получили pong, все по плану. Если получили pang, закрываем ставшую бесполезной статью и начинаем с криками бегать по комнате.)
А вот теперь фокус. Заключается он в том, что соединение между узлами, будучи установленным — что мы только что сделали — остается открытым и дальше, и для общения по нему реестр
epmd
уже не нужен. Поэтому мы теперь идем обратно в первый эмулятор и прибиваем его:> halt().
Что мы только что сделали? Мы, помимо прочего, закрыли соединение к
epmd
, и он освободил имя ejabberd
для перерегистрации. (Посмотрите еще раз в epmd -names
, если не верите.)Теперь по нашему открытому соединению, оставшемуся висеть под потолком без страховки, мы можем, пользуясь прекрасным модулем
rpc
, зайти на узел приложения и блистательно завершить сеанс одновременной игры на трех процессах:repair@hostname> rpc:call( ejabberd@hostname, erl_epmd, register_node, [ejabberd, 23456] ).
repair@hostname> halt().
И усе. Закрываем терминалы и делаем то, ради чего в самом начале вообще полезли в систему.
Вопросы, уточнения, исправления приветствуются.