Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Riak и Erlang/OTP

Глава 15 из книги "Архитектура приложений с открытым исходным кодом", том 1.

Оригинал: "Riak and Erlang/OTP", глава из книги "The Architecture of Open Source Applications"
Авторы: Francesco Cesarini, Andy Gross and Justin Sheehy
Перевод: Н.Ромоданов

Creative Commons: Перевод был сделан в соответствие с лицензией Creative Commons. С русским вариантом лицензии можно ознакомиться здесь.

15.4. Другие поведения рабочих процессов

С помощью тех же самых идей можно реализовывать и были реализованы много других видов поведений рабочих процессов.

15.4.1. Автоматы конечных состояний

Конечные автоматы (или машины с конечным числом состояний - FSM), реализованные в модуле поведения gen_fsm, являются важнейшим компонентом реализации стеков протоколов, используемых в сетях связи (той проблемной области, для которой первоначально и был создан язык Erlang). Состояния определяются как функции обратного вызова, в названиях которых отражено то, что возвращается в кортеже, имеющем переменную следующего состояния State, и то, каким образом обновляются данные цикла. Вы можете отправлять события для этих состояний как синхронно, так и асинхронно. Модуль функции обратного вызова конечного автомата также должен иметь возможность экспортировать стандартные функции обратного вызова, например, init, terminate и handle_info.

Разумеется, конечные автоматы не предназначены исключительно для целей телекоммуникаций. В Riak, они используются в обработчиках запросов. Когда клиент выдает запрос, например, get, put или delete, процесс, услышавший этот запрос, создаст процесс, реализующий соответствующее поведение gen_fsm. Например, riak_kv_get_fsm отвечающий за обработку запросов get, извлекает данные и отправляет их клиентскому процессу. Процесс FSM будет проходить через различные состояния, поскольку в нем определено, из каких узлов запрашивать данные, как в эти узлы отправлять сообщения, и как в ответ принимать данные, ошибки или тайм-ауты.

15.4.2. Обработчики событий

Обработчики и менеджеры событий являются еще одним поведением, реализованным в библиотечном модуле gen_event. Идея состоит в том, чтобы создать централизованное место, где принимаются события определенного вида. События могут передаваться синхронно и асинхронно с заранее определенным набором действий, выполняемых при их получении. Возможными реакциями на события может быть запись их в файл, посылка сообщения об аварии в виде SMS или сбор статистических данных. Каждое из этих действий определяется в отдельном модуле обратного вызова с его собственными данными цикла, которые сохраняются между вызовами. Для каждого конкретного менеджера событий можно добавлять, удалять или обновлять обработчики событий. Таким образом, на практике, в каждом менеджере событий может быть много модулей обратного вызова, а в различных менеджерах событий также может быть много различных экземпляров таких модулей обратного вызова. К числу обработчиков событий относятся процессы, получающие сигналы тревоги, отслеживающие данные в реальном времени, следящие за событиями, связанными с оборудованием, или просто регистрирующие данные в журнале.

Одно из применений в Riak поведения gen_event является управление подписками в «кольце событий», т. е. изменений принадлежности узлам разделов или назначение разделов узлам в кластере Riak. Процессы в узле Riak могут регистрировать функцию в экземпляре событий riak_core_ring_events, реализующем поведение gen_event. Всякий раз, когда центральный процесс, управляющий кольцом событий в этом узле, изменяет запись о принадлежности, он создает событие, в результате которого в каждом из этих модулей обратного вызова будет вызвана зарегистрированная функция. Таким образом, можно достаточно просто организовать реагирование различных частей Riak на изменения в одной из самых центральных структур данных Riak, причем не добавляя сложности в сам механизм централизованного управления этой структурой.

Наиболее распространенные модели распараллеливания и взаимодействия процессов обрабатываются с помощью трех основных типов поведения, которые мы только что рассмотрели: gen_server, gen_fsm и gen_event. Тем не менее, в больших системах с течением времени возникает необходимость в некоторых моделях, предназначенных для конкретного приложения, , т. е. нужно создавать новые виды поведений. В Riak есть одно такое поведение, riak_core_vnode, в котором формализована реализация виртуальных узлов. Виртуальные узлы являются первичной абстракцией хранения данных в Riak, которая по запросам, управляемым с помощью конечных автоматов, предоставляет единый интерфейс хранилища данных вида «ключ - значение». Интерфейс модулей обратного вызова задается с помощью функции behavior_info/1 следующим образом:

behavior_info(callbacks) ->
    [{init,1},
     {handle_command,3},
     {handoff_starting,2},
     {handoff_cancelled,1},
     {handoff_finished,2},
     {handle_handoff_command,3},
     {handle_handoff_data,2},
     {encode_handoff_item,2},
     {is_empty,1},
     {terminate,2},
     {delete,1}];

В приведенном выше примере показана функция behavior_info/1 узла riak_core_vnode. В списке кортежей {CallbackFunction, Arity} определен контракт, которому должны следовать модули обратного вызова. Эти функции должны быть экспортированы в конкретные реализации виртуальных узлов, иначе компилятор выдаст предупреждение. Реализация своего собственного поведения OTP относительно проста. Кроме определений ваших собственных функций обратного вызова, использующих модули proc_lib и sys, вам потребуется запускать их вместе с конкретными функциями, обрабатывать системные сообщения и следить за тем, не завершился ли родительский процесс.


Продолжение статьи: Супервизоры.