Visitors have accessed this post 11261 times.

HighLoad архитектура для веб-приложения – все ли тут просто и однозначно?

1
0
11261
9 октября 2020 11:20
Автор: Rebrain Me
HighLoad

Visitors have accessed this post 11261 times.

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

На hackernoon.com нам встретилась статья о базовых тезисах построения высоконагруженной архитектуры. И мы попросили прокомментировать их, согласиться или поспорить, эксперта по работе с высоконагруженными системами Александра Пряхина. Александр — технический директор E-Commerce проекта с серьезным бэкграундом разработки и технического обеспечения высоконагруженных веб-приложений и руководитель нашей программы “Архитектор высоких нагрузок”.

Первоисточник статьи https://hackernoon.com/how-to-build-a-high-load-architecture-for-your-web-application-hf2n32wg. Автор статьи – Arslan, fullstack разработчик, Project Manager, Software Engineer.

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

Помните всеми любимые Черные пятницы? Вы знаете, что иногда сайты и приложения оказываются не способны выдержать большой наплыв пользователей и теряют много денег из-за этого?

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

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

[Комментарий Александра Пряхина]: В целом — правильные вещи. Но не нужно забывать о том, что для маленького проекта можно настолько удариться в архитектуру, что все деньги будут улетать только на нее. Важным аспектом является построение не конечной архитектуры, которая будет выдерживать N тысяч соединений в секунду, а архитектуры, которая будет готова к росту с минимальными вложениями, принимая ровно столько клиентов, сколько нужно здесь и сейчас. Впрочем, об этом ниже в статье.

——

Вот некоторые факты о высоких нагрузках

  • Высокие нагрузки начинаются, когда один сервер перестает эффективно выполнять обработку данных.
  • Если один сервис одновременно обслуживает 10 тысяч подключений – это высокая нагрузка.
  • Высокая нагрузка — это одновременное обслуживание тысяч и миллионов пользователей.
  • Если вы разворачиваете веб-приложение на AWS (Amazon Web Services), Microsoft Azure, или Google Cloud Platform, вы используете архитектуру HighLoad.

[Комментарий Александра Пряхина]: Очень смелые заявления, которые превращают в Highload все подряд. Да, первое утверждение верно, особенно если под эффективностью обработки понимать скорость. Но Highload — это всегда относительное понятие. И он может быть как на сервере со 128 мегабайтами памяти, которому надо достаточно быстро обработать свои несколько запросов, так и на гигантском кластере, принимающем огромные потоки трафика. Поэтому 10 тысяч подключений будут Highload-ом далеко не для каждой инфраструктуры.

——

Проблемы, с которыми вы можете столкнуться, если ваше веб-приложение не справляется с высокими нагрузками:

  •         Медленная или бесконечная загрузка страниц
  •         Случайные ошибки
  •         Обрыв соединения с сервером
  •         Неполная загрузка контента
  •         Снижение активности пользователей
  •         Потеря покупателей

Как вы видите, архитектура проекта определяет его успешность. Нет счастливых покупателей – нет успеха и прибыли. Чтобы реализовать масштабируемые веб-приложения, вам нужно понимать принципы разработки высокопроизводительных программных решений.

[Комментарий Александра Пряхина]: Да, фундамент системы во многом влияет на ее прибыльность. И тут стоит добавить, что нужно понимать не только принципы разработки высокопроизводительных программных решений, но и принципы работы окружения в целом, чтобы не наплодить зоопарк хайповых прикладных решений с пометкой Highload.

——

Принципы построения высокопроизводительных решений

  1.   Гибкость и динамичность

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

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

[Комментарий Александра Пряхина]: Совершенно верно. Вначале надо закладываться именно на гибкость, а не на конкретную пропускную способность. Гибкость даст возможность наращивать эти цифры в будущем.

——

  1.   Постепенный рост проекта

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

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

Размещайте новые проекты в облаке, поскольку это позволяет снизить затраты на сервера, упростить управление проектами и процесс деплоя приложений.

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

Масштабирование веб-приложения – это постепенный процесс, который включает 4 основных шага

  •         Анализ нагрузки
  •         Выявление наиболее нагруженных участков
  •         Перенос их на отдельные ноды и оптимизация
  •         Анализ нагрузки после этих мер

[Комментарий Александра Пряхина]: Совет про облака тоже довольно смелый. Не всегда оно будет дешевле, чем другие виды хостинга. Да, расти в облаках проще, но на бюджете это может отразиться не очень позитивно. Также нужно помнить, что многие облака могут дать суровый vendor-lock, что в реалиях блокировок может навредить. Я бы рекомендовал ориентироваться больше на правильный пайплайн CI/CD, который позволит доставлять приложение на любую выбранную платформу.

Частные облака — это вообще совершенно другой уровень расходов. И рекомендовать его растущей компании я бы не стал.

——

Разработка масштабируемой архитектуры веб-проекта

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

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

