На прошлой неделе я написал первый пост о шардинге в SQL Azure, в котором я рассказал о том, что такое шардинг, почему он так важен для масштабирования, и почему SQL Azure является хорошим выбором хранилища данные, если мы собираемся использовать шардинг. Со своей стратегией pay as you go, SQL Azure подходит как нельзя лучше в качестве хранилища данных, но этого мало. Организация шардинга дело непростое, особенно если ваша база данных и ваше приложение изначально не было к этому готово. В этом случае придётся много чего ломать и перестраивать заново. Операции с данными довольно сложны и весь функционал работы с масштабируемым хранилищем приходится писать самому. Но скоро эта ситуация должна измениться. Это произойдёт с приходом SQL Azure Federations.
SQL Azure Federations – новая концепция работы с распределённым хранилищем данных в SQL Azure. Если в двух словах, то это выглядит так: в базе данных создаётся федерация, которая хранит информацию о распределении данных. Данные распределяются между шардами (отдельными базами данных) по диапазону ключей. Перераспределение данных между шардами автоматизировано и оптимизировано так, чтобы минимизировать время простоя. Также в SQL Azure Federations есть система роутинга, позволяющая определить на каком шарде находятся интересующие нас данные, что значительно облегчит реализацию шардинга в нашем приложении. Сейчас мега-фича Federations скрыта в недрах SQL Azure, и публичного доступа к ней нет, но её вовсю крутят и показывают на различных мероприятиях, команда разработчиков с удовольствием делится своими знаниями и рассказывает очень много про концепцию Federations. Я предлагаю вам взглянуть на те возможности, которые предоставляет нам SQL Azure Federations, потому что в скором времени эта фича станет доступной всем пользователям SQL Azure.
Начнём знакомиться с SQL Azure Federations с основных понятий:
- Federation Root – база данных, содержащая информацию о федерации (база данных)
- Federation (федерация) – представляет данные с шардов (по сути просто набор метаданных)
- Federation Key (ключ федерации) - ключ, который определяет маршрутизацию данных (поле таблицы)
- Federation Member (aka Shard) (член федерации) - физическое хранилище данных (отдельная база данных)
- Atomic Unit - Все строки таблицы с одинаковым значением federation key
Теперь давайте свяжем все эти понятия. Federation Root – корневая база данных, которая хранит в себе метаданные федерации, но не хранит сами данные федерации. Federation – набор метаданных, который описывает распределение данных между шардами (Federation Member). Federation Member – выделенная база данных, которая хранит в себе часть данных федерации. Распределение данных между членами федерации происходит на основе Federation Key – поля в базе данных, диапазон значений которого определяет данные шарда. Все строки таблицы, имеющие одинаковый Federation Key образуют один Atomic Unit.
Давайте рассмотрим это на небольшом примере. Имеется база продаж SalesDB. Мы решаем шардить таблицу заказов по полю CustomerId. В этом случае каждый шард (Federation Member) будет содержать данные какого-то дискретного количества заказчиков (диапазон значений поля CustomerId). Поле CustomerId в этом случае будет ключом федерации (Federation Key), а все строки с одинаковым CustomerId будут представлять собой один Atomic Unit. После того, как мы спланировали стратегию шардинга, можно приступать к реализации. На первом шаге мы создаём федерацию, при помощи следующей инструкции:
CREATE FEDERATION OrdersFederation (RANGE BIGINT)
После выполнения этой инструкции в базе данных будет создана федерация OrdersFederation. Метаданные федерации будут храниться в той базе данных, в контексте которой была выполнена инструкция. В инструкции указывается тип ключа федерации, по которому будет производиться шардинг. Также, после выполнения инструкции будет создан первый Federation Member, который, по умолчанию, не имеет фиксированного диапазона и хранит в себе все данные.
Теперь, определив федерацию, мы можем создавать таблицы. Следуя концепции Federations, у нас теперь есть 3 вида таблиц:
- Federated Tables
- Данные таблицы распределяются по шардам в зависимости от ключа федерации. В примере поле CustomerId является ключом федерации (Federation Key), его значение будет определять то, на каком шарде будут находиться данные таблицы. Данные таблицы будут распределены между шардами
- Создаётся при помоши инструкции: CREATE TABLE Orders (…) FEDERATE ON (CustomerId)
- Ключевое слово FEDERATE ON говорит о том, что это будет Federated Table
- Reference Table
- Данные таблицы будет реплицироваться между шардами. В нашем примере, на каждом шарде будет храниться полная копия данных таблицы ZipCodes
- Отсутствие условия FEDERATE ON говорит о том, что это будет Reference Table
- Создаётся при помоши инструкции: CREATE TABLE ZipCodes (…)
- Centralized Table
- Данные не находятся на шардах и хранятся только один раз
- Создаются в Root Database (без соединения с федерацией)
Таким образом у нас есть 3 варианта хранения данных в SQL Azure базе данных, если мы используем Federations: хранить данные в корневой базе, распределять данные между шардами и дублировать данные на каждом шарде.
И, наконец, самое интересное! Сейчас я расскажу о том, как SQL Azure Federations решает две большие проблемы шардинга: Маршрутизация запросов и Слияние/Разделение шардов.
Проблема маршрутизации состоит в том, что для работы с распределённой базой нужно знать, на каком шарде находятся данные, которые нам нужны. Для этого нужно писать в приложении свою логику, готовую к тому, что количество шардов со временем может увеличиться или уменьшиться. SQL Azure Federations решает эту проблему на уровне базы данных. Вначале вы устанавливаете соединение в корневой базой (здесь всё как обычно). Затем, так как каждый шард представляет собой отдельную базу данных, вам нужно соединиться с ней при помощи следующей инструкции:
USE FEDERATION OrdersFederation (56) WITH FILTERING = ON
После выполнения этой команды вы будете работать в контексте базы данных (шарда) на котором расположены данные с ключом федерации 56. Условие WITH FILTERING = ON говорит о том, что в этом соединении мы будем работать только с данными одного Atomic Unit (со строками у которых CustomerId = 56). При попытке обратиться к строкам с другим значением поля (даже если эти данные находятся на одном шарде) вы получите ошибку. Данные Reference Tables будут видны. Второй вариант использования этой инструкции включает в себя условие WITH FILTERING = OFF. В этом случае вам будут доступны данные всего шарда. Однако здесь есть опасность того, что шард может быть разделён, и вы попытаетесь обратиться к данным, которые уже будут на другом шарде. В первом случае, когда работа идёт только с одним Atomic Unit, такой проблемы не будет. Atomic Unit неделим. Все данные одного Atomic Unit заведомо находятся на одном шарде.
Вторая проблема, решаемая SQL Azure Federations – Разделение/Слияние данных. Обычно это головная боль для разработчиков и администраторов баз данных. Как организовать процесс создания шардов? Как уменьшить время простоя при переносе данных с одного шарда на другой? Как минимизировать время операции? И так далее. Вопросов много, но в SQL Azure Federations есть одно общее решение – операции SPLIT и MERGE. Инструкция SPLIT выглядит примерно так:
ALTER FEDERATION OrdersFederation SPLIT (100)
Federation Member, содержаший записи с ключом федерации 100, будет разбит на 2 члена федерации по этому ключу. Копирование данных происходит асинхронно. Все данные с ключом федерации меньшим или равным 100 копируются в одну базу, данные с ключом большим 100 в другую. После того, как все данные будут скопированы, происходит переключение и обновляются метаданные федерации. Таким образом время простоя приложения, работающего с базой при этой операции близко к нулю. Операция MERGE является полной противоположностью операции SPLIT и имеет такой-же синтаксис.
Всё что я сегодня показал, войдёт в первый релиз SQL Azure Federations, который судя по всему будет довольно скоро.Совсем недавно команда SQL Azure анонсировала программу раннего тестирования SQL Azure Federations, и если вы хотите быть одним из первых, кто это попробует, заходите по этой ссылке - и регистрируйтесь для получения доступа к ранней версии. Возможно к моменту релиза, синтаксис команд немного изменится, но сама концепция Federations останется такой-же. И, конечно же, на этом команда разработчиков не собирается останавливаться и SQL Azure Federations есть куда развиваться. Напоследок я хочу привести несколько приоритетных направлений, в которых работает команда разработки:
- Multi Column Federation Keys (Шардинг по составному ключу)
- Поддержка Entity Framework
- Schema Management (Обновление схемы таблицы сразу на всех шардах)
- Fan-out Queries (Распределённый запрос данных с нескольких шардов)
- Auto Repartitioning (Автоматическое разбиение базы данных в зависимости от определённого критерия (время отклика, размер базы данных и т.п.))
Ссылки по теме: