Записки погромиста

Записки погромиста на вольные темы

Масштабируем приложение от 0 до 100 тысяч пользователей.

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

Это хорошая проблема, но информация о том, как масштабировать веб-приложение от 0 до сотен тысяч пользователей, может быть скудной. Обычно решения приходят либо в результате массовых проблем, либо путем выявления узких мест (а часто и того, и другого).

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

Это попытка описать основы вокруг этой формулы в письменном виде. Мы собираемся сделать наш новый сайт обмена фотографиями Graminsta от 1 до 100 тысяч пользователей.

1 Пользователь: 1 Сервер.

Почти каждое приложение, как веб, так и мобильное, имеют три ключевых компонента — API, база данных и клиент (приложение или веб сайт). База данных хранит постоянные данные, API принимает и отправляет запросы и данные, клиент показывает данные пользователям и принимает пользовательский ввод.

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

Когда мы начинаем разработку приложения, нормально, что все три части работают на одном сервере. В любом случае, такой подход годится для среды разработки — один инженер работает на базой данных, API и клиентом.

В теории, можно загрузить это все в облако — DigitalOcean droplet или AWS EC2. С оглядкой на сказанное выше замечу, что если приложением пользуется хотя бы больше 1 человека, есть смысл вынести базу данных на отдельный сервер.

10 пользователей: отделяем слой базы данных.

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

100 пользователей: разделение клиентов.

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

Вот почему мне нравится думать о клиенте, как об отдельной сущности. Это позволяет охватить множество платформ — веб, мобильный веб, iOS, Android, десктоп и другие — они просто клиенты, которые используют тот же API.

1000 пользователей: добаляем Load Balancer.

Пользователи начинают активно пользоваться приложением, наш API уже не справляется с нагрузкой. Нам нужно больше вычислительной мощности!

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

Мы поместим балансировщик нагрзуки перед нашим веб клиентом и API и балансировщик нагрузки будет перенаправлять трафик на те экземпляры, которые в данный момент менее загружены.

Так же мы избаляемся от избыточности — когда один серверов упал, остальные экземпляры все в состоянии отвечать на запросы, вместо того, что бы упала вся система.

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

С помощью балансировщика нагрузки API можно масштабировать практически бесконечно — добавляя новые экземпляры сервера.

10000 пользователей: CDN.

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

Начиная с этого момента стоит использовать облачное хранилище для обслуживания статического контента, как например изображения, видео и т.п.

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

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

100000 пользователей масштабирование уровня базы данных.

Использование CDN сильно помогло нашему приложению. Нагрузка на наши сервера вполне приемлема, благодаря балансировщику нагрузки но… внезапно мы стали получать много таймаутов по запросам. Что случилось?

После некоторого расследования мы выяснили, что возможности нашей базы данных исчерпаны. Масштабирование этого уровня — самое сложное. В то время как наш API на множестве серверов обслуживает запросы, не хранящие состояние, этого нельзя сказать про большинство систем баз данных.

Кеширование.

Один из самых простых способов получить больше от нашей базы данных это новый компонент системы — уровень кеширования. Самый часто втсречаемый вариант такого решения это кэширования пары ключ-значение в памяти, например Redis или Memcached. Большинство облачных сервисов имеют свои решения для этого, например Elasticache в AWS или Memorystore в Google Cloud.

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

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

Реплики чтения.

Еще одно решение, которое может помочь нашей базе данных — добавление реплик чтения нашей базы данных. С помощью упомянутых выше сервисов это может быть сделано в один клик. Реплика для чтения будет синхронизирована с основной базой данных и доступна для SELECT  запросов. 

Что дальше.

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

Published by

Оставьте комментарий