Этот пост предназначен для определенной аудитории: разработчиков, которые, возможно, не выполнили много работы с базами данных или представлением данных, хотят начать работать над Mentat и ищут «быстрое исправление» контекста. .

Вы уже должны были прочитать Представляем Project Mentat. Этот пост может заполнить для вас некоторые пробелы.

Этот пост очень кратко описывает:

  1. Что такое база данных?
  2. Что такое схема?
  3. Что такое подборка событий?
  4. Что такое Datomic?
  5. Что такое SQLite?
  6. Что такое Project Mentat?

Ответы относительно краткие и несколько самоуверенные, но они должны стать отправной точкой для дальнейших исследований. Несогласие приветствуется!

Что такое база данных?

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

Традиционные «базы данных», как теперь понимают этот термин большинство разработчиков, являются реляционными базами данных SQL. Единственное взаимодействие осуществляется через язык текстовых запросов, SQL. Эти базы данных обычно являются ACID: атомарными, согласованными, изолированными и надежными.

Атомарно означает, что запись (действительно, связанный набор записей) либо происходит полностью, либо не происходит вообще.

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

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

Надежность означает, что после записи данные не теряются.

Обратите внимание, что эти свойства не имеют ничего общего с тем, использует ли БД SQL, является ли она реляционной или нет. Однако так называемые базы данных NoSQL часто игнорируют некоторые из этих свойств: они нередко теряют данные, которые были подтверждены как записанные (MongoDB является наиболее измышленным примером), не раскрывая транзакцию. примитивы (или для их транзакционных гарантий, применяемых только в одной строке или документе), или вообще не беспокоиться об ограничениях согласованности.

Некоторые утверждали, что эти свойства (и другие характеристики реляционных баз данных) устарели: например, что ограничения согласованности в базе данных лучше обрабатываются бизнес-логикой внутри приложения. Разные базы данных проводят эти линии в разных местах.

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

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

  • Реляционные базы данных хранят отношения между объектами. В базах данных SQL отношения моделируются в виде таблиц с произвольным количеством столбцов. Сущности - это строки в некоторой таблице, которые идентифицируются ключами. Запросы объединяют отношения (таблицы), чтобы получить новые отношения. Базы данных SQL не идеальны для хранения графиков - обход графа требует рекурсивных соединений, что является относительно недавней функцией SQL - документы, неструктурированные данные и т. Д., хотя «PostgreSQL часто бывает достаточно хорошо".
  • Базы данных документов хранят контент без предварительной явной схемы. Они часто используют JSON или XML в качестве собственного формата данных. (Хранение «без схемы» кажется экономией времени, но см. Ниже.)
  • Базы данных Graph моделируют данные как связи между узлами. Иногда эти ссылки могут быть аннотированы. Запросы выполняются с помощью обходов путей и условных обозначений, что может быть очень естественным для некоторых доменов. Обычно графические базы данных разрабатываются так, чтобы быстрее выполнять операции с графами, такие как «найди связанных субъектов», чем запросы к графу, смоделированному в базе данных другого типа.
  • Геопространственные базы данных фокусируются на пространственных координатах как на основном способе поиска вещей.
  • Приложения часто используют специальный плоский файл в качестве базы данных: он считывается в память и сбрасывается на диск при изменении. Обычно это резкий ответ на плохо настроенную базу данных (Мне не нужна вся эта сложная база данных!) Или на распространение независимых баз данных, и это заставляет разработчика приложения вручную выбирать, когда выполнять очистку, как запрашивать данные в памяти, как обрабатывать масштабирование и т. д. и т. д. Плоские файлы - хорошее решение для данных, которые редко меняются, не модифицируются одновременно и просты для запроса; файлы конфигурации - хороший пример. Это плохое решение для данных, которые часто меняются и требуют транзакционного чтения или записи. У Firefox есть хорошо задокументированные проблемы с хранилищем сессий.
  • И так далее.

Что такое схема?

Описание вашего домена. Рецепт формы ваших данных. Прочтите Мнение Мартина Фаулера о бессхемном хранении.

В схемах баз данных также часто описываются индексы / индексы: реляционные базы данных объединяют семантические, структурные и индексные описания данных в единую схему.

Реляционные базы данных (и другие) используют индексы для быстрого выполнения запросов. Индекс в реляционной базе данных (обычно) представляет собой копию всей или части таблицы, хранящуюся в другом порядке, с метаданными для облегчения поиска правильных значений.

Что такое подборка событий?

Идея о том, что состояние вашего приложения является конечным результатом последовательности событий, произошедших с более раннего состояния, и идея о том, что фундаментальная конструкция моделирования для работы с этим состоит в том, чтобы записывать последовательность событий напрямую, производя другие структуры данных из потока событий. Это должно быть хорошо знакомо разработчикам React / Redux.

Источники событий слабо связаны с CQRS, которая заключается в том, что читатели и писатели в вашей системе лучше всего обслуживаются различными представлениями данных. Наш подход не является самоуверенным - CQRS, не ES, - но вы часто увидите, что они обсуждаются вместе.

