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

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

Roman Bogachev VMware Specialist | Drone Pilot | Traveler

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

db_single_server

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

vertical_sharding

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

db_sharding_2

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

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

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

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

1
2
3
4
5
6
7
8
9
<?
$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. Создание копии

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

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

После этого достаточно переключить соединение на новый сервер:
(Теперь мы используем два разных соединения для разных таблиц)

1
2
3
4
5
<?
$con = mysql_connect('10.10.0.1');
$con_photos = mysql_connect('10.10.0.2');

#...

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

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

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

1
2
3
4
5
6
7
8
9
<?
$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 придется перенести на приложение. Например, такой запрос:
(выбор всех фотографий пользователя 1)

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
<?

# ...
$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)

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

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

db_sharding_fail

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

db_sharding

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

1
2
3
4
5
6
<?
$con = mysql_connect('10.10.0.1');
# $con_photos = mysql_connect('10.10.0.2');
$con_photos = mysql_connect('10.10.0.3');

#...

Самое важное

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