¬ интернете можно найти множество статей с описанием шаблонов масштабировани€ баз данных (Ѕƒ), но, в основном, это разрозненна€ информаци€ с перечислением методик и практически без объ€снений.

Ќиже приведено подробное руководство по шаблонам масштабировани€ Ѕƒ, пошаговым объ€снением принципов их работы и примерами использовани€.

DevOps

ѕрактический пример

ѕредположим, вы создали стартап, который предлагает совместные поездки по дешевой цене. ¬ы выбрали город дл€ поездок, а перва€ реклама привлекла не более 10 клиентов.

¬ы храните информацию обо всех клиентах, поездках, местах, бронировани€х и истори€х заказов в одной и той же Ѕƒ и, скорее всего, на одной физической машине. ” вас нет навороченного кешировани€ или конвейера обработки больших данных, ведь ваше приложение только по€вилось. Ќа данный момент это Ц идеальный вариант: в базе мало клиентов, и система, вр€д ли, бронирует по поездке каждые 5 минут.

Ќо врем€ идет. ¬ вашей системе регистрируетс€ все больше людей, ведь это самый дешевый сервис на рынке. ƒа и реклама сделала свое дело. ¬ы получаете по 10 заказов в минуту. ѕостепенно это количество увеличиваетс€ до 20, а затем и 30 бронирований в минуту.

¬ этот момент вы замечаете, что система начинает тормозить: врем€ отклика API сильно увеличилось, а некоторые транзакции блокируютс€ или зависают и, в конечном итоге, не проход€т. ¬рем€ ответа приложени€ также увеличилось, что вызвало недовольство клиентов.  ак же решить эту проблему?


Ўаблон є1 Ц оптимизаци€ запросов и реализаци€ пула соединений

ѕервое решение, которое приходит на ум: кэш слишком часто использует нединамические данные (истори€ бронировани€, истори€ платежей, профили пользователей и т.д.). Ќо прикладным уровнем кешировани€ вы не сможете решить проблему с временем отклика API, предоставл€ющим динамические данные (текущее местоположение водител€, ближайша€ машина дл€ конкретного клиента, текуща€ стоимость поездки после выхода на маршрут и т.д.).

¬ы приходите к выводу, что база данных слишком нормализована, поэтому вы решаете ее немного Ђразбавитьї и добавл€ете несколько избыточных столбцов (такие столбцы часто попадают в операторы WHERE или JOIN ON в запросах). Ёто сокращает количество запросов на соединение, разбивает большие запросы на несколько маленьких и добавл€ет их результаты на прикладной уровень.

ћожно зан€тьс€ и параллельной оптимизацией Ц настроить подключени€ к базам данных. ¬нешние и клиентские библиотеки Ѕƒ доступны практически дл€ всех €зыков программировани€. ƒл€ кешировани€ подключений к Ѕƒ можно воспользоватьс€ библиотеками пула соединений. Ћибо вы можете настроить размер пула соединений в самой —”Ѕƒ.

—оздание сетевого подключени€ Ц вещь весьма затратна€, поскольку требует двусторонней коммуникации между клиентом и сервером. ѕулы соединений помогают оптимизировать количество подключений. Ѕиблиотеки пула соединений реализуют мультиплексирование подключений Ц несколько потоков приложени€ могут пользоватьс€ одним и тем же подключением.

¬ы замер€ете врем€ отклика API и замечаете снижение задержки на 20-50% (или даже больше). Ќа данный момент это хороша€ оптимизаци€.

«атем вы расширили бизнес на еще один город и получили больше клиентов. ѕостепенно вы доходите до 80-100 бронирований в минуту. ¬аша система не в состо€нии справитьс€ с таким объемом. ¬ы вновь замечаете увеличение времени ожидани€ API, а слой базы данных не справл€етс€ с нагрузкой. Ќо в этот раз оптимизаци€ запросов не дает вам существенного улучшени€ производительности. ¬ы провер€ете метрики системы и видите, что дисковое пространство заполнено, ÷ѕ зан€т в 80% времени, а ќ«” переполн€етс€ слишком быстро.


Ўаблон є 2 Ц вертикальное масштабирование или масштабирование вверх

»зучив все системные метрики, вы не находите другого решени€, кроме как обновить аппаратное обеспечение системы. ¬ы увеличиваете размер оперативной пам€ти в 2 раза, а объем диска Ц раза в 3. Ёто называетс€ вертикальным масштабированием. ¬ы сообщаете группе по обслуживанию инфраструктуры, команде devops или агентам сторонних центров обработки данных (÷ќƒ) о необходимости обновлени€ вашей машины.

Ќо как настроить саму машину дл€ вертикального масштабировани€?

¬ы выдел€ете машину большего объема. ќдин из подходов заключаетс€ в том, чтобы не переносить данные со старой машины вручную, а настроить новую машину в качестве копии, или реплики (replica), уже существующего устройства, или источника (primary), прописав временную конфигурацию первичной реплики (primary replica). ѕосле завершени€ репликации назначьте новую машину в качестве primary и отключите старую. ѕоскольку обрабатывать запросы планируетс€ на этой новой машине, все чтение/запись также будет вестись на ней.

