Mnesia

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 22:16, 30 мая 2020.
Mnesia
Mnesia.png
Постоянный выпуск: 4.17 (12 мая 2020)
Написана на: Erlang
Операционная система: Кроссплатформенная
Тип ПО: Документо-ориентировання СУБД
Лицензия: Apache License
Веб-сайт erlang.org/doc/apps/mnesia/

Mnesia — распределенная СУБД реального времени, написанная на языке программирования Erlang. Технически является надстройкой над ETS- и DETS-таблицами, предоставляющей уровень транзакций и распределённого выполнения.

Общее

Mnesia - это распределенная Система Управления Базами Данных(СУБД), предназначенная для телекоммуникационных приложений и других Erlang приложений, которые требуют непрерывных операций и проявляют слабовыраженные свойства приложений реального времени.

Mnesia содержит в себе следующие возможности, которые в совокупности предоставляют отказоустойчивость и распределенность системы управления базами данных, написанной на Erlang:

  • Схема(schema) базы данных может динамически реконфигурироваться в режиме реального времени.
  • Таблицы(tables) могут быть объявлены с такими свойствами как месторасположение, репликация и живучесть.
  • Таблицы могут быть перемещены или реплицированы между несколькими узлами(nodes) улучшая отказоустойчивость. Остальная часть системы по-прежнему может обращаться к таблицам для чтения, записи и удаления записей.
  • Месторасположение таблицы прозрачно для программиста. В программах обращение к таблице ведется по имени, а система уже сама устанавливает связь с таблицей.
  • Транзакции могут быть распределены и в рамках одной транзакции может быть вызвано достаточно большое количество функций.
  • Несколько транзакций могут запускаться одновременно и их выполнение полностью синхронизируется самой СУБД. Mnesia гарантирует, что не может быть ситуации, когда два процесса оперируют одними и теми же данными.
  • Транзакциям может быть присвоено свойство выполнения на всех узлах системы, либо ни на одном. Транзакция также может быть не учтена в угоду скорости выполнения. Это, так называемая "грязная операция"(dirty operations), которая уменьшает загруженность системы и увеличивает скорость выполнения программы.

Модель базы данных

«Строки» в таблицах представлены в виде записей, которые содержат значение ключа и поле данных. Это поле данных, в свою очередь, может быть кортежем, содержащим структуру данных Erlang любой сложности.

Реляционные особенности

Модель базы данных реляционная, но это не то, что может ожидать кто-то, знакомый с SQL: база данных содержит таблицы, отношения между ними моделируются как другие таблицы.[Источник 1] Ключевой особенностью Mnesia является то, что таблицы могут быть переконфигурированы в схеме и перемещены между узлами не только во время работы базы данных, но даже во время операций записи.

Кодинг

Язык запросов Mnesia - это сам Erlang, а не SQL . Это позволяет легко представлять транзакции как естественную особенность Erlang, позволяя разработчикам использовать один язык во всем приложении.

Транзакции

Erlang- это функциональный язык . Mnesia опирается на это, чтобы получить поддержку транзакций ACID . Функциональный блок, который запускается как транзакция, представляет собой обычную конструкцию Erlang, которая называется Functional Object (или Fun) и вызывается одним выражением Mnesia mnesia:transaction(F). Это может привести к более чистому исходному коду, чем BEGIN/COMMIT синтаксис SQL, и, таким образом, позволяет избежать проблемы незакрытых транзакций в процедуре.

Опять же, из-за функциональности Erlang, вложенные транзакции становятся более простыми. Также возможно распределять транзакции по нескольким узлам (то есть отдельным серверам). Семантика использования транзакций таким образом остается согласованной, что облегчает написание библиотечного кода, который одинаково работает в любом контексте.

Общий стиль написания кода для Mnesia всегда будет использовать транзакции. По соображениям производительности он также поддерживает преднамеренные "грязная операция"(dirty operations), которые избегают транзакций. Они нарушают атомарность и изолирующие свойства ACID , но обеспечивают пропускную способность примерно в 10 раз больше.

Эффективное исполнение

Mnesia является частью стека веб-приложений LYME . Это похоже на LAMP , но основано на Erlang. Реализация на Erlang дает преимущество в эффективности благодаря использованию единой виртуальной машины в приложении. LYME использует это, так как Yaws веб - сервер также реализован в Erlang. Адресное пространство распределяется между кодом и данными, включая данные таблицы Mnesia[Источник 2].

Происхождение и лицензирование

Mnesia и Erlang были разработаны лабораторией компьютерных наук Эрикссон. Они были выпущены как программное обеспечение с открытым исходным кодом . Mnesia выпущена на основании производной лицензии Mozilla Public License . Начиная с OTP 18.0 они публикуются в соответствии с открытой лицензией Apache License 2.0 . Версии до OTP 18.0 были опубликованы под открытой лицензией Erlang Public License .

