Шардирование баз данных

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 17:11, 9 июня 2017.

Шардирование (горизонтальное партиционирование) — это принцип проектирования базы данных, при котором логически независимые строки таблицы базы данных хранятся раздельно, заранее сгруппированные в секции, которые, в свою очередь, размещаются на разных, физически и логически независимых серверах базы данных, при этом один физический узел кластера может содержать несколько серверов баз данных. Наиболее типовым методом горизонтального партицирования является применение хеш функции от идентификационных данных клиента, которая позволяет однозначно привязать заданного клиента и все его данные к отдельному и заранее известному экземпляру баз данных («шарду»), тем самым обеспечив практически неограниченную от количества клиентов горизонтальную масштабируемость.

Этот подход принципиально отличается от вертикального масштабирования, которое при росте нагрузки и объёма данных предусматривает наращивание вычислительных возможностей и объёма носителей информации одного сервера баз данных, имеющее объективные физические пределы — максимальное количество поддерживаемых CPU на один сервер, максимальный поддерживаемый объем памяти, пропускная способность шины и т. д.

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


Горизонтальный шардинг — это разделение одной таблицы на разные сервера. Это необходимо использовать для огромных таблиц, которые не умещаются на одном сервере. Разделение таблицы на куски делается по такому принципу:

  • На нескольких серверах создается одна и та же таблица (только структура, без данных).
  • В приложении выбирается условие, по которому будет определяться нужное соединение (например, четные на один сервер, а нечетные — на другой).
  • Перед каждым обращением к таблице происходит выбор нужного соединения.

Критерий шардинга — какой-то параметр, который позволит определять, на каком именно сервере лежат те или иные данные.

  • ID поля таблицы
  • Хеш-таблица с соответствиями «пользователь=сервер» (Тогда, при определении сервера, нужно будет выбрать сервер из этой таблицы. В этом случае узкое место — это большая таблица соответсвия, которую нужно хранить в одном месте.)
  • Определять имя сервера с помощью числового (буквенного) преобразования. (Например, можно вычислять номер сервера, как остаток от деления на определенное число (количество серверов, между которыми Вы делите таблицу). В этом случае узкое место — это проблема добавления новых серверов — Вам придется делать перераспределение данных между новым количеством серверов.)


Подход с применением шардирования баз данных

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

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

Шардинг и репликация

Репликация

  • Многие приложения только читают данные (Правда многие из этих чтений идут из memcache или другого кэша)
  • Используем слейвы для выполнения чтений
  • Репликация асинхронна (Нужно аккуратно чтобы не читать старые данные; Слейвы могут быть на разных позициях)
  • Не помогает масштабировать запись (Слейвы обычно могут выдерживать меньше записей чем мастер так как выполняют записи в один поток)
  • Кэши слейвов обычно очень дублированы

Репли­ка­ция — это син­хрон­ное или асин­хрон­ное копи­ро­ва­ние дан­ных между несколь­кими сер­ве­ра­ми. Веду­щие сер­вера назы­вают масте­рами (master), а ведо­мые сер­вера — слэй­вами (slave). Мастера исполь­зу­ются для изме­не­ния дан­ных, а слэйвы — для счи­ты­ва­ния. В клас­си­че­ской схеме репли­ка­ции обычно один мастер и несколько слэй­вов, так как в боль­шей части веб-про­ек­тов опе­ра­ций чте­ния на несколько поряд­ков боль­ше, чем опе­ра­ций запи­си. Однако в более слож­ной схеме репли­ка­ции может быть и несколько масте­ров.

Шардинг

  • Когда функциональное разбиение и репликация не помогают
  • Разбиваем данные на маленькие кусочки и храним на многих серверах
  • “Единственное” решение для крупного масштаба
  • Нужно аккуратное планирование
  • Может быть не просто реализовать (Особенно если это не предусмотрено дизайном)
  • Как разбивать данные очень критичный вопрос (Часто бывает надо несколько копий данных с разным разбиением)

Шар­динг — это при­ем, кото­рый поз­во­ляет рас­пре­де­лять дан­ные между раз­ными физи­че­скими сер­ве­ра­ми. Про­цесс шар­динга пред­по­ла­гает раз­не­се­ния дан­ных между отдель­ными шар­дами на основе некого ключа шар­динга. Связанные одинаковым зна­че­нием ключа шар­динга сущности груп­пи­ру­ются в набор дан­ных по задан­ному клю­чу, а этот набор хра­нится в пре­де­лах одного физи­че­ского шар­да. Это суще­ственно облег­чает обра­ботку дан­ных.


Совместное использование

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

Шардинг и репликация — это популярные и мощные техники масштабирования систем работы с данными. Несмотря на примеры для MySQL, эти подходы универсальны и могут применяться для любой технологии.

SQL Azure Federations

Если приложение использует базы данных MS SQL, возникает несколько вопросов. Конечно первое что приходит в голову — организовать кластер из виртуальных машин SQL Server. Решение достаточно простое и хорошо всем знакомое. А что делать, если приложение использует базу данных как сервис (SaaS)? Что если мы не хотим заниматься настройкой кластера SQL Server? Конечно же, если мы говорим о Windows Azure, то в качестве SQL базы данных будет использоваться SQL Azure. Эта база данных поддерживает технологию горизонтального масштабирования (шардинг) называемую SQL Azure Federations. Принцип ее работы очень простой: логически независимые друг от друга строки одной таблицы хранятся в разных базах данных.

Ограничения SQL Azure

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

Увеличивается скорость выборки данных из базы, поскольку сам размер хранящихся в конкретном шарде данных на порядок меньше, чем суммарный объем базы. Однако, в любой технологии есть свои недостатки. Шардинг не исключение. Если вспомнить, архитектуру SQL Azure, то как известно сервис не поддерживает выборку данных из нескольких баз данных одновременно. То есть одна база данных — одно соединение. И шарды — не исключение. То есть, если допустим простейший запрос на возврат количества клиентов в базе данных необходимо выполнить на каждом шарде отдельно.

Исходный запрос:

SELECT Count(*) FROM Account

Пример запроса для конкретного шарда:

USE FEDERATION Accounts(AccountId = 4) WITH RESET, FILTERING = OFF
GO
SELECT Count(*) FROM Account

Логику же суммирования значений, возвращаемых этим запросом необходимо размещать в приложении. То есть в результате использования федераций часть кода «уйдет» в приложение, поскольку на уровне базы данных некоторые возможности обычного SQL Server ограничены.

Конечно SQL Azure Federations не является панацеей и можно реализовать свой принцип горизонтального масштабирования баз данных. Допустим multi-tenant подход — тоже своего рода горизонтальное масштабирование базы данных. Поскольку данные одного пользователя отделены не только «логически» от данных другого пользователя, но и «физически». Если необходимо добавить нового пользователя — мы конфигурируем для него отдельную базу данных. Вопрос в том, что в логике приложения должен быть механизм «роутинга». То есть приложение должно знать с какой базой данных оно в данный момент работает.

Сама задумка компании Microsoft хорошая. Было бы неплохо получить инструмент позволяющий легко масштабировать базу данных. Однако как правило, перед принятием окончательного решения перейти к использованию SQL Azure Federations, необходимо тщательно провести анализ существующей базы данных, либо продумать до мельчайших деталей архитектуру базы данных, которую будет использовать приложение, а также саму логику приложения по работе с этой базой.


Серверы баз данных, поддерживающие шардирование:

  • MongoDB

MongoDB поддерживает шардирование с версии 1.6.

  • Plugin for Grails

Grails поддерживает шардирование путем Grails Sharding Plugin.

  • Redis

Redis база данных с поддержкой шардирования на стороне клиента.

  • SQL Azure

Microsoft поддерживает шардирование в SQL Azure через «федерации».

Практически любой сервер баз данных может быть использован по схеме шардинга, при реализации соответствующего уровня абстракции на стороне клиента. К примеру eBay применяет серверы Oracle в режиме шардинга[1], Facebook[2] и Twitter[3] применяют шардирование поверх MySQL и т. д.

Ссылки