Ниже находится вольный пересказ двух статей про типичные ошибки, которые мешают масштабированию веб-приложений.
Слепое следование модным на данный момент трендам и технологиям
- Почему вы решили сменить СУБД именно сейчас? Ведь текущая версия уже долгое время работает без проблем и у нас есть четкий план по наращиванию ее мощностей на следующие несколько лет вперед? Миграция СУБД потребует больших денежных вложений, во время миграции могут возникнуть серьезные проблемы, которые не удалось предусмотреть заранее, и есть вероятность, что вся система погрузится в хаос. - Ну, мы слышали, что СУБД, которая используется в данный момент у нас, уже устарела. К тому же все приличные компании уже используют новую СУБД, которая намного круче, чем наша.Обычно лучше выбирать и использовать технологии и средства, с которыми давно знаком ваш персонал, чем что-нибудь ультрасовременное и крутое, которое у всех на слуху, но никто толком с этим еще не работал и не знаком с его подводными камнями. Новинка обычно плохо документирована, содержит много багов, плохо интегрируется со сторонними приложениями, у нее еще не налажена нормальная техподдержка и нет нормальной пользовательской базы, с которой можно бесплатно консультироваться по техническим вопросам через специализированные сайты. Также обычно новые фичи, появившиеся в новой программе или технологии, вряд ли нужны именно вашему проекту, который успешно развивался без этих фич в течение длительного срока. Аргументы вида "Google или Facebook успешно внедрили и используют эту штуку" тут не прокатят. Во-первых, ни Google, ни Facebook не застрахованы от ошибок. Во-вторых, то, что подходит для Google, не обязательно подойдет для вас. Поэтому, прежде чем внедрять какую-нибудь крутую технологию от известной компании на своем проекте, посоветуйтесь с техническим персоналом (а не с PR'щиками) этой компании о том, что они думают о данной технологии.
Отсутствие средств мониторинга и планирования нагрузки
- Проверяли ли сетевые задержки в вашем приложении? - Нет. Мы уверены, что проблема в компоненте XYZ. - Откуда такая увренность? - Ну обычно, если приложение начинает тормозить, то виноват компонент XYZ.Масштабирование веб-приложения тесно связано с математическими расчетами. Если один запрос требует X% процессорного времени, то сколько понадобится процессоров для одновременной обработки N таких запросов? Если размер БД растет на Y% в день, и Z% этой БД кэшируются в оперативной памяти, то сколько понадобится оперативной памяти для нормальной работы СУБД через N дней? Для того, чтобы спланировать количество ресурсов (процессоров, памяти, серверов баз данных, application серверов, пропускную способность сети), необходимых в будущем, нужно знать статистику по запросам и количеству требуемых ресурсов для этих запросов. Для этого соответствующие средства мониторинга должны быть повсеместно встроены в ваш проект, чтобы иметь возможность заблаговременно выявить и предотвратить нехватку каких-либо ресурсов. Если вы забудете добавить счетчик производительности для какого-нибудь ресурса, высока вероятность того, что именно этого ресурса не хватит в ближайшем будущем. Мониторинг ресурсов позволяет выявлять узкие места в системе. Например, если статистика показывает, что при линейном увеличении количества пользователей использование некоторых ресурсов растет по экспоненте, то, скорее всего, нужно срочно пересмотреть алгоритмы, вызывающие экспоненциальный рост потребления ресурсов. Также мониторинг позволяет экономить ресурсы. Например, если мониторинг показывает, что при пиковой нагрузке memcache сервера загружены только на 20%, то, скорее всего, их количество можно уменьшить в пять раз без каких-либо проблем для всей системы в целом.
Принятие решений, основываясь на предыдущем опыте, абсолютно не связанным с текущим проектом
- Когда я работал в компании XYZ, мы использовали технологию ZYX. Так что предлагаю использовать ее и на нашем проекте. - Но ведь ты там работал менеджером по продажам.При нехватке необходимой информации люди склонны принимать решения, основанные на предыдущем опыте, даже если этот опыт не имеет отношения к текущей проблеме. Часто эти решения оказываются ошибочными. Например, под новый проект закупается оборудование, которое требовалось на предыдущем проекте, даже если предыдущий проект был связан с автоматизацией банка, а новый - с разработкой программ под iPhone. Обычно это приводит либо к пустой трате средств на ненужное оборудование, либо к недостатку какого-либо оборудования. Конечно, прислушиваться к своему предыдущему опыту бывает полезно, но только в случаях, когда текущая проблема аналогична проблеме из предыдущего опыта. Рассуждения, начинающиеся со следующих фраз, скорее всего, будут ошибочными:
- Когда я работал в компании XYZ, ...
- Когда я сталкивался с проблемой X (которая никак не связана с текущей проблемой), мы использовали решение Y.
- В проекте X используется Y, поэтому мы тоже должны это использовать.
Непонимание основных принципов масштабирования
- Как бы нам реализовать счетчик online пользователей? - Элементарно - добавим в БД таблицу online_users с одним полем user_ids и одной строчкой, которая будет содержать список online пользователей. При каждом запросе будем считывать список online пользователей, искать в нем текущего пользователя и если его там нет, то добавлять его и записывать обратно. Конечно, чтение и запись нужно делать в одной транзакции, чтобы не повредить поле user_ids. Ну, и еще нужно подумать об удалении пользователей из user_ids, которые давно не обращались к нашему сервису.К сожалению, среднестатистический разработчик не знаком с главным принципом масштабирования - share nothing. Программа, разработанная без учета этого принципа, скорее всего, будет содержать обращения к глобальным ресурсам в наиболее часто исполняющихся участках кода. Обращения к глобальным ресурсам типа поле в строчке базы данных, запись в memcache, файл на сетевой файловой системе, веб-сервис в единственном экземпляре часто обрабатываются последовательно (особенно если возможны обращения на запись). Это может привести к тому, что экземпляры программ будут тратить много времени в ожидании ответа от глобального ресурса, т.к. он не справляется с количеством приходящих к нему запросов. Также разработчики не уделяют внимание таким "деталям", как принцип работы используемых инструментов. Эти инструменты могут содержать кучу глобальных блокировок, которые могут препятствовать масштабированию приложения. Если заранее знать, как работает данный инструмент, то можно либо обойти его узкие места, которые мешают масштабированию, либо вообще отказаться от его использования. Например, в одном проекте используется 240 серверов, которые получают задания через очередь, организованную на базе единственного процесса. Эта однопроцессная очередь ограничивает пропускную способность всего проекта на 75%, т.е. 240 серверов простаивают в течение 75% всего времени, или, другими словами, 180 серверов стоят без дела. Если бы эта очередь была организована на базе четырех независимых процессов, сервера бы работали на полную мощность. Еще один пример - сайт использует глобальную блокировку при обновлении данных на заглавной странице. Эти данные подтягиваются по интернету из медленного веб-сервиса. Владельцы сайта долго не могли понять, почему время загрузки главной страницы не уменьшается (а даже чуть-чуть увеличивается) при увеличении количества frontend-серверов. Так что при проектировании и разработке очередного проекта всегда думайте о том, как он будет работать при большом количестве одновременных пользователей.
Игнорирование кэширования
- Согласно собранной статистике, ваше приложение осуществляет 7000 SQL запросов в секунду. Скорее всего, результаты существенной части этих запросов можно кэшировать. - Да, у нас стоит memcached. - Ну и какие данные вы там кэшируете? - Не в курсе. Используемый нами фреймворк отвечает за кэширование данных в memcached.Компании склонны тратить много средств на новое железо для того, чтобы масштабировать свои приложения, вместо того, чтобы разобраться, где бы можно было бы добавить кэширование. В большинстве случаев грамотное кэширование способно в несколько раз увеличить пропускную способность проекта на уже существующем железе. Так что, если вы хотите масштабировать ваш сайт, в первую очередь ищите, что можно закэшировать. Кэшировать можно не только данные. Например, следующие объекты поддаются кэшированию.
- Соединения с бэкендом и базами данных.
- Простые и сложные структуры данных.
- Части веб-страницы либо все веб-страницы целиком.
- Глобальный кэш, доступный из всех датацентров, в которых хостится приложение.
- Глобальный кэш, доступный только для приложений, которые хостятся в определенном датацентре.
- Локальный кэш для каждой физической машины, к которому могут процессы, запущенные на этой же машине.
- Локальный кэш внутри каждого процесса. Данные в этом и следующем кэше могут храниться уже в виде материализованных объектов.
- Локальный кэш для каждого потока.
Масштабирование невозможного
- В следующей итерации мы вручную разобьем нашу БД на N shard'ов. Это позволить увеличить пропускную способность нашей БД в N раз. Нужно придумать, как делить данные между shard'ами, чтобы запросы к ним были равномерно распределены. Также нужно подумать, что делать с данными, которые не могут быть разделены между shard'ами. Наверное, их стоит скопировать на каждый shard. Ну и еще нужно придумать схему увеличения количества shard'ов на будущее, когда N shard'ов нам будет мало. - Выглядит слишком сложно. Может, есть способ попроще для масштабирования нашего проекта? Например, кэширование одинаковых запросов? - Кэширование не пройдет - данные в нашем проекте слишком динамичные. - Вы уверены? Согласно собранной статистике, 90% запросов поддаются кэшированию. Так что кэширование потенциально может увеличить пропускную способность нашего приложения в 10 раз. - Чушь. Я здесь главный архитектор, так что будем делать так, как я сказал.Некоторые части инфраструктуры обычно трудно поддаются масштабированию либо их вообще нельзя масштабировать. Сюда входят СУБД с поддержкой транзакций, глобальные очереди заданий, сетевые файловые системы, сложные фреймворки и ORM'ы. Другие части инфраструктуры, наоборот, отлично масштабируются - веб-сервера, CDN'ы для статического контента, кэши, файлы на локальном диске и код, исполняемый на стороне клиента (javascript). Очевидно, что в первую очередь нужно уделить внимание тому, что легко поддается масштабированию. И только, если из этой части инфраструктуры удалось выжать все соки, переходить на трудно поддающиеся масштабированию части. К сожалению, это не так очевидно для многих "архитекторов масштабируемых приложений", которые в первую очередь берутся за выполнение невозможной работы по масштабированию немасштабируемого :) Ведь это так интересно - составлять планы по shard'ингу БД, подключать load balancing для master-slave архитектуры, настраивать распределенную файловую систему на 200 нодах. Такие rocket since идеи нравятся всем, так что они быстро находят поддержку и финансирование со стороны руководства. Хотя намного дешевле и проще было бы добавить кэширование статических объектов либо оптимизировать наиболее ресурсоемкий неэффективный код.
Single Point of Failure
- Как вы балансируете нагрузку между веб-сервисами и базой данных? - С помощью X load balancer. - А как вы балансируете нагрузку между веб-серверами и веб-сервисами? - С помощью того же X load balancer. - А нагрузка между веб-серверами и сетевой файловой системой? SSH? VPN между разными датацентрами? - Тоже через X load balancer. - Т.е. на X load balancer держится вся ваша инфраструктура? - Да. Он же такой мощный, что легко справляется с такой нагрузкой.Single Pint of Failure (SPoF) означает компонент системы, от которого зависит жизнеспособность всей системы. Если он перестает работать, вся система становится неработоспособной, не зависимо от того, насколько устойчивы к сбоям другие компоненты системы. Устойчивость системы определяется самым слабым звеном, поэтому SPoF в масштабируемой системе следует избегать всеми возможными способами. SPoF'ом может оказаться не только железяка либо программа, но и человек. Например, если работоспособность серверов может быть восстановлена только вручную посредством входа на них по SSH, а пароль от SSH знает только один человек, то он является SPoF. Часто SPoF можно отыскать в процессах разработки либо deployment'а. Например, работники одной компании пытались наложить экстренный патч и выкатить новый билд, чтобы остановить DDoS атаку. Но они не смогли этого сделать, т.к. соответствующая инфраструктура (система контроля версий и система установки нового билда) хостилась там же, куда была направлена DDoS атака. Существует разновидность SPoF, называемая каскадным SPoF. Он возникает тогда, когда в системе выходит из строя часть ресурса, нагрузка на которую превышает свободную пропускную способность оставшейся части ресурса. Например, если у вас есть три сервера, равномерно нагруженные на 80% и один из них выходит из строя, то его часть нагрузки не может полностью перейти на два оставшихся, что может привести к коллапсу данного ресурса, а за ним и всей системы в целом. Такой коллапс таже возможен при резком увеличении количества внешних запросов вледствие Slashdot эффекта либо банального DDoSa. Так что не забудьте предусмотреть механизмы, предотвращающие коллапс в такой ситуации.
Нездоровое стремление использовать повсюду cloud-технологии
- Итак, если ваше приложение оставить на AWS, то потребуется полностью переписать ваш проект для поддержки горизонтального масштабирования плюс 40 тысяч баксов за нашу консультацию. Если вы переедете на обычный хостинг, то в приложении потребуются лишь косметические изменения плюс 10 тысяч баксов за нашу консультацию. К тому же на обычном хостинге ваше приложение будет потреблять меньше ресурсов при эквивалентной нагрузке. - ОК. Давайте оставим наше приложение на AWS и сделаем его масштабируемым. Cloud-технологии - это же так круто!В последнее время многие "заболели" страстью к cloud-технологиям и пытаются использовать их там, где им совсем не место. Современные cloud-хостинги отлично подходят для стартапов - не нужно платить за превоначальную инфраструктуру и легко масштабировать приложение на первых порах. Но затем начинаются проблемы. Оказывается, что cloud-хостинги имеют кучу ограничений и недостатков, которые отсутствуют в обычных датацентрах. Например, при высоких нагрузках произвольные запросы начинают сильно тормозить либо завершаться с ошибкой. Обращение к файлу либо к БД работет намного медленне, чем в обычном датацентре. Цена за cloud-ресурсы может превышать цену за аналогичные ресурсы в обычных датацентрах. В cloud-хостингах нельзя использовать произвольную конфигурацию сети либо собственные железяки типа SSL ускорителей.
Релоцировались? Теперь вы можете комментировать без верификации аккаунта.