Erlang: Лучший способ для одиночного gen_server в кластере erlang? - PullRequest
6 голосов
/ 16 декабря 2010

Настройка:

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

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

Вопрос (ы):

  • Можнопроверить, зарегистрирован ли процесс глобально в функции start_link gen_server и в этом случае вернуть {ok, Pid} уже запущенного процесса вместо запуска нового экземпляра gen_server?
  • Правильно ли, что таким образом один процесс будет частью нескольких супервизоров, и если один процесс выйдет из строя, все супервизоры на всех других узлах попытаются перезапустить процесс.Первый супервизор создаст новый процесс gen_server, а все остальные супервизоры снова свяжутся с этим процессом.
  • Должен ли я использовать какой-то global:trans() внутри функции start_link gen_server?

Пример кода:


start_link() ->
    global:trans({?MODULE, ?MODULE}, fun() ->
        case gen_server:start_link({global, ?MODULE}, ?MODULE, [], []) of
            {ok, Pid} -> 
                {ok, Pid};
            {error, {already_started, Pid}} ->  
                link(Pid), 
                {ok, Pid};
            Else -> Else
        end     
    end).


Ответы [ 2 ]

5 голосов
/ 16 декабря 2010

Если вы вернете {ok, Pid} чего-то, на что вы не ссылаетесь, это запутает супервизора, который полагается на возвращаемое значение.Если вы не хотите, чтобы супервизор использовал это в качестве функции start_link, вы можете обойтись без него.

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

Один из способов, которыми я создавал глобальные синглтоны в прошломчтобы запустить процесс на всех узлах, но иметь один из них (тот, который выигрывает глобальную гонку регистрации), быть ведущим.Другие процессы контролируют мастер, и когда мастер выходит, попытайтесь стать мастером.(И опять же, если они не выигрывают регистрационную гонку, то они следят за тем, что сделал).Если вы сделаете это, вам придется самостоятельно обрабатывать глобальную регистрацию имени (т.е. не использовать функциональность gen_server:start({global, ...), потому что вы хотите, чтобы процесс запускался независимо от того, выиграет ли он при регистрации, он просто будет вести себя по-разному в каждом случае.

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

Мой метод обычно требует нескольких раундов пересмотра, чтобы избавиться от угловых случаев, но, на мой взгляд, меньше хлопот, чем написание распределенного приложения OTP.Этот метод имеет еще одно преимущество перед распределенными приложениями в том, что вам не нужно статически настраивать список узлов, участвующих в вашем кластере - любой узел может быть кандидатом на запуск мастер-копии процесса.Ваш подход имеет то же свойство.

4 голосов
/ 16 декабря 2010

Как насчет превращения gen_server в приложение и использования распределенных приложений ?

...