====== MySQL Вертикальный шардинг ======
Обычно Web приложения работают с одним сервером базы данных. Почти всегда приложение использует более одной таблицы. Одной из техник масштабирования базы данных является разделение таблиц по разным серверам.
{{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/db/005.jpg?nolink&|005.jpg}}
В этом случае несколько таблиц будут находиться на одном сервере, а остальные на другом. Тогда запросы к разным таблицам будут обрабатываться разными серверами базы данных. Это и называется вертикальным шардингом.
{{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/db/006.jpg?nolink&|006.jpg}}
Сервера с разными таблицами называются шардами. Некоторые таблицы, обычно, больше остальных. Шардинг обычно начинают с наиболее крупных и нагруженных таблиц. Их выделяют в отдельную группу и выносят на отдельный сервер.
{{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/db/007.jpg?nolink&|007.jpg}}
===== Подготовка шардинга =====
Для выделения таблицы на отдельный сервер необходимо выполнить несколько простых действий.
==== 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. Создание копии ====
Далее необходимо создать полную копию выбранных таблиц на новом сервере. В простом случае можно использовать дамп и остановку всего сайта на период создания копии. Чтобы сделать это без паузы, следует воспользоваться репликацией. В этом случае на новом сервере настраивается реплика нужных таблиц. В качестве **Master** будет выступать старый сервер, а новый будет **Slave**.
==== 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** придется перенести на приложение. Например, такой запрос: (выбор всех фотографий пользователя 1)
|
SELECT * FROM photos p JOIN albums a ON (a.id = p.album_id) WHERE a.user_id = 1
|
Если таблицы **users** и **albums** находятся на разных серверах, можно получить тот же результат так: (Выполнение двух запросов вместо одного JOIN’a)
|
# ...
$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)
|
===== Отказоустойчивость =====
Вероятность поломки серверов баз данных увеличивается с ростом их количества.
{{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/db/008.jpg?nolink&|008.jpg}}
Для обеспечения отказоустойчивости необходимо резервировать сервера баз данных с помощью репликации. В таком случае, каждый шард будет иметь резервный сервер с копией данных.
{{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/db/009.jpg?nolink&|009.jpg}}
В случае выхода из строя одного из шардов достаточно будет переключить его соединение на резервный сервер: (Для использования резервного сервера достаточно будет изменить параметры соединения)
|
$con = mysql_connect('10.10.0.1');
# $con_photos = mysql_connect('10.10.0.2');
$con_photos = mysql_connect('10.10.0.3');
#...
|
===== Самое важное =====
Вертикальный шардинг — это удобный механизм масштабирования баз данных. Выделение логически связанных групп таблиц в отдельные шарды позволит даже использовать **JOIN’ы**. Обязательно используйте схему резервирования для повышения отказоустойчивости при шардинге. Начинайте с наиболее крупных и нагруженных таблиц. Для особо крупных таблиц применяйте методику горизонтального шардинга.