Системы распределенных баз данных 101
Или распределенные базы данных - что на самом деле означает « веб-масштаб »?
Системы распределенных баз данных являются сложными критериями и могут быть разных видов. Если я углублюсь в глубины моих смутно запомнившихся исследований по этому вопросу в университете, я попытаюсь объяснить некоторые из ключевых инженерных проблем построения системы распределенных баз данных.
Сначала немного терминологии
Свойства ACID (атомарность, непротиворечивость, изоляция и долговечность). Это ключевые инварианты, которые необходимо применять для обеспечения надежной реализации транзакции без нежелательных побочных эффектов.
Атомарность требует, чтобы транзакция была завершена или откат полностью. Частично завершенные транзакции никогда не должны быть видны, и система должна быть построена таким образом, чтобы это не происходило.
Согласованность требует, чтобы транзакция никогда не нарушала какие-либо инварианты (такие как декларативная ссылочная целостность), которые гарантированы схемой базы данных. Например, если существует внешний ключ, должно быть невозможно вставить дочернюю запись с почтением к несуществующему родителю.
Изоляция требует, чтобы транзакции не мешали друг другу. Система должна гарантировать те же результаты, если транзакции выполняются параллельно или последовательно. На практике большинство продуктов RDBMS допускают режимы, которые компенсируют изоляцию и производительность.
Долговечность требуетчтобы когдато совершил, то сделка остается в постоянной памяти таким образомчто является устойчивым к аппаратному или программному сбою.
Ниже я объясню некоторые технические препятствия, предъявляемые этими требованиями к распределенным системам.
Архитектура общего диска: архитектура, в которой все узлы обработки в кластере имеют доступ ко всему хранилищу. Это может представлять собой центральное узкое место для доступа к данным. Примером системы с общим диском является Oracle RAC или Exadata .
Архитектура Shared Nothing. Архитектура, в которой узлы обработки в кластере имеют локальное хранилище, которое невидимо для других узлов кластера. Примерами систем без разделения ресурсов являются Teradata и Netezza .
Архитектура разделяемой памяти: архитектура, в которой несколько процессоров (или узлов) могут получить доступ к общему пулу памяти. Большинство современных серверов имеют общую память. Совместно используемая память облегчает определенные операции, такие как кэширование или элементарные примитивы синхронизации, которые намного сложнее выполнять в распределенных системах.
Синхронизация: универсальный термин, описывающий различные методы для обеспечения согласованного доступа к общему ресурсу несколькими процессами или потоками. Это гораздо сложнее сделать в распределенных системах, чем в системах с общей памятью, хотя некоторые сетевые архитектуры (например, BYNET Teradata) имели примитивы синхронизации в сетевом протоколе. Синхронизация также может сопровождаться значительными накладными расходами.
Semi-Join: примитив, используемый для объединения данных, хранящихся в двух разных узлах распределенной системы. По сути, он состоит из достаточного количества информации о строках, которые объединяются и объединяются и передаются одним узлом в другой для разрешения объединения. Для большого запроса это может включать значительный сетевой трафик.
Возможная согласованность: термин, используемый для описания семантики транзакций, которая компенсирует немедленное обновление (согласованность при чтениях) на всех узлах распределенной системы для повышения производительности (и, следовательно, более высокой пропускной способности транзакций) при записи. Возможная согласованность является побочным эффектом использования Quorum Replication в качестве оптимизации производительности для ускорения фиксации транзакций в распределенных базах данных, где несколько копий данных хранятся на отдельных узлах.
Алгоритм Лампорта: алгоритм для реализации взаимного исключения (синхронизации) в системах без разделяемой памяти. Обычно взаимное исключение в системе требует атомарного чтения-сравнения-записи или аналогичной инструкции типа, обычно применяемой только в системе с общей памятью. Существуют и другие алгоритмы распределенной синхронизации, но Лампорт был одним из первых и наиболее известен. Как и большинство механизмов распределенной синхронизации, алгоритм Лампорта в значительной степени зависит от точной синхронизации и синхронизации тактов с четырьмя узлами кластера.
Two Phase Commit (2PC): семейство протоколов, которые гарантируют, что обновления базы данных, включающие несколько физических систем, будут фиксироваться или откатываться последовательно. Независимо от того, используется ли 2PC в системе или в нескольких системах через диспетчер транзакций, он несет значительные накладные расходы.
В протоколе двухфазной фиксации менеджер транзакций просит участвующие узлы сохранить транзакцию таким образом, чтобы они могли гарантировать ее фиксацию, а затем сигнализировать об этом состоянии. Когда все узлы вернулись в «счастливое» состояние, они сигнализируют узлам о фиксации. Транзакция по-прежнему считается открытой, пока все узлы не отправят ответ, указывающий, что фиксация завершена. Если узел выходит из строя до того, как сигнализировать о завершении фиксации, менеджер транзакций будет повторно запрашивать узел, когда он возвращается, пока не получит положительный ответ, указывающий, что транзакция зафиксирована.
Multi-Version Concurrency Control (MVCC): управление конфликтами путем записи новых версий данных в другое место и предоставления другим транзакциям возможности просматривать старую версию данных до тех пор, пока новая версия не будет зафиксирована. Это уменьшает конкуренцию с базой данных за счет некоторого дополнительного трафика записи для записи новой версии, а затем помечает старую версию как устаревшую.
Алгоритм выбора: распределенные системы, включающие несколько узлов, по своей природе менее надежны, чем одна система, поскольку существует больше режимов отказов. Во многих случаях какой-то механизм необходим для кластерных систем, чтобы справиться с отказом узла. Алгоритмы выбора - это класс алгоритмов, используемых для выбора лидера для координации распределенных вычислений в ситуациях, когда узел «лидер» не определен или надежен на 100%.
Горизонтальное разбиение: таблица может быть разделена по нескольким узлам или томам хранения по ключу. Это позволяет разбить большой объем данных на более мелкие порции и распределить их по узлам хранения.
Sharding: набор данных может быть горизонтально разделен между несколькими физическими узлами в архитектуре без общего доступа . Если это разделение непрозрачно (т. Е. Клиент должен знать схему разделения и определить, какой узел запрашивать явным образом), это называется разделением. Некоторые системы (например, Teradata) делят данные по узлам, но местоположение прозрачно для клиента; этот термин обычно не используется в сочетании с этим типом системы.
Согласованное хеширование: алгоритм, используемый для распределения данных по разделам на основе ключа. Он характеризуется равномерным распределением ключей хеш-функции и возможностью упругого расширения или уменьшения количества сегментов. Эти атрибуты делают его полезным для разделения данных или загрузки по кластеру узлов, где размер может динамически изменяться при добавлении или удалении узлов из кластера (возможно, из-за сбоя).
Multi-Master Replication: метод, позволяющий реплицировать записи на несколько узлов в кластере на другие узлы. Этот метод облегчает масштабирование, позволяя разделить или разделить некоторые таблицы между серверами, а другие синхронизировать в кластере. Записи должны быть реплицированы на все узлы, в отличие от кворума, поэтому фиксации транзакций в архитектуре с репликацией с несколькими хозяевами обходятся дороже, чем в системе с репликацией кворума.
Неблокирующий коммутатор: Сетевой коммутатор, который использует внутренний аппаратный параллелизм для достижения пропускной способности, которая пропорциональна количеству портов без внутренних узких мест. Наивная реализация может использовать перекрестный механизм, но это имеет сложность O (N ^ 2) для N портов, ограничивая его меньшими коммутаторами. Коммутаторы большего размера могут использовать более сложную внутреннюю топологию, называемую неблокирующим минимальным связующим коммутатором, для достижения линейного масштабирования пропускной способности без необходимости использования аппаратного обеспечения O (N ^ 2).
Создание распределенной СУБД - насколько это может быть сложно?
Несколько технических проблем делают это довольно трудным для выполнения на практике. Помимо дополнительной сложности построения распределенной системы, архитектор распределенной СУБД должен преодолеть некоторые сложные инженерные проблемы.
Атомарность в распределенных системах: если данные, обновляемые транзакцией, распределяются по нескольким узлам, фиксация / откат узлов должны координироваться. Это добавляет значительную нагрузку на системы без совместного использования ресурсов. В системах с общим диском это не проблема, так как все хранилище видно всем узлам, поэтому один узел может координировать фиксацию.
Согласованность в распределенных системах. Чтобы взять приведенный выше пример внешнего ключа, система должна иметь возможность оценить согласованное состояние. Например, если родитель и потомок отношения внешнего ключа могут находиться на разных узлах, необходим некоторый механизм распределенной блокировки, чтобы гарантировать, что устаревшая информация не используется для проверки транзакции. Если это не применяется, у вас может возникнуть (например) состояние гонки, при котором родитель удаляется после проверки его наличия, прежде чем разрешить вставку дочернего элемента.
Отложенное применение ограничений (т. Е. Ожидание подтверждения фиксации DRI) требует, чтобы блокировка удерживалась на протяжении транзакции. Этот тип распределенной блокировки имеет значительные накладные расходы.
Если хранится несколько копий данных (это может быть необходимо в системах без общего доступа, чтобы избежать ненужного сетевого трафика от полусоединений), все копии данных должны быть обновлены.
Изоляция в распределенных системах. В тех случаях, когда данные, затронутые транзакцией, находятся на нескольких узлах системы, блокировки и версия (если используется MVCC) должны быть синхронизированы между узлами. Чтобы гарантировать сериализуемость операций, особенно на архитектурах без совместного использования ресурсов, где могут храниться избыточные копии данных, требуется механизм распределенной синхронизации, такой как алгоритм Лампорта, который также сопровождается значительными издержками в сетевом трафике.
Долговечность в распределенных системах. В системе с общими дисками проблема долговечности практически такая же, как и в системе с общей памятью, за исключением того, что протоколы распределенной синхронизации по-прежнему требуются для разных узлов. СУБД должна вести записи в журнал и последовательно записывать данные. В системе без совместного использования может быть несколько копий данных или частей данных, хранящихся на разных узлах. Протокол двухфазного принятия необходим, чтобы гарантировать, что принятие происходит правильно на узлах. Это также влечет за собой значительные накладные расходы.
В системе без разделения ресурсов потеря узла может означать, что данные недоступны для системы. Чтобы смягчить эти данные могут быть реплицированы на более чем один узел. Согласованность в этой ситуации означает, что данные должны быть реплицированы на все узлы, где они обычно находятся. Это может привести к значительным накладным расходам на записи.
Одной из распространенных оптимизаций, выполняемых в системах NoSQL, является использование репликации кворума и возможной согласованности, чтобы позволить реплицировать данные лениво, гарантируя при этом определенный уровень устойчивости данных путем записи в кворум, прежде чем сообщить о транзакции как выполненной. Затем данные лениво реплицируются на другие узлы, где находятся копии данных.
Обратите внимание, что «возможная согласованность» является основным компромиссом в отношении согласованности, который может быть неприемлемым, если данные должны просматриваться последовательно, как только транзакция будет совершена. Например, в финансовом приложении обновленный баланс должен быть доступен немедленно.
Shared-Disk системы
Система с общим диском - это система, в которой все узлы имеют доступ ко всему хранилищу. Таким образом, вычисление не зависит от местоположения. Многие платформы СУБД также могут работать в этом режиме - Oracle RAC является примером такой архитектуры.
Системы с общими дисками могут существенно масштабироваться, поскольку они могут поддерживать отношения M: M между узлами хранения и узлами обработки. SAN может иметь несколько контроллеров, а база данных может работать на нескольких серверах. В этих архитектурах центральным узким местом является коммутатор, но перекрестные коммутаторы позволяют этому коммутатору иметь большую полосу пропускания. Некоторая обработка может быть выгружена на узлы хранения (как в случае с Oracle Exadata), что может уменьшить трафик на пропускную способность хранилища.
Хотя коммутатор теоретически является узким местом, доступная полоса пропускания означает, что архитектуры совместно используемых дисков будут достаточно эффективно масштабироваться до больших объемов транзакций. В большинстве основных архитектур СУБД используется такой подход, поскольку он обеспечивает «достаточно хорошую» масштабируемость и высокую надежность. В архитектуре с избыточным хранилищем, такой как волоконно-оптический канал, нет единой точки отказа, так как между любым узлом обработки и любым узлом хранения есть как минимум два пути.
Системы Shared-Nothing
Системы без разделения ресурсов - это системы, в которых, по крайней мере, некоторые данные хранятся локально на узле и не видны непосредственно другим узлам. Это устраняет узкое место центрального коммутатора, позволяя масштабировать базу данных (по крайней мере, теоретически) с количеством узлов. Горизонтальное разделение позволяет разделить данные по узлам; это может быть прозрачно для клиента или нет (см. раздел выше).
Поскольку данные по своей природе распределены, для запроса могут потребоваться данные из более чем одного узла. Если для объединения требуются данные из разных узлов, операция полусоединения используется для передачи достаточного количества данных для поддержки объединения из одного узла в другой. Это может привести к большому количеству сетевого трафика, поэтому оптимизация распределения данных может существенно повлиять на производительность запросов.
Часто данные реплицируются между узлами системы без общего доступа, чтобы уменьшить необходимость в полусоединениях. Это очень хорошо работает на устройствах хранилищ данных, поскольку измерения, как правило, на много порядков меньше, чем таблицы фактов, и их можно легко реплицировать между узлами. Они также обычно загружаются пакетами, поэтому затраты на репликацию являются меньшей проблемой, чем в транзакционном приложении.
Присущий параллелизм архитектуры без общего доступа делает их хорошо подходящими для такого рода запросов сканирования таблиц / агрегирования, которые характерны для хранилища данных. Операции такого типа могут масштабироваться почти линейно с количеством узлов обработки. Большие объединения между узлами, как правило, приводят к дополнительным издержкам, поскольку операции полусоединения могут генерировать большой сетевой трафик.
Перемещение больших объемов данных менее полезно для приложений обработки транзакций, где накладные расходы на несколько обновлений делают этот тип архитектуры менее привлекательным, чем общий диск. Таким образом, этот тип архитектуры обычно не используется широко в приложениях хранилища данных.
Sharding, репликация кворума и возможная согласованность
Репликация кворума - это средство, где СУБД реплицирует данные для обеспечения высокой доступности. Это полезно для систем, предназначенных для работы на более дешевом аппаратном оборудовании, которое не имеет встроенных функций высокой доступности, таких как SAN. В этом типе системы данные реплицируются на несколько узлов хранения для повышения производительности чтения и избыточного хранилища, чтобы сделать систему устойчивой к аппаратному отказу узла.
Однако репликация записей на все узлы составляет O (M x N) для M узлов и N записей. Это делает запись дорогой, если запись должна быть реплицирована на все узлы, прежде чем транзакции разрешено фиксировать. Репликация кворума - это компромисс, который позволяет немедленно реплицировать записи в подмножество узлов и затем лениво записывать их в другие узлы с помощью фоновой задачи. Записи могут быть зафиксированы быстрее, обеспечивая определенную степень избыточности, гарантируя, что они реплицируются на минимальное подмножество (кворум) узлов до того, как транзакция будет передана клиенту как зафиксированная.
Это означает, что за считыванием узлов за пределами кворума могут просматриваться устаревшие версии данных до тех пор, пока фоновый процесс не завершит запись данных в остальные узлы. Семантика известна как «Возможная согласованность» и может быть или не быть приемлемой в зависимости от требований вашего приложения, но означает, что транзакции фиксируются ближе к O (1), чем O (n) в использовании ресурсов.
Разделение требует, чтобы клиент знал о разделении данных в базах данных, часто используя тип алгоритма, известного как «согласованное хеширование». В изолированной базе данных клиент хеширует ключ, чтобы определить, к какому серверу в кластере отправлять запрос. Поскольку запросы распределяются по узлам в кластере, узкого места с одним узлом-координатором запросов не возникает.
Эти методы позволяют масштабировать базу данных с почти линейной скоростью, добавляя узлы в кластер. Теоретически, репликация кворума необходима только в том случае, если базовый носитель данных считается ненадежным. Это полезно, если нужно использовать обычные серверы, но имеет меньшую ценность, если базовый механизм хранения имеет свою собственную схему высокой доступности (например, SAN с зеркальными контроллерами и многопутевое подключение к хостам).
Например, Google BigTable сам по себе не поддерживает репликацию кворума, хотя работает в GFS, кластерной файловой системе, которая использует репликацию кворума. BigTable (или любая система без совместного использования ресурсов) может использовать надежную систему хранения с несколькими контроллерами и распределять данные между контроллерами. Параллельный доступ был бы тогда достигнут посредством разделения данных.
Вернуться на платформы RDBMS
Не существует внутренней причины, по которой эти методы нельзя было бы использовать с RDBMS. Однако управление блокировками и версиями в такой системе будет довольно сложным, и любой рынок для такой системы, вероятно, будет достаточно специализированным. Ни одна из основных платформ RDBMS не использует репликацию кворума, и я не знаю ни одного продукта RDBMS (по крайней мере, ни одного продукта со значительным внедрением), который бы это делал.
Системы с общим диском и без общего доступа могут масштабироваться до очень больших рабочих нагрузок. Например, Oracle RAC может поддерживать 63 обрабатывающих узла (которые сами по себе могут быть большими машинами SMP) и произвольное количество контроллеров хранилища в сети SAN. IBM Sysplex (кластер мэйнфреймов zSeries) может поддерживать несколько мэйнфреймов (каждый со значительной вычислительной мощностью и собственной пропускной способностью ввода / вывода) и несколько контроллеров SAN. Эти архитектуры могут поддерживать очень большие объемы транзакций с семантикой ACID, хотя они предполагают надежное хранение. Teradata, Netezza и другие поставщики создают высокопроизводительные аналитические платформы, основанные на проектах без совместного использования ресурсов, которые масштабируются до чрезвычайно больших объемов данных.
До сих пор на рынке дешевых, но сверхвысокопроизводительных полностью ACID RDBMS-платформ доминирует MySQL, который поддерживает сегментирование и репликацию с несколькими хозяевами. MySQL не использует репликацию кворума для оптимизации пропускной способности записи, поэтому фиксация транзакций обходится дороже, чем в системе NoSQL. Sharding обеспечивает очень высокую пропускную способность чтения (например, Facebook широко использует MySQL), поэтому этот тип архитектуры хорошо масштабируется для нагрузок с высокой нагрузкой на чтение.
Интересная дискуссия
BigTable - это архитектура без разделения ресурсов (по сути, пара распределенных ключей и значений), как указывал Майкл Хаузенблас ниже . Моя первоначальная оценка включала движок MapReduce, который не является частью BigTable, но обычно используется вместе с ним в его наиболее распространенных реализациях (например, Hadoop / HBase и каркас Google MapReduce).
Сравнивая эту архитектуру с Teradata, которая имеет физическое сходство между хранилищем и обработкой (т. Е. Узлы имеют локальное хранилище, а не общую SAN), вы могли бы утверждать, что BigTable / MapReduce является архитектурой совместно используемых дисков через глобально видимую параллельную систему хранения.
Пропускная способность системы стиля MapReduce, такой как Hadoop, ограничена пропускной способностью неблокирующего сетевого коммутатора. 1 Неблокирующие коммутаторы могут, однако, обрабатывать агрегаты с большой пропускной способностью из-за параллелизма, присущего конструкции, поэтому они редко представляют собой существенное практическое ограничение производительности. Это означает, что архитектура с общим диском (возможно, лучше именуемая как система с общим хранилищем) может масштабироваться до больших рабочих нагрузок, даже если сетевой коммутатор теоретически является узким местом.
Первоначально было отмечено, что хотя это центральное узкое место существует в системах с общими дисками, подсистема многораздельного хранения с несколькими узлами хранения (например, планшетные серверы BigTable или контроллеры SAN) все еще может масштабироваться до больших рабочих нагрузок. Неблокирующая архитектура коммутатора может (теоретически) обрабатывать столько текущих соединений, сколько она имеет портов.
1 Конечно, доступная пропускная способность обработки и ввода / вывода также представляет собой ограничение производительности, но сетевой коммутатор является центральной точкой, через которую проходит весь трафик.