Highload на Java: о чем нужно помнить

от автора

Highload — это тема одновременно модная и достаточно заезженная, тем более, что нет четкого определения, что же такое «Highload». Для ясности, давайте назовем «Highload» сетевое приложение, которое должно обрабатывать 1000 запросов в секунду. А приложение, обрабатывающее 1 запрос в секунду, соответственно, «не Highload». Мой опыт показывает, что между первым и вторым есть существенная разница в архитектуре, подходах к разработке и проблемах. В этой статье я попытаюсь изложить эти отличия, как я их понимаю.

image

Итак…

Многие фреймворки имеют ограничения на производительность

С этим придется просто смириться. Очень большое количество кода не способно работать под большой нагрузкой — из-за чрезмерных требований к памяти, процессору, неэффективной синхронизации, устаревших механизмов ввода-вывода или плохой обработки ошибок при нехватке ресурсов. Даже если ваша любимая библиотека написана очень умными людьми и не имеет изъянов — она может не подойти просто потому, что при её проектировании эффективность принесли в жертву удобству или простоте использования. Поэтому — будьте готовы жить с самописками или искать те немногие решения, которые пройдут нагрузочные тесты под ваше конкретное приложение. Верить в этом деле нельзя никому.

Кеширование, кеширование и еще раз кеширование

Редкая высоконагруженная система обходится без кешей — особенно над СУБД. Правильное кеширование в распределенной системе — это большая и сложная тема, поэтому имеет смысл задуматься сразу о данных: кто и как будет их обновлять и запрашивать, а также где и как можно пожертвовать целостностью или актуальностью данных.

Простота

В целом — чем проще система, тем быстрее она работает. Нужно стремиться к максимальной простоте, часто в ущерб понятности, концептуальности или красоте архитектуры.

Пропускная способность сети имеет пределы

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

Не забывайте про off-heap

Некоторые объекты в Java требуют дополнительную память для работы, поэтому не нужно рассчитывать, что если -Xmx выставлен, то приложение точно влезет на сервер. Например, каждый поток в Java требует от 256K до 2 мегабайт off-heap памяти для своей работы. При умножении на 1000 получается уже достаточно много, так что следите за кол-вом потоков, используемых вашим приложением.

GC не резиновый

Даже если строгих требований к latency нет, о сборке мусора нужно помнить. Старайтесь ограничивать кол-во аллокаций и, особенно, общий объем выделяемой памяти на каждый запрос. Все необходимые метрики есть в профайлере Java Mission Control.

Аккуратнее с логгированием

Утверждение «приличное приложение всегда должно логгировать входные и выходные данные» — верно, но в высоконагруженном приложении легко станет узким местом вашей системы. Contention на логгере, недостаточная скорость жестого диска, гигабайты логов в час — это всё суровая реальность. Поэтому выбирать данные для логгирования нужно очень аккуратно и помнить про стектрейсы — они занимают много места и при большом кол-ве ошибок способны положить приложение. Часто приходится вообще не писать логи на диск, а слать их по сети в специализированную систему (и помнить, что сеть тоже не резиновая, ага).

Поведение при нехватке ресурсов

Что делать, если приложению приходит больше запросов, чем оно способно прожевать? Если база внезапно стала отвечать в два раза медленней? Если в сети начались потери пакетов? Хорошее приложение должно не виснуть наглухо, а отвечать «завтра приходи». Мораль — для всех взаимодействий с внешними системами должны быть таймауты, приложение должно ограничивать кол-во параллельно обрабатываемых запросов и клиент должен знать, что делать, если приложение занято или не отвечает.

Сделайте нормальный мониторинг

Еще одна сложная и обширная тема, но вкратце — если приложение наметво повесило машину, то где-то должны остаться графики потребления памяти, свопа, диска, цпу, потоков, системных дескрипторов.

И всегда тестируйте приложение под нагрузкой

Приложение легко может умереть под высокой нагрузкой, вполне прилично себя ведя под низкой. Если оно работало неделями на 1 запросе в секунду, на 1000 оно может умереть из-за ничтожной утечки памяти или ресурсов, перегрузки сети, перегрузки или переполнения диска и еще по 1001 причине. Поэтому — всегда гоняйте билд на полной нагрузке перед релизом на прод.

На этом всё. Комметируйте, поправляйте, делитесь своим опытом.

ссылка на оригинал статьи http://habrahabr.ru/post/270059/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *