Архитектурные решения — фундамент любых приложений. В том числе и приложений с высокими нагрузками. Важно понимать, что архитектура Web приложения определяет 95% успешности его работы. В том числе способность справляться с нагрузками.
Разрабатывая успешное, а значит большое, Web приложение, необходимо разобраться в принципах построения крупных систем.
Вы никогда не знаете, что произойдет с приложением завтра. Возможно, количество ваших пользователей увеличиться в 5 раз. Возможно, резко начнет набирать популярность второстепенная функция. И она создаст новые проблемы. Чем больше будет становиться система, тем более сложным (= менее эффективным) будет становиться долгосрочное планирование.
Успешность работы над крупным приложением подразумевает вовсе не детальное планирование всех аспектов. Основное усилие должно быть направлено на обеспечение гибкости системы. Гибкость позволит быстро вносить изменения. Это наиболее важное свойство любой быстрорастущей системы.
Не пытайтесь спрогнозировать объем аудитории на год вперед. То же самое касается и архитектуры приложения. Основа успешной разработки — постепенные решения. Это применимо и к программной и к аппаратной части.
Если Вы запускаете новое приложение, нет смысла сразу обеспечивать инфраструктуру, которая способна выдержать миллионы посетителей. Используйте облака для хостинга новых проектов. Это позволит снизить затраты на сервера и упростить их управление.
Многие облачные хостинги предоставляют услуги приватной сети. Это позволит безопасно использовать несколько серверов прямо в облаке. Таким образом, вы сможете выполнять первые шаги в масштабировании без переезда на физику.
Простые решения разрабатывать крайне сложно. Тем не менее, лучше потратить время и усилия на упрощение решений (как для разработки так и для пользователей). Гибкая система не бывает сложной.
Работа над крупным проектом очень напоминает загрузку картинки формата Progressive JPEG. Вы двигаетесь не постепенно, а хаотично. Вам придется постоянно дорабатывать и переделывать разные решения, переключаться с одних на другие.
Применяйте правило 95% процентили:
Инвестируйте время только в обеспечение 95% функционала. Остальные 5% отбрасывайте — это частные случаи, которые ведут к усложнению системы.
Например:
Акцентируйте внимание на важном. Запомните, у вас всегда будет больше задач, чем времени на их решение. Ставьте приоритеты правильно — решайте те проблемы, которые возникают у большинства пользователей.
Масштабирование любого Web приложения — это постепенный процесс, который включает:
Новое приложение обычно запускается на одном сервере, на котором работают и Web сервер и база данных и само приложение:
Это разумно, т.к. это экономит время и деньги на запуск. Используйте именно такой подход для старта. Если боитесь не выдержать стартовую нагрузку — возьмите мощный сервер в аренду. Только в исключительных ситуациях, когда вы абсолютно точно уверены в большой стартовой нагрузке, переходите сразу к тому, что описано ниже.
Чаще всего, первым узлом, который оказывается под нагрузкой, является база данных. Это понятно. Каждый запрос от пользователя к приложению — это обычно от 10 до 100 запросов к базе данных:
Вынесение базы данных на отдельный сервер позволит увеличить ее производительность и снизить ее негативное влияние на остальные компоненты (PHP, Nginx и т.п.). Для подключения к MySQL на отдельном сервере используйте IP адрес этого сервера:
mysql_connect('10.10.0.2', 'user', 'pwd');
# 10.10.0.2 — IP адрес MySQL во внутренней сети
Перенос базы данных на другой сервер может стать проблемой для работающего приложения, т.к. займет какое-то время. Вы можете:
После выделения MySQL на отдельный сервер, убедитесь в его оптимальной настройке.
Масштабирование баз данных — одна из самых сложных задач во время роста проекта. Существует очень много практик — денормализация, репликации, шардинг и многие другие.
Далее на очереди Web сервер. Его выделение на отдельный узел позволит оставить больше ресурсов для приложения (в примере — PHP):
В этом случае Вам придется настроить deployment приложения и на сервер Nginx и на сервер с PHP. Сервер PHP обычно называют бекендом. Тогда Nginx будет отдавать файлы статики самостоятельно, а PHP сервер будет занят только обработкой скриптов. Nginx позволяет подключаться к бекенду по IP адресу:
server { server_name ruhighload.com; root /var/www/ruhighload; index index.php; location ~* .(php)$ { fastcgi_pass 10.10.10.1:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } }
# Все файлы статики Nginx будет отдавать без обращения на бекенд
Если Вы используете загрузку файлов, вам нужно будет выделить файловое хранилище на отдельный узел (об этом — ниже).
Когда нагрузка растет, Web приложение постепенно начинает работать все медленнее. В какой-то момент причина будет лежать уже в самой реализации. Тогда стоит установить несколько PHP бекендов:
Все бекенды важно иметь одинаковой конфигурации. Nginx умеет балансировать нагрузку между ними. Для этого Вам необходимо выделить список бекендов в upstream и использовать его в конфигурации:
upstream backend { server 10.10.10.1; server 10.10.10.2; server 10.10.10.3; } server { server_name ruhighload.com; root /var/www/ruhighload; index index.php; location ~* .(php)$ { fastcgi_pass backend; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } }
# Nginx будет равномерно распределять нагрузку между указанными бекендами
Вы можете использовать веса бекендов, если одни из них мощнее, чем другие:
upstream backend { server 10.10.10.1 weight=10; server 10.10.10.2 weight=2; server 10.10.10.3 weight=4; }
# Из каждых 16 запросов, первый бекенд обработает 10, второй — 2, а третий — 4
Как только вы начнете использовать несколько бекендов, запросы от одного пользователя будут попадать на разные сервера. Это потребует использования единого хранилища для сессий, например Memcache.
Подключение серверов кэширования — одна из самых простых задач:
Memcache обеспечивает использование нескольких серверов в стандартной поставке:
<? $m = new Memcache; $m->addServer('10.5.0.1'); $m->addServer('10.5.0.2'); ... $m->get('user1')
# Подключаем Memcache к нескольким серверам сразу
Memcache самостоятельно распределит нагрузку между используемыми серверами. Для этого он использует алгоритм постоянного хеширования. Вам понадобится следить за вытеснениями и вовремя добавлять новое оборудование.
Очереди задач позволяют выполнять тяжелые операции асинхронно, не замедляя основного приложения. Архитектурно это выглядит так:
Сервер очереди принимает задачи от приложения. Worker-сервера обрабатывают задачи. Их количество следует увеличивать, когда среднее количество задач в очереди будет постепенно расти.
DNS поддерживает балансировку на основе Round Robin. Это позволяет указать несколько IP адресов принимающих Web серверов (называются фронтендами):
Для использования этого механизма, необходимо установить несколько одинаковых фронтендов. Тогда в DNS следует указывать такие А записи:
.... ruhighload.com IN A 1.2.3.90 IN A 1.2.3.91 IN A 1.2.3.92
# Используем несколько IP адресов для одной А записи
В этом случае DNS будет отдавать разные IP адреса разным клиентам. Таким образом будет происходить балансировка между фронтендами.
Загрузка и обработка файлов обычно происходит на бекенде. Когда бекендов несколько, это неудобно:
Правильным решением будет использование отдельных серверов для загрузки, хранения и обработки файлов:
На практике это реализуется так:
Загрузку удобно перекладывать на клиентскую сторону. Тогда форма будет отправлять запрос на конкретный сервер:
<form action="http://images1.ruhighload.com/upload.php" method="post" enctype="multipart/form-data"> <input type="file" name="file"> <input type="submit" value="Загрузить"> </form>
Домены можно генерировать случайным образом из уже существующих:
<form action="http://images<?=mt_rand(1, 10)?>.ruhighload.com/upload.php" method="post" enctype="multipart/form-data"> ...
Прокси (proxy), или прокси-сервер — это программа-посредник, которая обеспечивает соединение между пользователем и интернет-ресурсом. Принцип…
Согласитесь, было бы неплохо соединить в одно сайт и приложение для смартфона. Если вы еще…
Повсеместное распространение смартфонов привело к огромному спросу на мобильные игры и приложения. Миллиарды пользователей гаджетов…
В перечне популярных чат-ботов с искусственным интеллектом Google Bard (Gemini) еще не пользуется такой популярностью…
Скрипт (англ. — сценарий), — это небольшая программа, как правило, для веб-интерфейса, выполняющая определенную задачу.…
Дедлайн (от англ. deadline — «крайний срок») — это конечная дата стачи проекта или задачи…