заключение одним предложением
Для вычислительных API, работающих на одноядерном процессоре, выполните отладку, чтобы найти максимальное количество потоков в соответствии с бизнес-требованиями (максимальное время отклика), а затем отладьте размер кучи в соответствии с количеством потоков (в основном зависит от количества перезапусков). времена старого поколения)
Если есть что-то, что вы не понимаете, пожалуйста, оставьте сообщение в области комментариев, спасибо!
задний план
После нескольких месяцев работы над проектом с открытым исходным кодом, который я написал, наконец-то обрел форму.После того, как он был упакован в образ Docker и выпущен на AWS EC2, написание кода подошло к концу. Последующий вопрос: "сколько запросов в секунду может поддерживать мой проект". Из-за использования Docker он становится "сколько запросов в секунду может поддерживать мой проект на основе конфигурации Docker". Это:
- Поскольку я использовал IaaS для создания сервера Linux (используя Ubuntu), базовая конфигурация — 1 ГБ ОЗУ, 1 ЦП (2,5 ГГц) и более 10 ГБ свободного места на жестком диске (не SSD).
- Конечно, я не хочу, чтобы контейнер Docker занимал все вышеперечисленные ресурсы. Другая причина заключается в том, что текущая минимальная единица памяти, предоставляемая IaaS, составляет 500 МБ. С учетом накладных расходов других процессов в системе максимальный ресурс памяти, доступный для образа Docker, составляет 400 МБ.
- Проект представляет собой реализацию OAuth2 с загрузкой Spring, которая сама по себе имеет низкие требования к вводу-выводу и состоит из коротких ссылок. Потому что для генерации токенов JWT основная нагрузка приходится на ЦП. Со встроенным Tomcat многопоточность работает на одном процессоре, количество запросов более 99%, а коэффициент использования просто банален
Первый шаг: определить показатели теста производительности (бенчмарк)
Как говорится, говорить об ИТ без нужд бизнеса — хулиганство.
Проект является проектом с открытым исходным кодом, поэтому я должен решить потребности бизнеса.Вообще говоря, мы не хотим, чтобы пользователи регистрировались слишком быстро (и есть случаи одновременных входов, но они относительно редки).На этот раз API (oauth/token) Я устанавливаю максимум 2 секунды, исходя из этого, чтобы найти узкие места в производительности.
Шаг 2: Определите настраиваемые параметры
Итак, какие параметры можно настроить для повышения производительности без изменения кода проекта?
- Параметры, связанные с JVM, такие как GC, куча, стек потоков
- Параметры, связанные с Tomcat, такие как max-threads, max-connections, accept-count
Для проектов, основанных на вычислениях, основное внимание по-прежнему уделяется max-threads.Если настройка является разумной, накладные расходы на производительность, вызванные переключением контекста ЦП, могут быть уменьшены, а соответствующий размер кучи может избежать дрожания производительности, вызванного частым запуском GC.
Третий шаг: откройте тест (предупреждение о нескольких изображениях)
Хотя название основано на тесте производительности Docker, я все же хочу сравнить разницу в производительности с Docker и без него, поэтому тест будет разделен на две части. Ниже приведена основная информация о jre.
ubuntu@ip-xxx-xx-xx-xxx:~$ java -version
openjdk version "11.0.4" 2019-07-16
OpenJDK Runtime Environment (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3)
OpenJDK 64-Bit Server VM (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3, mixed mode, sharing)
ubuntu jre информация
/ # java -version
openjdk version "11" 2018-09-25
OpenJDK Runtime Environment 18.9 (build 11+28)
OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)
информация о докере jre
3.1 Тест производительности без Docker
3.1.1 Куча фиксирована, диаграмма взаимосвязи разного количества потоков
Размер кучи 50 м - это OOM в случае 100 потоков, поэтому здесь 0
3.1.2 Количество потоков фиксировано, а диаграмма взаимосвязей при разных размерах кучи
3.2 Тест производительности на основе Docker
прямое сравнение
На картинке выше показан результат без ограничения размера контейнера Docker.
Изображение выше ограничивает размер контейнера Docker до 450 МБ.
3.3 Количество сборок мусора (1000QPS)
Программа аварийно завершает работу, когда 50-метровая куча из 100 потоков на приведенном выше рисунке равна 0.
Шаг 4: Анализ
4.1 Докер против не-докера
Очевидно, что Docker будет нести определенную нагрузку на производительность, и эта нагрузка будет становиться более заметной по мере увеличения количества потоков и увеличения количества запросов в секунду. Но это не значит, что Docker плохой, ведь накладные расходы на производительность можно решить, открыв еще одну ноду, а по сравнению с удобством, которое дает Docker, его можно почти не учитывать.
4.2 Количество потоков и куча JVM
Обсуждение здесь ограничено вычислительными API с высокой загрузкой ЦП на одно ядро, Serial GC
- Хотя количество потоков увеличивает пропускную способность, время отклика будет увеличиваться быстрее.
- Если куча слишком мала, это приведет к частой сборке мусора (молодое поколение оказывает меньшее влияние, а старое поколение наиболее заметно) и даже OOM приведет к падению программы.
- Если Heap слишком мал, то чем больше количество потоков, тем больше количество рециклов в старом поколении, но уменьшение в молодом поколении (старое поколение — главная сила)
- Чрезмерный размер кучи не принесет повышения производительности, но количество коллекций молодого поколения будет значительно уменьшено, в то время как старое поколение практически не пострадает.
4.3 Заключение одним предложением
Для вычислительных API, работающих на одноядерном процессоре, выполните отладку, чтобы найти максимальное количество потоков в соответствии с бизнес-требованиями (максимальное время отклика), а затем отладьте размер кучи в соответствии с количеством потоков (в основном зависит от количества перезапусков). времена старого поколения)
4.4 Назад к моему проекту с открытым исходным кодом
Очень просто, 10 потоков 100м кучи