Назначение

Так же, как и язык программирования Erlang, СУБД Mnesia была разработана компанией Ericsson для распределенных вычислений реального времени и систем высокой доступности для отрасли телекоммуникаций. Она не предназначена ни для использования в качестве офисной системы для обработки экономических данных, ни как замена стандартных SQL-систем. Mnesia создана для поддержки использования языка Erlang в случаях, когда требуется СУБД-подобное хранение данных. Mnesia более схожа с встраиваемыми движками СУБД, такими как Berkeley DB, чем с типичными SQL СУБД.

Когда использовать Mnesia

Используйте Mnesia со следующими типами приложений:

  • Приложения, которые должны копировать данные.
  • Приложения, которые выполняют поиск данных.
  • Приложения, которым необходимо использовать атомарные транзакции для одновременного обновления нескольких записей.
  • Приложения, которые используют программные характеристики в реальном времени.

Mnesia не подходит для следующих типов приложений:

  • Программы, которые обрабатывают текстовые или бинарные файлы.
  • Приложения, которые просто нуждаются в поисковом словаре, который можно сохранить на диск. Эти приложения используют стандартную библиотеку dets , которая является дисковой версией модуля ets .
  • Приложения, которые нуждаются в средствах логгирования дисков. Эти приложения могут использовать модуль disk_log по своему предпочтению.
  • Жесткие системы реального времени.

Деревья контроля

Основной концепцией в Erlang/OTP является дерево контроля (supervision tree). Это модель структурирования процессов, основанная на идее рабочих и контролеров.

  • Рабочие – это процессы, которые выполняют вычисления, и, собственно, выполняют основную работу.
  • Контролеры (супервизоры) – это процессы, которые контролируют поведение рабочих. Супервизор может перезапустить рабочего, если что-то пойдет не так.
  • Дерево контроля – это иерархическое разделение кода на контролеров и рабочих, позволяющее разрабатывать устойчивое к ошибкам программное обеспечение.

На рисунке 1 представлено графическое представление дерева контроля, на котором квадратными блоками представлены контролеры, кругами – рабочие.

Рисунок 1 – дерево контроля

Первый запуск Mnesia

В этом разделе представлена ​​упрощенная демонстрация запуска системы Mnesia . Диалог от оболочки Erlang выглядит следующим образом:

unix>  erl -mnesia dir '"/tmp/funky"'
        Erlang (BEAM) emulator version 4.9
        
        Eshell V4.9  (abort with ^G)
        1> 
        1> mnesia:create_schema([node()]).
        ok
        2> mnesia:start().
        ok
        3> mnesia:create_table(funky, []).
        {atomic,ok}
        4> mnesia:info().
        ---> Processes holding locks <--- 
        ---> Processes waiting for locks <--- 
        ---> Pending (remote) transactions <--- 
        ---> Active (local) transactions <---
        ---> Uncertain transactions <--- 
        ---> Active tables <--- 
        funky          : with 0 records occupying 269 words of mem 
        schema         : with 2 records occupying 353 words of mem 
        ===> System info in version "1.0", debug level = none <===
        opt_disc. Directory "/tmp/funky" is used.
        use fall-back at restart = false
        running db nodes = [nonode@nohost]
        stopped db nodes = [] 
        remote           = []
        ram_copies       = [funky]
        disc_copies      = [schema]
        disc_only_copies = []
        [{nonode@nohost,disc_copies}] = [schema]
        [{nonode@nohost,ram_copies}] = [funky]
        1 transactions committed, 0 aborted, 0 restarted, 1 logged to disc
        0 held locks, 0 in queue; 0 local transactions, 0 remote
        0 transactions waits for other nodes: []
        ok

В этом примере выполняются следующие действия:

  • Шаг 1: Система Erlang запускается из командной строки UNIX с флагом -mnesia dir «/ tmp / funky» , который указывает, в каком каталоге хранить данные.
  • Шаг 2: Новая пустая схема инициализируется на локальном узле с помощью команды mnesia: create_schema ([node ()]) . Схема содержит информацию о базе данных в целом.
  • Шаг 3: СУБД запускается с помощью команды mnesia: start () .
  • Шаг 4: создается первая таблица, которая называется funky , путем выполнения выражения mnesia: create_table (funky, []) . Таблица имеет свойства по умолчанию.
  • Шаг 5: mnesia: info () используется для отображения на терминале информации о состоянии базы данных.

Поведения

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

Поведения(Behaviours) – это формализация таких общих паттернов. Идея заключается в том, чтобы разделить код в процессе на общую часть (модуль поведения) и специализированную часть (модуль обратного вызова(callback module))