ќтлично. ¬ы прокачали систему, и теперь все работает намного быстрее.

¬аш бизнес идет на ура, и вы решаете расширитьс€ еще до 3 городов. “еперь вы ведете де€тельность в 5 городах. “рафик увеличилс€ втрое, вы получаете по 300 заказов в минуту. ѕроблема с производительностью вернулась: размер индекса сильно сказываетс€ на пам€ти, базу данных необходимо посто€нно поддерживать, а сканирование таблицы с индексом замедлилось до невозможности. ¬ы подсчитали стоимость дальнейшего масштабировани€ системы, но цена не внушает довери€. “ак что же делать?


Ўаблон є3 Ц разделение ответственности на команды и запросы (CQRS):

¬ы понимаете, что та сама€ больша€ машина не в состо€нии обработать все запросы на чтение/запись. ƒа и чаще всего компани€м нужны транзакционные возможности на запись (write), а не чтение (read). ¬ас даже устраивает небольша€ несогласованность данных или замедление операций read. ¬ принципе, раньше это тоже не казалось вам проблемой. ¬ы решаете, что неплохо было бы разделить операции чтени€ и записи на физической машине. Ёто позволит отдельным машинам выполн€ть больше операций чтени€/записи.

“еперь вы берете целых 2 большие машины и настраиваете их репликами дл€ текущего компьютера. –епликаци€ базы данных решит вопрос с переносом данных с primary машины на реплики. ¬ы перенаправл€ете все запросы на чтение (буква Q в CQRS, что означает Ђзапросї - Query) в реплики Ц люба€ реплика может обслуживать любой запрос на чтение. ј все запросы на запись остаютс€ на первичной машине. ¬озможна небольша€ задержка в репликации, но в вашем конкретном случае это не критично.

¬ариант с настройкой primary-replica вполне подходит дл€ большинства стартапов среднего масштаба, получающих по сотн€м тыс€ч запросов ежедневноЕ но при условии, что компании периодически архивируют старые данные.

¬ы вновь расширились на 2 города, и замечаете, что primary-машина не справл€етс€ со всеми запросами на запись. ћногие такие запросы приход€т с опозданием. Ѕолее того, задержка между primary и replica начинает сказыватьс€ на клиентах и водител€х. Ќапример, поездка завершена, клиент успешно ее оплачивает, но водитель не видит платеж, поскольку активность клиента Ц это запрос на запись, который идет на машину primary, а активность водител€ Ц это запрос на чтение, который приходит на одну из реплик. ¬с€ система настолько замедлилась, что водитель не видит платежа как минимум секунд 30, и это вызывает недовольство как со стороны клиента, так и у самого водител€.  ак же поступить сейчас?


Ўаблон є4 Ц репликаци€ с несколькими источниками

 онфигураци€ primary-replica помогла вам успешно масштабироватьс€, однако теперь дл€ операций записи не хватает возможностей. Ѕыть может, вы согласитесь слегка пожертвовать быстротой запросов на чтение. ј почему бы не перенести запросы на запись тоже в реплики?

¬ модели с несколькими источниками (multi-primary) все машины работают как источник, и как реплика. “ака€ структура чем-то напоминает замкнутый круг из машин: A->B->C->D->A. ЂBї может реплицировать данные из ЂAї, ЂCї Ц реплицирует данные из Ђ¬ї, ЂDї Ц дублирует данные из ЂCї, а ЂAї делает тоже самое из ЂDї. ¬ы можете выполн€ть операцию чтени€ и одновременно записывать данные в любой узел; вы можете транслировать запрос во все узлы, а значение вернет один из откликнувшихс€ узлов. ¬се узлы имеют одинаковую схему Ѕƒ, один и тот же набор таблиц, индекс и т.д. Ќо нужно следить, чтобы в узлах одной таблицы не было конфликта по id , иначе при трансл€ции запросов несколько узлов вернут разные данные по одному и тому же id.

¬ообще считаетс€, что дл€ ID лучше использовать UUID или GUID. ≈ще один недочет данной системы: из-за трансл€ции запросов и поиска корректного результата, запросы на чтение могут оказатьс€ неэффективными. Ёто, своего рода, принцип распределени€/сборки в действии.

» вот вы вновь масштабировали бизнес. ¬ этот раз на 5 новых городов. —истема не справл€етс€. “еперь вам нужно обрабатывать по 50 запросов в секунду. ¬ам очень не хватает обработки большого количества параллельных запросов. Ќо как это сделать?


Ўаблон є5 Ц декомпозици€

¬ы знаете, что база данных location получает много трафика на чтение/запись. ¬полне возможно, что соотношение записи к чтению составл€ет 7:3. Ёто создает большую нагрузку на существующие Ѕƒ. ¬ таблицах location содержитс€ несколько первичных данных: долгота (longitude), широта (latitude), отметка времени (timestamp), ID водител€ (driver id), ID поездки (trip id) и т.д.

