Вертикальный шардинг

Обычно Web приложения работают с одним сервером базы данных. Почти всегда приложение использует более одной таблицы.

Одной из техник масштабирования базы данных является разделение таблиц по разным серверам. В этом случае несколько таблиц будут находится на одном сервере, а остальные на другом. Тогда запросы к разным таблицам будут обрабатываться разными серверами базы данных. Это и называется вертикальным шардингом.

Сервера с разными таблицами называются шардами. Некоторые таблицы обычно больше остальных. Шардинг обычно начинают с наиболее крупных и нагруженных таблиц. Их выделяют в отдельную группу и выносят на отдельный сервер.

Подготовка шардинга

Для выделения таблицы на отдельный сервер необходимо выполнить несколько простых действий.

1. Отдельное соединение

Убедиться, что в коде для всех обращений к выбранной таблице используется отдельное соединение. Перед включением отдельного сервера, оно будет просто дублировать основное соединение:

<?
$con = mysql_connect('10.10.0.1');
$con_photos = mysql_connect('10.10.0.1');

#...
mysql_query('SELECT * FROM users ...', $con);

#...
mysql_query('SELECT * FROM photos ...', $con_photos);

# Дубликат соединения для выбранных таблиц

2. Создание копии

Далее необходимо создать полную копию выбранных таблиц на новом сервере. В простом случае можно использовать дамп и остановку всего сайта на период создания копии. Чтобы сделать это без паузы, следует воспользоваться репликацией. В этом случае на новом сервере настраивается реплика нужных таблиц. В качестве Мастера будет выступать старый сервер, а новый будет Слейвом.

3. Переключение соединения

После этого достаточно переключить соединение на новый сервер:

<?
$con = mysql_connect('10.10.0.1');
$con_photos = mysql_connect('10.10.0.2');

#...

# Теперь мы используем два разных соединения для разных таблиц

Если для создания копии использовалась репликация, ее необходимо остановить.

Работа из приложения

В приложении мы будем работать с разными соединениями для разных таблиц:

<?
$con = mysql_connect('10.10.0.1');
$con_photos = mysql_connect('10.10.0.2');

#...
mysql_query('SELECT * FROM users ...', $con);

#...
mysql_query('SELECT * FROM photos ...', $con_photos);

# используем разные соединения для соответствующих таблиц

Это означает, что у нас будет столько же соединений, сколько и шардов. Их количество может быть большим, поэтому лучше использовать методику ленивой загрузки ресурсов для установки соединений.

JOIN'ы

Понятно, что JOIN двух таблиц на разных серверах сделать невозможно. Есть два варианта решения этой задачи.

Группы таблиц

Часто JOIN запросы имеют место только между какой-то группой таблиц, которые логически связанны друг с другом. Например таблицы, которые хранят данные о альбомах и фотографиях пользователей:

  • photos список фотографий, содержит album_id
  • albums список альбомов

В таком случае удобнее выносить на отдельный шард сразу всю группу этих таблиц. Это позволит использовать JOIN в рамках этой группы.

Выборка в приложении

В другом варианте, функциональность JOIN'a придется перенести на приложение. Например, такой запрос:

SELECT * FROM photos p JOIN albums a ON (a.id = p.album_id) WHERE a.user_id = 1

# Выбор всех фотографий пользователя 1

Если таблицы users и albums находятся на разных серверах, можно получить тот же результат так:

<?

# ...
$q = mysql_query('SELECT * FROM albums WHERE user_id = 1', $connection_albums);
$albums = mysql_fetch_all($q);


# получаем список ID альбомов пользователя
foreach ( $albums as $album ) $album_ids[] = $album['id'];


# выбираем все фотки для указанных альбомов
$q = mysql_query('SELECT * FROM photos WHERE album_id IN (' . implode(',', $album_ids) . ')', $connection_photos)

# Выполнение двух запросов вместо одного JOIN'a

Отказоустойчивость

Вероятность поломки серверов баз данных увеличивается с ростом их количества.

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

В случае выхода из строя одного из шардов достаточно будет переключить его соединение на резервный сервер:

<?
$con = mysql_connect('10.10.0.1');
$con_photos = mysql_connect('10.10.0.2');
$con_photos = mysql_connect('10.10.0.3');

#...

# Для использования резервного сервера достаточно будет изменить параметры соединения

Самое важное

Вертикальный шардинг — это удобный механизм масштабирования баз данных. Выделение логически связанных групп таблиц в отдельные шарды позволит даже использовать JOIN'ы. Обязательно используйте схему резервирования для повышения отказоустойчивости при шардинге. Начинайте с наиболее крупных и нагруженных таблиц. Для особо крупных таблиц применяйте методику горизонтального шардинга.


Подпишитесь на Хайлоад с помощью Google аккаунта
или закройте эту хрень