Сложности и ошибки проектирований высоконагруженных приложений
Этот урок — подведение итогов изученного материала, касающегося проектирования высоконагруженных приложений. Здесь вы рассмотрите самые распространённые ошибки, которые допускают разработчики при увеличении нагрузки на систему. Понимание этих проблем позволит вам заранее их предвидеть и избегать.
Вы также разберёте кейсы реальных компаний, которые успешно справились с этими вызовами, и рассмотрите решения для преодоления трудностей, связанных с ростом нагрузки.
Распространённые проблемы высоконагруженных приложений
Проблемы и ошибки, которые возникают при разработке, бывают разными. Они могут появляться независимо, а могут выявляться в комплексе. Наша задача — как можно раньше их выявлять и предлагать их решение. Разберём самые популярные ошибки. Их всего семь.
1. Неправильный выбор технологий
При проектировании высоконагруженной системы важно уделить внимание изучению и выбору подходящих технологий. Для этого нужно провести тестирование и определить, соответствует ли технология конкретно вашим задачам.
Например, сервис Dropbox изначально использовал Python для своей платформы, но с ростом пользовательской базы перешёл на Go для определённых компонентов, чтобы улучшить производительность и эффективность. Это отняло много времени и ресурсов, но дало свои плоды.
2. Недооценка нагрузки и некорректное тестирование
Недостаточно реалистичное тестирование нагрузки ведёт к неожиданным сбоям в производственной среде. Понятно, что не всегда можно предугадать, с какой нагрузкой столкнётся система. Но стоит сделать всё возможное, чтобы определить точные НФТ.
Например, приложение Pokemon Go столкнулось с серьёзными проблемами масштабируемости и доступности в первые дни после запуска из-за недооценки популярности игры и последующей высокой нагрузки на серверы.
3. Неэффективное использование ресурсов
Неоптимальное использование вычислительных мощностей, памяти или других ресурсов, ведущее к избыточным расходам и снижению производительности. Также нужно помнить о том, что ресурсы не бесконечны. Чем больше ваша система потребляет ресурсов, тем дороже она обходится и тем меньше она полезна для бизнеса.
Поэтому необходимо уделять достаточное внимание оптимизации производительности и регулярно выполнять нагрузочное тестирование. Часто проблема решается с помощью использования оборудования и паттернов, которые подходят под ваши сценарии нагрузки.
Например, Instagram* в своё время перешёл с облачной инфраструктуры Amazon EC2 на высокопроизводительные серверы Facebook*, что позволило оптимизировать использование ресурсов и улучшить производительность их сервисов.
4. Пренебрежение оптимизацией запросов к базе данных
Сложные или неправильно оптимизированные запросы к базе данных — одна из самых распространённых ошибок, которые в итоге приводят к высоким задержкам и неэффективному использованию ресурсов.
Нужно использовать средства анализа планов запросов. Существует множество техник и подходов: от оптимизации отдельных запросов и индексирования до рефакторинга всей схемы БД.
Например, LinkedIn столкнулся с проблемами производительности из-за неоптимизированных запросов SQL. Из-за этого компания внедрила специализированные инструменты для анализа и оптимизации запросов, что позволило обрабатывать ей тысячи запросов в секунду.
5. Игнорирование пользовательского опыта при проектировании API
Создание API без учёта удобства и эффективности использования приводит к снижению производительности клиентских приложений. Эту ошибку вы уже разбирали в уроках о проектировании front-to-back взаимодействий. Однако она довольна распространена, поэтому всегда анализируйте, насколько ваш API подходит под пользовательские сценарии.
Например, Slack значительно улучшил производительность своего API, пересмотрев методы и структуру запросов/ответов, используя в том числе GraphQL для сокращения количества запросов и объёма передаваемых данных.
6. Недооценка тестирования
Недостаточное или неполное тестирование системы, особенно в плане нагрузочного тестирования. В случае некачественного тестирования вам будет сложно предсказать, какие узкие места «выстрелят» у приложения в производственной среде. Покрытие тестированием должно стремиться к 100%-му объёму функционала. Если такой возможности нет, то необходимо выделить критичный для системы функционал и сконцентрироваться на нём. Тестирование не должно проходить для «галочки»: это важный инструмент, который позволяет не «тушить пожары» на проде.
Например, компания Twitter после выхода каждой новой версии приложения проводит симуляцию реального трафика и нагрузочное тестирование для предотвращения сбоев.
7. Неверная декомпозиция системы
Часто системы сталкиваются с излишним потреблением ресурсов, которые связаны с неверной декомпозицией системы. Это проявляется из-за слишком гранулярной декомпозиции, что приводит к высоким накладным расходам на обмен данными между компонентами. Также узкие места появляются из-за неверно выбранных границ ответственности, когда функциональность одного компонента «просачивается» в другие. Это приводит к циклическим зависимостям, которые усложняют масштабирование системы.
Например, приложение Amazon Prime Video столкнулось с проблемой слишком гранулярной декомпозиции, которая привела к избыточному взаимодействию между компонентами. В результате компания понесла высокие издержки на ресурсы сети и хранения. После объединения некоторых компонентов команде сервиса удалось сократить затраты на ресурсы почти на 90%.
При проектировании высоконагруженной системы важно уделить внимание изучению и выбору подходящих технологий. Для этого нужно провести тестирование и определить, соответствует ли технология конкретно вашим задачам.
Недостаточно реалистичное тестирование нагрузки ведёт к неожиданным сбоям в производственной среде. Понятно, что не всегда можно предугадать, с какой нагрузкой столкнётся система. Но стоит сделать всё возможное, чтобы определить точные НФТ.
Неоптимальное использование вычислительных мощностей, памяти или других ресурсов, ведущее к избыточным расходам и снижению производительности. Также нужно помнить о том, что ресурсы не бесконечны. Чем больше ваша система потребляет ресурсов, тем дороже она обходится и тем меньше она полезна для бизнеса.
Сложные или неправильно оптимизированные запросы к базе данных — одна из самых распространённых ошибок, которые в итоге приводят к высоким задержкам и неэффективному использованию ресурсов.
Создание API без учёта удобства и эффективности использования приводит к снижению производительности клиентских приложений. Всегда анализируйте, насколько ваш API подходит под пользовательские сценарии.
Недостаточное или неполное тестирование системы, особенно в плане нагрузочного тестирования. В случае некачественного тестирования вам будет сложно предсказать, какие узкие места «выстрелят» у приложения в производственной среде. Покрытие тестированием должно стремиться к 100%-му объёму функционала.
Часто системы сталкиваются с излишним потреблением ресурсов, которые связаны с неверной декомпозицией системы. Это проявляется из-за слишком гранулярной декомпозиции, что приводит к высоким накладным расходам на обмен данными между компонентами.
Вот и всё, теория подошла к концу. Впереди вас ждёт проектная работа.