Модуль поведения является частью Erlang/OTP. Для того, чтобы реализовать процесс как контролер, пользователю необходимо только реализовать модуль обратного вызова, который должен экспортировать предопределенное множество функций (функций обратного вызова(callback functions)).

Пример демонстрирует, как код может быть разделен на общую и специализированную части. Предположим, следующий код (написанный на чистом Erlang) для простого сервера, который следит за некоторым количеством «каналов». Другие процессы могут создавать и уничтожать эти каналы, вызвая функции alloc/0 и free/1, соответственно. (пример не компиллируется, есть ошибки)

-module(ch1).
-export([start/0]).
-export([alloc/0, free/1]).
-export([init/0]).

start() ->
    spawn(ch1, init, []).

alloc() ->
   ch1 ! {self(), alloc},
   receive
       {ch1, Res} ->
           Res
   end.

free(Ch) ->
   ch1 ! {free, Ch},
   ok.

init() ->
   register(ch1, self()),
   Chs = channels(),
   loop(Chs).

loop(Chs) ->
   receive
       {From, alloc} ->
           {Ch, Chs2} = alloc(Chs),
           From ! {ch1, Ch},
           loop(Chs2);
       {free, Ch} ->
           Chs2 = free(Ch, Chs),
           loop(Chs2)
   end.

Код сервера может быть разделен на общую часть server.erl:

-module(server).
-export([start/1]).
-export([call/2, cast/2]).
-export([init/1]).

start(Mod) ->
   spawn(server, init, [Mod]).

call(Name, Req) ->
   Name ! {call, self(), Req},
   receive
       {Name, Res} ->
           Res
   end.

cast(Name, Req) ->
   Name ! {cast, Req},
   ok.

init(Mod) ->
   register(Mod, self()),
   State = Mod:init(),
   loop(Mod, State).

loop(Mod, State) ->
   receive
       {call, From, Req} ->
           {Res, State2} = Mod:handle_call(Req, State),
           From ! {Mod, Res},
           loop(Mod, State2);
       {cast, Req} ->
           State2 = Mod:handle_cast(Req, State),
           loop(Mod, State2)
   end.

и модуль обратного вызова ch2.erl:

-module(ch2).
-export([start/0]).
-export([alloc/0, free/1]).
-export([init/0, handle_call/2, handle_cast/2]).

start() ->
   server:start(ch2).

alloc() ->
   server:call(ch2, alloc).

free(Ch) ->
   server:cast(ch2, {free, Ch}).

init() ->
   channels().

handle_call(alloc, Chs) ->
   alloc(Chs). % => {Ch,Chs2}

handle_cast({free, Ch}, Chs) ->
   free(Ch, Chs). % => Chs2

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

Использование поведений делает чтение и понимание кода другими программистами легче. Структуры Ad hoc, возможно более эффективные, всегда сложнее понимать.

Модуль server соотвествует, со значительными упрощениями, поведению gen_server из Erlang/OTP.

Стандартными поведениями в Erlang/OTP являются:

  • gen_server - для реализации клиент-серверной модели взаимодействия.
  • gen_fsm - для реализации конечных автоматов.
  • gen_event - для реализации обработки событий.
  • supervisor - для реализации контролера в дереве контроля.

Компилятор понимает атрибут модуля -behaviour(Behaviour) и ругается при отсутствии функций обратного вызова. Например:

-module(chs3).
-behaviour(gen_server).
...
3> c(chs3).
./chs3.erl:10: Warning: undefined call-back function handle_call/3
{ok,chs3}

Приложения

Erlang/OTP поставляется с набором компонент, каждая из которых реализует особый функционал. Компоненты в терминологии Erlang/OTP называются приложениями (applications). Примерами приложений Erlang/OTP являются Mnesia, которая содержит в себе все необходимое для программирования баз данных, и Debugger, используемый для отладки Erlang программ. Минимальная система, основанная на Erlang/OTP, состоит из приложений Kernel и STDLIB[1].

Концепция приложений относится и к структуре программы (процессам), и к структуре директорий (модулям).

Приложение простейшего типа не содержит ни одного процесса, а состоит из набора функциональных модулей. Такие приложения называются библиотечными приложениями(library application).

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

Примечания

Источники

  1. Mnesia // http://erlang.org: сайт. URL: http://erlang.org/doc/apps/mnesia/Mnesia_chap1.html#1 (дата обращения: 16.05.2020)
  2. Mnesia // "Mnesia - A Distributed Robust DBMS for Telecommunications Applications": сайт. URL: http://www.erlang.se/publications/mnesia_overview.pdf (дата обращения: 16.05.2020)