[Комментарий Александра Пряхина]: Тут есть противоречие. Автор сначала советует брать мощный сервер, а ниже рекомендует отделять БД от приложения. Брать один мощный сервер в самом начале — не самая лучшая идея. Как раз здесь философия облачных сервисов помогает набирать и оплачивать ровно столько ресурсов, сколько будет использоваться. Огромный мощный сервер же часто будет давать процентов 80 простоя.

——

Отделение базы данных

Чаще всего первая нода под нагрузками – это база данных. Каждый запрос от пользователя к приложению обычно включает от 10 до 100 запросов к базе данных. Расположение базы данных на отдельном сервере повысит ее производительность и уменьшит ее негативное влияние на скорость работы других компонентов (PHP, Nginx и т. д.).

[Комментарий Александра Пряхина]: Факт, с которым не поспоришь. БД нужен отдельный сервер, если у вас что-то отличное от homepage.

——

Перенос базы данных

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

  • Используйте простое решение – разместите на сайте объявление о планируемых работах. И лучше провести миграцию ночью, когда пользовательская активность минимальна.
  • Используйте репликацию, чтобы синхронизировать данные с одного сервера с другим. После миграции вам нужно будет изменить IP-адрес в приложении на адрес нового сервера. А потом – отключить старый сервер.

[Комментарий Александра Пряхина]: В первом случае обязательно стоит вспомнить о том, что простой не всегда допустим. Что если ваше приложение обслуживает разные часовые пояса? А вот совет с репликацией вполне себе рабочий. И часто стоит делать несколько репликаций 

  •         для разделения потоков записи и чтения,
  •         для бэкапирования,
  •         для горячей замены.

И да, такое решение даст прирост в скорости при размещении БД и логики рядом, нивелируя накладные расходы на передачу по сети.

——

Разделение веб-сервера

Далее отделяйте веб-сервер от логики. Выделение его в отдельную ноду позволит оставить больше ресурсов для приложения. Говоря о примере с PHP, вы должны настроить деплой продукта на оба сервера — Nginx и PHP-FPM, представляющих backend.

Nginx быстро передаст статичные файлы, а PHP-FPM будет занят только скриптами. 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 и PHP-FPM стоит на поздних этапах развития, когда есть понимание того, что логика требует выделенного ресурса. Вначале это скорее навредит.

А вот выделение на отдельный сервер балансировщика на базе Nginx, о чем написано ниже, вполне имеет смысл.

——

Используйте несколько бэкэндов

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

При установке бэкэндов убедитесь, что они имеют одинаковую конфигурацию. Используйте Nginx, чтобы сбалансировать нагрузку между ними. Для этого вы должны определить список приоритетных бэкэндов и использовать его в конфигурации:

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;

}

}

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

[Комментарий Александра Пряхина]: Решение простое, «в лоб», но, тем не менее, рабочее. Вот только автор забыл рассказать про несколько важных аспектов: 

  1. Бэкэнд-сервера должны собираться автоматически (тем же Ansible), чтобы быть одинаковыми по конфигурации.
  2. Между балансировщиком и бэкэндами должен быть настроен процесс проверки доступности бэкэндов (Heartbeat). Иначе вышедший из строя бэкэнд будет отдавать балансировщику ошибку.
  3. Сервера вполне могут быть разными по железу — балансировка Nginx позволяет расставлять веса, направляя больше трафика на более мощную ноду.
  4. Nginx — это не единственный и не самый гибкий способ балансировки. HAProxy, например, тоже неплохо занимается этой задачей. А в облаках есть свои балансировщики. Например, ELB в AWS.
  5. Если балансировщик Nginx выходит из строя, это положит весь продукт. Поэтому балансировщик становится точкой отказа. И пункт ниже поможет работать с кластером балансировки.

——

Очередность задач и балансировка DNS

Очередность задач позволяет асинхронно выполнять «тяжелые» операции, не замедляя работу основного приложения. Пока сервер очередей будет получать задачи из веб-решения, другие серверы будут обрабатывать их. Если среднее количество задач в очереди будет расти, увеличьте количество серверов, чтобы сбалансировать нагрузку.

DNS поддерживает балансировку на основе Round Robin, позволяя указывать несколько IP-адресов принимающих веб-серверов, называемых веб-интерфейсами. Здесь вам необходимо установить несколько идентичных внешних интерфейсов, чтобы DNS давал разные IP-адреса разным клиентам. Таким образом, вы обеспечите баланс между внешними интерфейсами.

[Комментарий Александра Пряхина]: Довольно странно, что автор объединил эти два пункта.

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

DNS-балансировку стоит применять как раз относительно балансировщиков, стоящих перед бэкэндами. И это будет одним из способов для нивелирования проблемы единой точки отказа.

——

Хранилища файлов

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

Более того, они могут снизить производительность бэкэнда. Чтобы избежать таких трудностей, вы должны использовать отдельные сервера для загрузки, хранения и обработки файлов.

Вы можете сделать это следующим образом

  • Выделить отдельный поддомен для файлового сервера.
  • Развернуть на сервере Nginx и небольшое приложение для хранения и обработки файлов.
  • Масштабироваться, добавив новые сервера и поддомены (например, images1, images2, images3 и т.д.).
  • Передать загрузку файла на сторону клиента, чтобы форма отправляла запрос на определенный сервер.

