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

UnixForum





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

Экосистема NoSQL

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

Оригинал: The NoSQL Ecosystem
Автор: Adam Marcus
Перевод: А.Панин

13.2. Модели данных и запросов систем NoSQL

Модель данных базы данных задает то, как данные будут логически организованы. Ее модель запросов устанавливает способ получения и обновления данных. Стандартными моделями данных являются реляционная модель, модель хранилища с доступом на основе ключей или различные модели на основе графов. Языки запросов, о которых вы могли слышать, включают SQL, поиск на основе ключей и MapReduce. Системы NoSQL комбинируют различные модели данных и запросов, что в итоге приводит к появлению различных архитектурных решений.

13.2.1. Модели данных систем NoSQL на основе ключей

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

В системах, основанных на поиске ключей, сложные объединения операций или извлечение данных, соответствующих нескольким ключам, могут потребовать нестандартного подхода к использованию имен ключей. Разработчик, желающий найти запись работника по ее идентификатору и найти всех работников отдела, может создать два типа ключей. Например, ключ employee:30 будет указывать на запись работника с идентификатором 30, а ключ employee_departments:20 может указывать на список всех работников отдела с идентификатором 20. Операция объединения запросов переносится в область логики приложения: для получения записей работников отдела 20 приложение сначала получает список идентификаторов работников с помощью ключа employee_departments:20, после чего в цикле получает записи работников с помощью ключей employee:ID с использованием списка идентификаторов работников.

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

Давайте кратко затронем типы данных, ассоциированных с каждым ключом. Различные системы NoSQL предлагают различные решения в данной области.

Хранилища пар ключ-значение

Простейшей формой хранилища системы NoSQL является хранилище пар ключ-значение. Каждый ключ ставится в соответствие значению, в форме произвольных данных. Хранилище системы NoSQL не располагает информацией об этих данных и просто передает их приложению. В нашем примере базы данных работников Employee ключу employee:30 могут соответствовать данные в формате JSON или таких бинарных форматах, как Protocol Buffers4, Thrift5 или Avro6, хранящие информацию о работнике с идентификатором 30.

Если разработчик использует структурированные форматы для хранения сложных структур данных, соответствующих ключу, он должен обрабатывать данные на уровне приложения: хранилище пар ключ-значение в общем случае не предоставляет механизмов для запросов ключей на основании некоторых свойств соответствующих им значений. Хранилища пар ключ-значение отличаются простотой их модели запросов, обычно состоящей из примитивов для установки, получения и удаления значений (set, get и delete), но не предусматривают возможности добавления простых функций фильтрации на уровне базы данных ввиду непрозрачности этих значений. Система Voldemort, основанная на системе Dynamo компании Amazon, предоставляет распределенное хранилище пар ключ-значение. Система BDB7 предоставляет библиотеку, реализующую интерфейс для работы с парами ключ-значение.

Хранилища пар ключ-структура данных

Хранилища пар ключ-структура данных, ставшие популярными благодаря системе Redis8, ассоциируют каждое значение с определенным типом. В Redis доступные типы, которые могут использоваться значением, включают в себя: целочисленные значения, строки, списки, множества и отсортированные множества. В дополнение к примитивам set / get / delete существуют такие специфичные для типов команды, как увеличение уменьшение целочисленного значения или добавление/извлечение элементов списка, позволяющие реализовать функции запросов модели без значительного влияния на характеристики производительности. Предоставляя простые специфические для типов функции, при этом избегая таких операций как сборки или объединения при работе с множеством ключей, система Redis поддерживает баланс между функциональностью и производительностью.

Хранилища пар ключ-документ

Хранилища пар ключ-документ, такие, как CouchDB9, MongoDB10 и Riak11 ставят в соответствие ключу какой-либо документ, содержащий структурированную информацию. Эти системы хранят документы в JSON или подобном JSON формате. Они содержат списки и словари, которые могут рекурсивно встраиваться друг в друга.

Система MongoDB разделяет пространство ключей на коллекции, поэтому ключи для записей работников (Employees) и записей отделов (Department), например, не будут пересекаться. Системы CouchDB и Riak возлагают задачу отслеживания типов на разработчика. Свобода действий и сложность хранилищ документов представляют обоюдоострый меч: разработчики приложений получают свободу моделирования своих документов, но логика запросов в рамках приложения может стать чрезмерно сложной.

Хранилища семейств столбцов BigTable

Системы HBase и Cassandra основывают свои модели данных на модели, используемой системой BigTable компании Google. В этой модели ключ идентифицирует строку, которая содержит данные, хранящиеся в одном или нескольких семействах столбцов (Column Families - CF). В рамках семейства столбцов каждая строка может содержать множество столбцов. Значения в каждом столбце содержат метку времени, поэтому несколько версий соответствий между строкой и столбцом могу находиться в одном семействе столбцов.

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

