Даже самые однообразные данные могут иметь какую-то ценность, если их много и они хранятся сколь угодно долго, поэтому важнейшая характеристика любой системы Больших Данных — это масштабируемость. Но только хранить мало — особенно актуальна проблема масштабируемости для интерактивных (веб-) приложений, внезапные всплески обращений к которым способны создавать нагрузку на системные ресурсы, превышающую расчетную.
Облачные платформы позволяют выделять ресурсы по мере необходимости, но когда разработчики приложений начали пользоваться облаком, выяснилось, что стандартные базы данных слишком негибки, чтобы адаптироваться к средам облачных масштабов. Итогом стала волна инноваций — появился целый ряд новых системных архитектур, функциональных возможностей и моделей данных. Хотя новые системы имеют многие фундаментальные свойства своих предшественниц (например, логическую и физическую независимость данных), развертываются и используются они по-новому, что позволяет достичь более высоких масштабируемости и быстродействия.
Попытаемся понять, как разработчики «разобрали на части» СУБД и составили новые системные архитектуры, отличающиеся от классической трехзвенной.
Зачем изобретать СУБД заново?
Модель аренды ресурсов с оплатой по мере использования, характерная для облаков, дает разработчикам системных архитектур новые возможности оптимизации затрат, но для получения экономии управление данными в облаке должно отвечать ряду новых требований.
- Эластичность. Облачные СУБД должны легко масштабироваться вверх и вниз в зависимости от рабочей задачи. Таким образом можно избежать избыточности ресурсов и снизить операционные расходы. Лучше всего подойдет горизонтальное масштабирование, поскольку подключать или отключать дополнительные машины проще, чем модернизировать отдельную систему, а кроме того, такое масштабирование теоретически не имеет границ.
- Гибкость и простота управления. Процедура развертывания новых приложений, пользующихся облачной СУБД, должна быть простой. Данное требование подразумевает применение адаптируемых моделей данных и схем.
- Отказоустойчивость. Для облачных СУБД необходима автоматическая обработка аварийных ситуаций, так как сбои в крупномасштабных развертываниях скорее норма, чем исключение.
Поскольку традиционные базы данных не отвечают всем этим требованиям, некоторые разработчики решили, что пришла пора отказаться от реляционной модели и SQL. В результате появилось течение NoSQL. Было разработано множество новых СУБД, рассчитанных на выполнение перечисленных требований и не полагающихся на традиционную модель данных и язык запросов. Но истинная причина проблем не в SQL и не в реляционной модели — виновата монолитная природа традиционных архитектур баз данных.
Трехзвенная архитектура
Базы данных, в том числе облачные, редко используются сами по себе — они служат основой приложений (транзакционных или аналитических) и встроены в сложные системные архитектуры. Классическая архитектура, которая изучается на любом курсе компьютерных наук, состоит из трех звеньев, или уровней: презентационного, уровня приложений и уровня данных (см. рис. 1, а). Каждый из уровней предоставляется в виде сервиса и обычно размещен на одном или более выделенных серверах. Такая многозвенная система имеет немало преимуществ. Самое важное — она многое упрощает, в том числе тестирование. В многоуровневых системах облачного масштаба на каждом из уровней проще выполнять масштабирование, тиражирование, секционирование и кэширование. Более того, путем переноса вычислений с уровня данных на уровень приложений или на презентационный можно снизить нагрузку на первый. Уровни приложений и презентационный проще масштабировать, так как они могут быть реализованы в качестве сервисов без сохранения состояния (stateless): администраторы могут повышать масштабируемость и отказоустойчивость путем горизонтального масштабирования (добавления новых машин), не заботясь о сложных протоколах синхронизации. Однако уровень баз данных — это сервис, сохраняющий состояние (stateful), и его горизонтальное масштабирование требует более сложных управляющих архитектур (например, «ведущий-ведомый», master/slave), а также протоколов обеспечения целостности данных (например, протокола двухфазного подтверждения). Соответственно, на уровне баз данных высокой масштабируемости и отказоустойчивости достичь сложнее.
Дополнительно ухудшает ситуацию то, что, поскольку базы данных обычно реализуются как монолитные системы, их масштабирование может быть только вертикальным (когда сервер оснащается более мощным оборудованием), а это подразумевает ограничения на готовность и масштабируемость. Но несмотря на это, крупные облачные сервис-провайдеры все же применяют классическую монолитную архитектуру, так как она дает возможность использовать существующие зрелые СУБД. Например, в Microsoft SQL Azure и платформе мини-приложений Yahoo такая архитектура применяется совместно со специальной коммутационной структурой поверх уровня данных, улучшающей готовность и масштабируемость.
Новые уровни данных
Многие разработчики, недовольные монолитной архитектурой, отказались от нее в пользу гибкости, необходимой для применения систем в облачных средах с оплатой по мере использования. При этом традиционная трехзвенная архитектура была преобразована в пятиуровневую: презентационный уровень, приложение, база данных, менеджер записей и файловая система (см. рис. 1, б). В новых системах эти уровни (слои) по-разному комбинируются; каждый слой представляет собой сервис с возможностью независимого масштабирования и управления для отказоустойчивости. Появились два новых уровня, а один был переработан.
Файловый уровень
Этот уровень обеспечивает доступ к файлам и лежит внизу стека. Интерфейс файловой системы предоставляет соответствующие функции записи/считывания и обычно оптимизирован для больших файлов. Наиболее известные облачные примеры файлового уровня: Google File System и Amazon Simple Storage Service. Обычно файлы семантически организованы в иерархическую структуру — имена файлов в пределах своего локального контекста уникальны. Многие из существующих распределенных файловых систем имеют либеральную модель консистентности, но обладают свойством монотонности (система обладает свойством монотонности по чтению собственных записей, если результат записи процесса в элемент данных всегда виден последующим операциям чтения того же процесса).
Уровень менеджера записей
Менеджер записей расширяет функциональность файловой системы, предоставляя более мелкодисперсный доступ к данным. В простейшем случае менеджер записей поддерживает только операции чтения и записи одиночных значений для каждого ключа. Системы, предоставляющие этот простой интерфейс, стали популярными вместе с развитием движения NoSQL (обычно их называют хранилищами «ключ-значение»). Но многие системы этой категории начали предоставлять более развитую функциональность, в том числе реляционные модели и возможность запрашивать диапазоны ключей с сортировкой. В результате получились уже не просто хранилища «ключ-значение», а системы «менеджеры записей», поскольку они реализуют функциональность, похожую на аналогичный компонент СУБД. Менеджер записей может упорядочить элементы данных в файловой системе так, чтобы ускорять выполнение взаимосвязанных запросов. К этому же уровню можно отнести такие механизмы оптимизации доступа, как индексы на основе B-деревьев, поскольку они предоставляют тот же интерфейс, что и данные, индексируемые ими. На этом уровне менеджер записей может реализовывать версионный контроль — хранить по нескольку версий одной и той же записи. Дополнительно он может поддерживать примитивы контроля одновременности, например test-and-set (считывания и замены значения).
Уровень баз данных
Этот уровень находится поверх менеджера записей, отвечая за обработку запросов и транзакций, а также за обслуживание представлений и индексов. В зависимости от системной модели запросов, базе приходится выполнять разный объем работы — от компиляции SQL-подобных запросов в физические планы выполнения для менеджера записей до простого принятия решения о том, к каким серверам обращаться для извлечения данных. В системах, поддерживающих аналитические запросы (таких как Hadoop MapReduce), база планирует выполнение элементов работ (заданий) из параллельных запросов на доступных серверах. Большинство существующих менеджеров записей поддерживают только атомарный доступ к индивидуальным записям, а база дополнительно может выполнять функции транзакционной системы с соответствующими гарантиями. Кроме того, на уровне базы данных автоматически создаются и обновляются вторичные индексы.
Новая иерархия уровней позволяет на каждом из них использовать различные методы распределения — например, между уровнями можно применять кэширование и комбинировать различные управляющие архитектуры в одной системе, такие как «ведущий-ведомый» и модель с несколькими ведущими. Важным архитектурным решением для уровней данных будет выбор компромисса между готовностью и консистентностью. Чтобы сохранять высокое быстродействие верхних уровней, когда хранение становится более распределенным, нужны масштабируемая модель данных и язык запросов — запрос не должен пытаться получить доступ к данным сразу из всех узлов хранения.
Новые архитектуры
В существующих системах упомянутые уровни комбинируются по-разному, и при совмещении большего количества уровней приходится жертвовать модульностью и скоростью взаимодействия с отдельно стоящими уровнями.
Пятизвенная архитектура
В такой архитектуре каждый уровень представляет собой отдельный сервис (рис. 1, б). Самый известный пример — это стек Google, состоящий из GFS (файловый уровень), BigTable (уровень менеджера записей) и Megastore (уровень баз данных). Наверху же находятся уровни приложений и презентационный. Такая сепарация обеспечивает высокую модульность, позволяющую разработчикам легко использовать отдельные элементы стека. Например, при аналитической обработке данных с помощью MapReduce можно пользоваться только файловым уровнем. BigTable, работая поверх файловой системы, предоставляет функциональность простого менеджера записей: доступ к ключам-значениям («строкам» в терминологии Google) с атомарными однострочными операциями, применяемыми для работы с веб-индексом Google. Уровень Megastore добавляет к этому поддержку транзакций и самоподдерживаемые индексы. Хотя у такого расслоения есть много преимуществ, оно создает дополнительный сетевой трафик между уровнями: например, операция соединения требует, чтобы данные доставлялись с файлового уровня через диспетчер записей на уровень базы данных. Возможно также снижение эффективности из-за дублирования функциональности на разных уровнях. В случае Google разные уровни выполняют протоколирование для нужд консистентности и отказоустойчивости, создавая дублирующиеся журналы.
Четырехзвенная разделенная архитектура с файловым уровнем
Один из способов уменьшить трафик между уровнями — объединить базу данных и диспетчер записей в один уровень (рис. 1, в). Внизу, в роли надежной сетевой системы хранения данных (Networked Attached Storage, NAS) действует файловый сервис. Подобно классической трехзвенной архитектуре, такое сочетание позволяет разработчикам пользоваться стандартными СУБД, такими как MySQL, однако за достижение высокой отказоустойчивости в этом случае отвечает файловый уровень, а не база данных. Примеры — Amazon Relational Database Service, Amazon Elastic Compute Cloud (EC2) в сочетании с Amazon Elastic Block Service (EBS), используемым как NAS. Последний позволяет разработчикам установить СУБД по выбору — можно достигнуть высокой устойчивости, просто сохраняя все журналы операций базы на томе EBS, который можно будет смонтировать на другом экземпляре EC2, если первоначальный даст сбой. К сожалению, такая архитектура наследует ограничения по масштабируемости от классической трехзвенной, так как обычно использует традиционную монолитную СУБД. Кроме того, трудно согласовать различные протоколы консистентности, применяемые внутри файлового уровня и объединенного уровня базы данных и диспетчера записи. В связи с этим, например, если Amazon RDS даст сбой, приложение может потерять изменения, внесенные за последние пять минут.
Трехзвенная система
Существует еще один вариант — уровень базы данных включается в качестве библиотеки в состав приложения. Внизу находится уровень файловой системы и менеджера записей, который можно тиражировать на несколько машин и секционировать между ними. Такая архитектура четко отделяет stateless-часть общего стека (презентационный уровень, уровень приложений и базу данных) от постоянной stateful-части (менеджера записей и файловой системы), при этом предоставляя оптимизированный путь доступа к данным через комбинированный уровень файлов и диспетчера записи. Другими словами, обработка запросов и транзакций автоматически масштабируется с уровнем приложений, облегчая нагрузку stateful-уровня. Более того, менеджер записей может масштабироваться до сотен узлов, обходя традиционное узкое место масштабируемости внутри уровня данных. Такая архитектура дает прекрасные возможности расширения, но лучше всего она подходит для рабочих задач с большим объемом транзакций и с малыми наборами данных в каждой. При более крупных аналитических запросах узким местом может стать сеть между приложением (базой данных) и диспетчером записей (файловым уровнем). Но в связи с непрерывным ростом пропускной способности сетей и появлением все более мощных менеджеров записей, способных выполнять проталкивание предиката (predicate push-downs), данные ограничения могут исчезнуть.
***
На сегодня среди комбинированных многозвенных архитектур еще нет четкого победителя. Некоторые специалисты по-прежнему уверены, что больше всего преимуществ дает традиционная трехзвенная архитектура, поскольку соответствующие системы полностью контролируют данные и при грамотной реализации могут масштабироваться. Другие отдают предпочтение модульным стекам, мотивируя это, например, нежеланием платить за полноценную систему обработки запросов, когда нужно лишь сохранять ключ и значение. Наконец, немало преимуществ есть и у СУБД-библиотеки, предоставляющей лучшее из двух миров: обработку запросов и прямой доступ к ключам и значениям.
Тим Краска (kraska@cs.brown.edu) — доцент факультета компьютерных наук Университета Брауна, Бет Трушковски (trush@eecs.berkeley.edu) — аспирант Калифорнийского университета Беркли.