Экстренная реанимация epmd

    (Проблема, по всей видимости, чрезвычайно экзотическая, но в плане «как оно внутри устроено» достаточно познавательная.)

    Вот, допустим, работает у вас приложение, написанное на Эрланге (ну, скажем, тот же 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().

    И усе. Закрываем терминалы и делаем то, ради чего в самом начале вообще полезли в систему.

    Вопросы, уточнения, исправления приветствуются.
    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 10
    • +1
      Очень здорово, пишите ещё. Тут про Erlang материала почти нет.
      • +1
        Обязательно, как только придумается, о чем писать.

        Подстава Эрланга в том, что на синтетических примерах сложно показать его прелесть, а выдумывать в учебных целях что-то полноценное не каждый возьмется.
        • 0
          я не ерлангер.
          а почему сразу нельзя было сделать рпц вызов?
          • 0
            Сразу — это в какой момент?
            • 0
              В самом начале мы не можем этого сделать по той же самой причине, по которой в первом абзаце валятся управляющие скрипты — без регистрации в epmd у rpc:call нет никакой возможности связаться с узлом.

              Из анонимного узла мы не можем этого сделать, потому что анонимные узлы в принципе ни с кем не могут общаться.

              Вместо пинга мы не можем этого сделать, потому что имя все еще занято анонимным узлом — а если мы его раньше времени убьем, не установив соединения, то потеряем регистрацию и, опять же, rpc:call никуда не пробьется.
        • 0
          Можно, конечно, начать искать виновных, но сначала все-таки неплохо бы поднять систему на место.
          Угу. Подняли. А теперь надо бы всё-таки выяснить, почему оно сломалось. IMHO вопрос важный, т.к. если не ясна причина, то это может повториться, а регулярно заниматься таким ремонтом… да и просто любопытно.
          • 0
            Не, ну кто спорит-то.

            У меня сейчас только одна хоть сколько-нибудь жизнеспособная гипотеза — что кто-то по ошибке или незнанию прибил процесс. Случаи самопроизвольной смерти epmd, когда никто ничего не трогает, насколько я могу судить, еще не были зафиксированы.

            (Мы сами к той системе, кстати, имеем только достаточно ограниченный удаленный доступ и знаем только то, что нам говорят и что видно по логам. Тут с расследованием не особо развернешься.)
            • 0
              Т.е. данные случай можно считать единичным?
              • 0
                Как мне сейчас представляется, да.
          • 0
            И снова о реанимации epmd: sidentdv.livejournal.com/769.html

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.