Снова идите прочтите Мартина Фаулера и посмотрите этот список для дальнейшего чтения.

Что такое Datomic?

Datomic - это база данных с закрытым исходным кодом, написанная на Clojure и работающая на JVM, созданная и поддерживаемая Cognitect. Datomic имеет богатый язык схем, хранит реляционные данные (хотя и немного более свободно, чем база данных SQL) и отличается своим отношением ко времени и изменениям. Коду приложения доступна история всех изменений. Схема также доступна. Определения схем могут со временем развиваться, при этом более старые определения доступны, как и более старые данные. Приложения могут запрашивать прошлые (и гипотетические будущие!) Состояния системы.

Запись хранимых данных в Datomic - в отличие от традиционных реляционных баз данных - хорошо осведомлена о времени и состоянии, аналогично тому, как Clojure делает явным различие между значениями и идентичностью в состоянии.

Все базы данных в пользовательских приложениях должны обрабатывать изменяющиеся и растущие данные с течением времени; Datomic включает это как часть своей модели данных. Напротив, большинство баз данных полностью забывают, что изменения когда-либо имели место, с изменениями, которые хранятся в журнале только достаточно долго, чтобы обеспечить надежность или репликацию: данные, хранящиеся в самой базе данных в настоящее время, являются чисто моментальными снимками, а приложения, которые должны отражать время, и изменения в их модели данных должны отражаться в явной форме. «Удаление» в Datomic - это на самом деле одно из двух: опровержение (указание на то, что более ранний факт больше не соответствует действительности) и удаление (вырезание части истории, как будто она никогда не имело место, как правило, по юридическим причинам или по соображениям конфиденциальности).

Есть много других особенностей Datomic, таких как различие между одноранговыми узлами и транзактором.

Прочтите вступление (часть 1, часть 2) и посмотрите, как Рич Хикки объясняет:

Datomic - это сервис, который работает вместе с широким спектром существующих систем хранения (включая AWS и Cassandra), используя их для хранения фрагментов индекса.

Что такое SQLite?

SQLite - это очень стабильная, довольно быстрая, чрезвычайно хорошо протестированная встроенная база данных SQL. Встроенные (также называемые «бессерверными») базы данных уже не так распространены; большинство баз данных SQL - на самом деле большинство баз данных ACID - представляют собой относительно большие размещенные серверы, такие как PostgreSQL, MySQL, и т. д.

Мы широко используем SQLite в Firefox, и Mozilla поддерживает хорошие отношения со своими разработчиками.

Что такое Project Mentat?

Mentat - это встроенное хранилище данных: по сути, модель данных Datomic и интерфейс схемы выражены поверх базы данных SQLite.

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

Основными преимуществами Mentat в таких приложениях, как Tofino, являются:

  • Естественно расширять схему и устанавливать новые отношения между сущностями. В живых приложениях схемы все время меняются.
  • Моделирование схемы выполняется на уровне домена («страница может иметь несколько посещений»), а не на уровне хранения («таблица посещений имеет столбец с неуникальным, не нулевым ограничением внешнего ключа, которое относится к таблице страниц») .
  • Различные части приложения могут совместно использовать одну базу данных.
  • Журнал транзакций доступен для запросов (и для синхронизации).
  • Язык запросов позволяет легко выражать объединения, в частности самосоединения в виде графов, которые в SQL очень сложны. Вот введение в язык запросов Datalog, используемый Datomic, DataScript и Mentat.
  • Архитектура базы данных делает естественным решение проблемы производительности через материализацию представлений и индексов внутри или вне самой базы данных. Например, атрибут можно пометить для полнотекстового поиска, просто добавив «:fulltext true» в схему. Приложения видят каждую транзакцию по мере ее возникновения и, таким образом, могут создавать свои собственные кеши.
  • Многие из ошибок, допущенных разработчиками, добавляющими базу данных ad hoc гибкостью - например, таблица «метаданных», содержащая строки, приводящая к неэффективному хранению и медленным запросам, - удалось избежать: сама схема предлагает достаточную гибкость в таком строковом хранилище нет необходимости.

Mentat использует комбинацию собственных свойств ACID SQLite и последовательных операций записи для достижения гарантий ACID (более или менее).

Здесь стоит признать, что то, как Mentat хранит данные в SQLite, является деталью реализации. Мы могли бы разделить нашу datoms таблицу на части; мы могли бы хранить журнал транзакций в базе данных ATTACHed; мы могли даже автоматически выводить традиционные «широкие» таблицы базы данных, где это необходимо. Граница абстракции довольно непрозрачна, и только транзактор и обработчик запросов должны знать о деталях. Абстрагирование хранилища таким образом само по себе ценно: мы можем внести существенные изменения в то, как реализован Mentat, не изменяя поверхность нашего API, а внутренние улучшения немедленно становятся доступными для всех потребителей.

Что дальше?

В этом посте раскрывается некоторый контекст, но не рассматривается, как именно построен Mentat. Некоторые страницы вики проекта освещают это, но, возможно, скоро появится другой пост.