Модель данных каждого проекта так или иначе отличается от оригинальной модели системы BigTable, но в рамках системы Cassandra она претерпела наиболее значительные изменения. Система Cassandra вводит понятие суперстолбца в рамках каждого семейства столбцов для реализации нового уровня соответствия, моделирования и индексирования. Она также устраняет понятие локальных групп, которые могли физически хранить объединенное множество семейств столбцов для повышения производительности.

13.2.2. Хранилища на основе графов

Одним из классов хранилищ систем NoSQL являются хранилища на основе графов. Не все генерируемые данные аналогичны по своей структуре и реляционная модель, а также модели на основе ключей не всегда лучшим образом подходят для хранения и осуществления запросов любых данных. Графы являются фундаментальной структурой в компьютерных науках и системы HyperGraphDB12 и Neo4J13 являются двумя популярными системами NoSQL для хранения данных, структурированных в форме графов. Хранилища на основе графов практически по всем параметрам отличаются от других типов хранилищ, рассмотренных нами ранее: они используют отличные модели данных, шаблоны для обхода данных и создания запросов, физическое размещение данных на диске, метод распределения данных по множеству машин, а также семантики запросов транзакций. Мы не будем рассматривать эти фундаментальные отличия из-за ограничений объема главы, но вы должны понимать, что определенные классы данных могут более успешно храниться и модифицироваться с помощью запросов в случае применения хранилищ на основе графов.

13.2.3. Сложные запросы

Существуют известные исключения в отношении методов поиска данных в системах NoSQL только на основе ключей. Система MongoDB позволяет индексировать ваши данные на основе любого количества свойств и использует язык относительно высокого уровня для указания того, какие данные вы хотели бы извлечь. Системы на основе BigTable поддерживают сканеры для итерации в рамках семейства столбцов и выбора определенных элементов с помощью фильтрации по столбцам. Система CouchDB позволяет создавать различные отображения данных и выполнять задачи MapReduce в отношении вашей таблицы для упрощения выполнения более сложных операций поиска и обновления данных. Большинство систем имеют биндинги для системы Hadoop или другого фреймворка MapReduce для выполнения аналитических запросов в отношении наборов данных.

13.2.4. Транзакции

Системы NoSQL обычно отдают приоритет производительности системы над семантиками транзакций. Другие системы на основе SQL позволяют использовать любой набор выражений в рамках транзакции - от простых выборок строк на основе первичного ключа до сложных объединений нескольких таблиц, которые впоследствии используются для усреднения значений нескольких полей.

Эти базы данных на основе SQL предоставляют гарантии ACID для транзакций. Выполнение множества операций в рамках транзакции атомарно (Atomic, буква A в аббревиатуре ACID), что означает выполнение либо всех операций, либо отказ от их выполнения. Постоянство (Consistency, буква C) подразумевает уверенность в том, что после выполнения транзакции база данных будет находиться в обычном состоянии и не будет повреждена. Изоляция (Isolation, буква I) обозначает уверенность в том, что если две транзакции будут работать с одной и той же записью, они не будут мешать друг другу. Долговечность (Durability, буква D, данная тема будет подробно освещена в следующем разделе) подразумевает уверенность в том, что как только транзакция будет завершена, измененные данные будут сохранены в надежном месте.

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

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

Система Redis является известным исключением из общей тенденции отказа от транзакций. При работе на одном сервере, она предоставляет команду MULTI для атомарного и постоянного комбинирования множества операций, а также команду WATCH для изоляции операций. Другие системы предоставляют низкоуровневые функции проверки и установки значения (test-and-set), реализующие в некоторой степени гарантии изоляции.

13.2.5. Хранилище данных без жестко заданной схемы

Одним из распространенных параметров многих систем NoSQL является отсутствие жесткого требования к использованию схем в базе данных. Даже в хранилищах документов и хранилищах, использующих семейства столбцов, свойства подобных объектов не обязаны быть одинаковыми. Этот подход имеет преимущество, заключающееся в требовании меньшего структурирования данных и меньших затрат производительности при модификации схем в реальном времени. Данное решение возлагает большую ответственность на разработчика приложений, который должен использовать более безопасные методы программирования. Например, является ли отсутствие свойства lastname с фамилией в записи работника ошибкой, которую нужно исправить, или вызвано обновлением схемы, которая в данный момент используется системой? Управление данными и схемами реализуется на уровне стандартного кода приложения после нескольких итераций проекта, работающего с системами NoSQL, поддерживающими хранилища без жестко установленных схем.


Продолжение статьи: 13.3. Долговечность хранения данных.