Microsoft Azure
Облачный бизнес
Вам понадобится

Microsoft Azure

Попробуйте платформу Microsoft Azure совершенно бесплатно.

Visual Studio

Бесплатная версия Visual Studio, позволяющая создавать приложения для платформы Microsoft Azure.

SDKs и дополнительные
инструменты

Инструменты разработки приложений для платформы Microsoft Azure.

Горизонтальное масштабирование облачного SQL Server (шардинг)

Шардинг является в известном смысле аналогом партиционирования в SQL Azure. Партиционирование в on-premise SQL Serverпозволяет распределить таблицу по файл-группам (след., по дискам) в пределах одной базы. Шардинг в SQL Azure используется для распределения таблицы по федерации облачных БД. Как мы знаем, сервер SQL Azure выступает логической сущностью, и находящиеся под его управлением базы данных будут, скорее всего, расположены на различных физических серверах. Федерация представляет собой набор партиций, определяемых схемой распределения федерации. Схема федерации задает ключ, на основе которого происходит разбиение. Федерирование оказывается полезным в ряде практических сценариев, например, чтобы превзойти ограничение на размер облачной базы (на момент написания поста 150 гиг), разбив массивную таблицу заказов по их номерам, или в мультитенантном сценарии, когда каждый CustomerID хранится на отдельном сервере, и т.д.

Зайдем на портал Windows Azure и создадим новую базу данных AdventureWorksFed, как описывалось здесь. Она будет корнем будущей федерации. Корень является логической точкой входа, который знает, как устроена федерация и маршрутизирует соединения к соответствующему шарду на основе значения ключа. Также корневая база хранит другие метаданные: имена пользователей, пароли, роли и т.д. Заходим в администрирование базы, как описывалось здесь и нажимаем кнопку New в верхнем меню. Создаем схему федерации, задавая ее имя, а также имя и тип ключа. В диалекте облачного T-SQL этому действию соответствует команда CREATE FEDERATION. Очень похоже на создание схемы партиционирования. На данный момент поддерживаются типы INT, BIGINT, UNIQUEIDENTIFIER и VARBINARY(n), где n не может превышать 900. Из способов распределения на данный момент единственно возможный  - по диапазонам (range), как и в партиционировании.

image001 

Рис.1

Обратите внимание, что вместе со схемой автоматически создался первый член федерации - служебная база данных по имени system-<guid>. Она не видна на портале в списке пользовательских баз. Чтобы ее увидеть, нужно соединиться с БД master и выполнить команду select * from sys.databases. Поле is_federation_member имеет у нее значение true.

image002

Рис.2

Возвратимся в корень федерации - БД AdventureWorksFed. Ознакомиться с метаданными федерации можно при помощи системныхпредставлений sys.federations, sys.federation_distributions, sys.federation_member_distributions order by federation_id, range_low. Так, мы видим, что на данный момент она состоит из одного члена, готового вместить данные, начиная с минимального значения bigint(range left в терминах партиционирования).

image003

Рис.3

Список федераций показывается на портале Windows Azure в Administration корневой базы:

image004

Рис.4

Кликнем на стрелку напротив единственной федерации в БД AdventureWorksFed и создадим на ней таблицу Customer, которая будет автоматически распределять свои данные по ее членам:

image005

Рис.5

image006

Рис.6

Принципиальным моментом выступает предикат federated on, привязывающий ключ таблицы (ID) к ключу федерации (cid). Для наполнения созданной таблицы выберем один из рассмотренных ранее способов. Я, в частности, воспользуюсь SSIS, чтобы перенести результаты запроса

select CustomerID, AccountNumber, format(ModifiedDate, 'yyyy-MM-dd') as ModifiedDate from Sales.Customer

в созданную на Рис.6 в Облаке Table1. 

image007

Рис.7

Всего в таблице Table1 содержатся клиенты с ID от

select min(ID), max(ID) from Table1
------------------------------------------------------
1       30118

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

with cte as (select ID, ntile(2) over (order by ID) ntile from Table1)
select ntile, count(1), max(ID) from cte group by ntile

image008

Рис.8

Рассплитим таблицу Table1 по границе 20208. Вместо одного члена федерации образуется два, данные (и нагрузка) будут разделены между ними. 

image009

Рис.9

Сплит занимает некоторое время:

image010

Рис.10

После чего по нажатию кнопки Refresh можно видеть, что таблица состоит уже из двух партиций:

image011

Рис.11

Метаданные первого члена федерации (подобно Рис.3):

image012

Рис.12

Аналогично, для второго:

USE FEDERATION CustomerFederation(cid=25000) WITH RESET, FILTERING=OFF
GO
SELECT db_name() db_name
SELECT * FROM sys.federation_member_distributions
SELECT MIN(ID) [CustomerID Low], MAX(ID) [CustomerID High] FROM Table1
 db_name
system-52d6b399-6425-4cfa-a16d-b64944637acb
 federation_id member_id   distribution_name     range_low   range_high
65536         65538       cid                   20208     NULL
 CustomerID Low       CustomerID High
20208                30118

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