“ам практически нет информации о поездках или данных пользовател€, его платежах и т.д. ¬озможно, стоит разделить таблицы location на отдельную схему?  ак насчет того, чтобы распределить эту Ѕƒ по отдельным машинам с корректно настроенной конфигурацией primary-replica или multi-primary?

Ёто называетс€ декомпозицией данных по функциональности. ¬ разных Ѕƒ можно хранить данные, разделенные по функциональному признаку, а результат (при необходимости) агрегируетс€ на серверном уровне. “акой способ позволит вам масштабировать нужный функционал с большим количеством запросов на чтение/запись. ¬ то же врем€ прикладной или серверный уровень приложени€ должен будет зан€тьс€ объединением результатов, что приведет к значительному изменению кода.

“еперь представьте себе, что вы масштабировались до 20 городов в своей стране и планируете открыть филиалы в јвстралии. –астущий спрос на ваше приложение требует все более быстрого времени ответа. Ќи один из методов выше с этим не поможет. ¬ам нужно масштабировать систему так, чтобы при расширении в другие страны/регионы не приходилось слишком часто проектировать и мен€ть архитектуру.  ак же тогда поступить?


Ўаблон є6 Ц горизонтальное масштабирование

¬ы хорошо загуглили эту тему, почитали массу статей о том, как другие компании решали такую проблему, и пон€ли, что настал момент масштабироватьс€ горизонтально. ¬ы выделили, скажем, 50 машин Ц все с одинаковой схемой Ѕƒ и одинаковыми наборами таблиц. Ќа каждой машине хранитс€ лишь часть данных.

ѕоскольку во всех Ѕƒ хранитс€ один и тот же набор таблиц, вы можете спроектировать систему таким образом, чтобы реализовать прив€зку данных (то есть все св€занные данные хран€тс€ на одной машине). ¬ каждой машине может быть сво€ реплика; реплики используютс€ дл€ восстановлени€ после сбо€.  ажда€ така€ база данных называетс€ Ђшардомї. Ќа физической машине может быть один или несколько шардов Ц их количество зависит от нужной вам схемы проектировани€. ¬ы должны придумать ключ шардировани€, который бы всегда относилс€ к одной и той же машине. ѕредставьте себе много машин с кучей св€занных данных в одном наборе таблиц; операции на чтение/запись запрашиваютс€ дл€ одной и той же строки или набора ресурсов на одной и той же машине с Ѕƒ.

–еализовать шардинг довольно сложно. ѕо крайней мере, так говор€т инженеры. Ќо при обслуживании миллионов или даже миллиардов запросов, рано или поздно вам придетс€ пойти на столь непростой шаг.

Ќастроив шардинг, вы уверены, что сможете масштабироватьс€ во многие страны. ¬аш бизнес разросс€ настолько, что инвесторы вынуждают вас расшир€тьс€ на другие континенты. » тут оп€ть возникают проблемы. ¬се то же врем€ отклика API. ¬аш сервис находитс€ в —Ўј, и у пользователей из ¬ьетнама возникают трудности при бронировании. Ќо почему? » что же делать?


Ўаблон є7 Ц умное сегментирование центров обработки данных

¬аш бизнес развиваетс€ в јмерике, ёжной јзии и нескольких странах ≈вропы.  аждый день вы получаете миллионы заказов, а ваш сервер атакуют миллиарды запросов. ѕоздравл€ю! Ёто пиковый момент в вашей де€тельности.

«апросы из приложени€ поступают с разных континентов и проход€т через сотни или даже тыс€чи серверов в интернете, поэтому врем€ отклика растет. ћожет, распределить трафик по центрам обработки данных? ¬ы могли бы настроить ÷ќƒ в —ингапуре, и он бы обрабатывал все запросы из ёжной јзии. «атем сделать еще один в √ермании Ц он займетс€ всеми запросами из европейских стран, и оставить ÷ќƒ в  алифорнии дл€ обработки американских запросов.

 роме того, вам понадобитс€ репликаци€ между ÷ќƒ Ц на случай, если потребуетс€ восстановление после сбо€. ≈сли центр обработки данных в  алифорнии выполн€ет репликацию сингапурского ÷ќƒ, то в случае аварии в  алифорнии (стихийные бедстви€, отсутствие электричества и т.д.), все запросы из —Ўј будут передаватьс€ в —ингапур и наоборот.

“акой метод масштабировани€ подходит дл€: обслуживани€ миллионов клиентов из разных стран, сохранени€ всех данных и поддержани€ посто€нной доступности системы.


«аключение

¬ статье приведены общие методы по масштабированию базы данных. —тоит сказать, что у большинства инженеров нет достаточных возможностей дл€ реализации всех шаблонов. Ќо лучше знать о существовании таких схем, которые в будущем могут помочь вам с проектированием архитектуры и систем.


—кидки 50% в Merion Academy

¬ыбрать курс