[Комментарий Александра Пряхина]: Неплохой совет. Тут стоит вспомнить о том, что есть также решения типа AWS S3, который дает такое хранилище по очень низкой цене. И это в большинстве случаев будет самым дешевым решением.

——

Нет ничего сложного в создании приложения, которое пропорционально масштабируется по серверам по мере роста потока трафика. Все части стоит делать Stateless, учитывать балансировка нагрузки, кэширование на 90%, надежная сеть для доставки контента — и у вас HighLoad архитектура.

[Комментарий Александра Пряхина]: А вот чему я удивлен, так это минимальному упоминанию в статье CDN и кэширования.

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

——

Тем не менее, ключевой фактор – это оценка эффективности затрат. Скажем, у вас есть 100 тысяч пользователей и один сервер. Значит, чтобы стало 130 тысяч, вам нужен дополнительный сервер? Слишком сложно, не правда ли?

Таким образом, вы должны сделать один шаг назад и подумать — какая часть системы вызывает проблемы? Если это база данных, выберите масштабируемую базу данных перед началом разработки проекта. Или вы можете использовать несколько баз данных, например, одну для записи и одну для чтения (CQRS).

Определение и решение таких проблем производительности заблаговременно и без значительного увеличения затрат на инфраструктуру – это и есть эффективная практика обеспечения высокой нагрузки.

Кстати, будем рады в комментариях вашему мнению — какие пункты вам кажутся спорными, а с какими вы согласны?

От редакции

Если вам интересно посещать открытые онлайн-мероприятия по DevOps, Kubernetes, Docker, GitlabCI и др. и задавать вопросы в режиме реального времени, подключайтесь к каналу DevOps by REBRAIN*Анонсы мероприятий каждую неделю

Практикумы для специалистов по инфраструктуре и разработчиков — https://rebrainme.com.
Наш Youtube-канал — https://www.youtube.com/channel/UC6uIx64IFKMVmj12gKtSgBQ.

Агентство Fevlake, проектируем и поддерживаем IT-инфраструктуры с 2012 года — https://fevlake.com.

Комментарии (3)
Введено символов из возможных
Не отвечать

Вам также может понравится

7 шагов HighLoad
array(1) { [0]=> object(WP_Term)#11166 (16) { ["term_id"]=> int(9) ["name"]=> string(8) "HighLoad" ["slug"]=> string(8) "highload" ["term_group"]=> int(0) ["term_taxonomy_id"]=> int(9) ["taxonomy"]=> string(8) "category" ["description"]=> string(0) "" ["parent"]=> int(0) ["count"]=> int(3) ["filter"]=> string(3) "raw" ["cat_ID"]=> int(9) ["category_count"]=> int(3) ["category_description"]=> string(0) "" ["cat_name"]=> string(8) "HighLoad" ["category_nicename"]=> string(8) "highload" ["category_parent"]=> int(0) } } HighLoad

Автор - Александр Пряхин

Все! Хочу работать с высоконагруженными системами, - решили вы. Начинаю учиться.

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

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

0
0
4 декабря 2020
Sandboxing Nginx
array(1) { [0]=> object(WP_Term)#11166 (16) { ["term_id"]=> int(7) ["name"]=> string(6) "DevOps" ["slug"]=> string(6) "devops" ["term_group"]=> int(0) ["term_taxonomy_id"]=> int(7) ["taxonomy"]=> string(8) "category" ["description"]=> string(0) "" ["parent"]=> int(0) ["count"]=> int(19) ["filter"]=> string(3) "raw" ["cat_ID"]=> int(7) ["category_count"]=> int(19) ["category_description"]=> string(0) "" ["cat_name"]=> string(6) "DevOps" ["category_nicename"]=> string(6) "devops" ["category_parent"]=> int(0) } } DevOps

Автор - Юрий Изоркин

В конце 2018 года мне на глаза попался пул-реквест, который позволял запускать сервис nginx от непривилегированного пользователя - https://github.com/NixOS/nixpkgs/pull/51551 - nginx: do not run anything as root. Это повышает защиту web-сервера nginx.

При каждом запуске сервиса nginx происходит проверка конфигурации на...

4
0
13 ноября 2020
Инструменты DevOps
array(1) { [0]=> object(WP_Term)#11545 (16) { ["term_id"]=> int(7) ["name"]=> string(6) "DevOps" ["slug"]=> string(6) "devops" ["term_group"]=> int(0) ["term_taxonomy_id"]=> int(7) ["taxonomy"]=> string(8) "category" ["description"]=> string(0) "" ["parent"]=> int(0) ["count"]=> int(19) ["filter"]=> string(3) "raw" ["cat_ID"]=> int(7) ["category_count"]=> int(19) ["category_description"]=> string(0) "" ["cat_name"]=> string(6) "DevOps" ["category_nicename"]=> string(6) "devops" ["category_parent"]=> int(0) } } DevOps

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

7
0
16 октября 2020