Подтвердить что ты не робот

Что может вызвать глобальное замедление Tomcat/JVM?

У меня возникла странная, но серьезная проблема с несколькими (около 15) экземплярами веб-приложений Java EE-ish (Hibernate 4+ Spring + Quartz + JSF + Facelets + Richfaces) на Tomcat 7/Java 7.

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

Это две диаграммы, отображающие время отклика двух коротких рабочих процессов/действий (вход в систему, список доступа к семинарам, ajax-обновление этого списка, выход из системы, нижняя строка - это просто время запроса для обновления ajax) два примера экземпляра приложения:

Response times of context 1Resoinse times of context 2

Как вы можете видеть, оба экземпляра приложения "взрываются" в одно и то же время и остаются медленными. После перезапуска сервера все возвращается к норме. Все экземпляры приложения "взрываются" одновременно.

Мы сохраняем данные сеанса в базе данных и используем это для кластеризации. Мы проверили размер и номер сеанса, и оба они довольно низки (что означает, что на других серверах с другими приложениями мы иногда имеем больше и больше сеансов). Другой Tomcat в кластере обычно остается быстрым в течение еще нескольких часов, и после этого случайного количества времени он также "умирает". Мы проверили размеры кучи с помощью jconsole, а основная куча оставалась между 2.5 и 1 ГБ, пул соединений db в основном полон бесплатных соединений, а также пулов потоков. Максимальный размер кучи составляет 5 ГБ, а также имеется достаточно свободного пространства. Нагрузка не особенно высока; всего около 5% нагрузки на основной процессор. Сервер не заменяет. Это также не проблема оборудования, поскольку мы дополнительно развернули приложения для виртуальной машины, где проблемы остались прежними.

Я не знаю, где искать больше, я из идей. Есть ли у кого-то идея, где искать?

2013-02-21 Обновление: новые данные!

Я добавил еще два графика трассировки в приложение. Что касается измерения: система мониторинга вызывает сервлет, который выполняет две задачи, измеряет время выполнения для каждого на сервере и записывает время, принятое в качестве ответа. Эти значения регистрируются системой мониторинга.

У меня есть несколько интересных новых фактов: горячее передислоцирование приложения заставляет этот единственный экземпляр текущего Tomcat сходить с ума. Это также, по-видимому, влияет на производительность вычисления центрального процессора (см. Ниже). Этот индивидуальный контекст-взрыв отличается от общего контекста-взрыва, который происходит случайным образом.

Теперь для некоторых данных:

Diagram 3Diagram 4

Сначала отдельные строки:

  • Светло-голубой - это общее время выполнения небольшого рабочего процесса (подробности см. выше), измеренного на клиенте
  • Красный - это "часть" светло-голубого цвета, и это время, затраченное на выполнение специального шага рабочего процесса, измеренного на клиенте.
  • Синий цвет измеряется в приложении и состоит из чтения списка сущностей из БД через Спящий режим и итерации по этому списку, выборки ленивых коллекций и ленивых объектов.
  • Green - это небольшой процессорный тест с использованием операций с плавающей точкой и целого числа. Насколько я вижу, нет выделения объектов, поэтому никакого мусора.

Теперь для отдельных этапов взрыва: я отметил каждое изображение тремя черными точками. Первый - это "небольшое" разброс в более или менее одном экземпляре приложения - в Inst1 он перескакивает (особенно заметен в красной строке), в то время как Inst2 ниже более или менее остается спокойным.

После этого небольшого взрыва произошел "большой взрыв", и все экземпляры приложения на этом Tomcat взорвались (2-я точка). Обратите внимание, что этот взрыв влияет на все операции высокого уровня (обработка запросов, доступ к БД), но не. Он остается низким в обеих системах.

После этого я перепрограммировал Inst1, коснувшись файла context.xml. Как я уже сказал ранее, этот экземпляр идет от взрыва до полного уничтожения (светло-голубая линия выходит из графика - она ​​составляет около 18 секунд). Обратите внимание, как: а) это перераспределение не влияет на Inst2 вообще, и б) как не влияет на доступ к необработанному DB-интерфейсу Inst1, но как внезапно кажется, что ЦПУ стал медленнее!. Я говорю, это безумие.

Обновление обновленияСлушатель утечки Tomcat не скулит о старых потоках ThreadLocals или Threads, когда приложение не развернуто. Очевидно, что есть какая-то проблема очистки (которая, как я полагаю, напрямую не связана с Большим взрывом), но Tomcat не имеет для меня намека.

2013-02-25 Обновление: прикладная среда и расписание кварца

Среда приложения не очень сложна. Сетевые компоненты в стороне (я не знаю достаточно о них) там в основном один сервер приложений (Linux) и два сервера баз данных (MySQL 5 и MSSQL 2008). Основная загрузка - на сервере MSSQL, другая - только как место для хранения сеансов.

Сервер приложений запускает Apache как балансировщик нагрузки между двумя Tomcats. Итак, у нас есть два JVM, работающих на одном оборудовании (два экземпляра Tomcat). Мы используем эту конфигурацию, чтобы не балансировать нагрузку, поскольку сервер приложений способен просто запускать приложение (что было сделано уже много лет), но для включения небольших обновлений приложений без простоев. Соответствующее веб-приложение развертывается как отдельный контекст для разных клиентов, около 15 контекстов для Tomcat. (Мне кажется, что я смешал "экземпляры" и "контексты" в моей публикации - здесь, в офисе, они часто используются синонимом, и мы обычно волшебным образом знаем, что говорит коллега. Мой плохой, мне очень жаль.)

Чтобы прояснить ситуацию с лучшей формулировкой: диаграммы, которые я опубликовал, отображали время отклика двух разных контекстов одного и того же приложения на одной и той же JVM. "Большой взрыв" влияет на все контексты на одной JVM, но не происходит с другой (порядок, в котором Tomcats взрывается случайным образом). После горячей пересылки один контекст на одном экземпляре Tomcat сходит с ума (со всеми смешными побочными эффектами, такими как, казалось бы, более медленный процессор для этого контекста).

Общая нагрузка на систему довольно низкая. Это внутреннее программное обеспечение, связанное с основным бизнесом, с примерно 30 активными пользователями одновременно. Специфические запросы приложений (затрагивающие серверы) в настоящее время составляют около 130 в минуту. Количество одиночных запросов невелико, но сами запросы часто требуют нескольких сотен выборок в базе данных, поэтому они довольно дороги. Но обычно все вполне приемлемо. Приложение также не создает большие бесконечные кеши - некоторые данные поиска кэшируются, но только на короткий промежуток времени.

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

Мы исключили некоторые аспекты, но приложение обновлялось несколько раз в течение последних месяцев, и, таким образом, мы, например, не может просто развертывать более старую версию. Самым большим обновлением, которое не было внесением изменений, был переход от JSP к Facelets. Но все-таки "что-то" должно быть причиной всех проблем, но я понятия не имею, почему Facelets, например, должен влиять на время запросов БД.

Кварц

Что касается графика кварца: всего 8 заданий. Большинство из них работают только один раз в день и связаны с синхронизацией больших объемов данных (абсолютно не "большой", как в "больших больших данных", а просто больше, чем усредненный пользователь видит в своей обычной повседневной работе). Тем не менее, эти рабочие места, конечно, работают ночью, и проблемы возникают в дневное время. Я опускаю здесь подробный список вакансий (если полезен, я могу предоставить более подробную информацию). Исходный код рабочих мест не был изменен в течение последних месяцев. Я уже проверил, совпадают ли взрывы с рабочими местами, но результаты в лучшем случае неубедительны. Я бы сказал, что они не выравниваются, но поскольку есть несколько заданий, которые запускаются каждую минуту, я пока не могу это исключить. На мой взгляд, acutal-задания, которые работают каждую минуту, довольно малы, они обычно проверяют, доступны ли данные (в разных источниках, БД, внешние системы, учетная запись электронной почты), и если это так записать его в БД или нажать на другую систему.

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

2013-02-28 Обновление: фазы и время JSF

Я вручную добавил слушателя JSF phae в приложение. Я выполнил образец вызова (обновление ajax), и это то, что у меня есть (слева: обычный запуск экземпляра Tomcat, справа: экземпляр Tomcat после Big Bang - числа были взяты почти одновременно из обоих Tomcats и находятся в миллисекундах):

  • RESTORE_VIEW: 17 против 46
  • APPLY_REQUEST_VALUES: 170 против 486
  • PROCESS_VALIDATIONS: 78 против 321
  • UPDATE_MODEL_VALUES: 75 против 307
  • RENDER_RESPONSE: 1059 против 4162

Само обновление ajax относится к форме поиска и ее результатам поиска. Там также задерживается еще одна задержка между фильтром внешнего запроса приложения и потоком веб-потока: там FlowExecutionListenerAdapter, который измеряет время, затрачиваемое на определенных этапах веб-потока. Этот слушатель сообщает 1405 мс для "Запрошенного представления" (который, насколько я знаю, первое событие веб-потока) из общего числа 1632 мс для полного запроса на нерасширенный Tomcat, поэтому я оцениваю примерно 200 мс накладных расходов. < ш > Но на взорванном Tomcat он сообщает 5332 мс для запрошенного запроса (что означает, что все фазы JSF происходят за эти 5 секунд) из общей длительности запроса 7105 мс, таким образом, мы занимаем почти 2 секунды накладные расходы для всего, что было за пределами запроса веб-потока.
Ниже моего измерительного фильтра цепь фильтра содержит org.ajax4jsf.webapp.BaseFilter, затем вызывается сервлет Spring.

2013-06-05 Обновление: все, что происходит в последние недели

Небольшое и довольно позднее обновление... производительность приложения по-прежнему отстойная через некоторое время, и поведение остается неустойчивым. Профилирование еще не помогло, оно просто породило огромное количество данных, которые трудно вскрыть. (Попробуйте зайти в данные о производительности или профилировать производственную систему... вздох). Мы провели несколько тестов (разрывая определенные части программного обеспечения, отказываясь от других приложений и т.д.) И фактически имели некоторые улучшения, которые влияют на все приложение. Режим флеша по умолчанию для нашего EntityManager равен AUTO, и при просмотре рендеринга выдается множество выборок и выборок, всегда включающих проверку необходимости промывки.
Таким образом, мы построили фазовый прослушиватель JSF, который устанавливает режим сброса на COMMIT во время RENDER_RESPONSE. Это значительно улучшило общую производительность и, похоже, немного смягчило проблемы.

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

См. следующий рисунок, например:
Diagram

На этой диаграмме показаны два экземпляра tomcat, работающих в одном и том же контексте (что означает тот же самый дБ, та же конфигурация, тот же банд). Опять же, синяя линия - это время, затраченное чистыми операциями чтения БД (выбор списка объектов, их повторение, ленивые выборки и связанные с ними данные). Бирюзовая и красная линии измеряются путем рендеринга нескольких видов и выполнения обновления ajax, соответственно. Данные, полученные двумя запросами в бирюзовых и красных, в основном такие же, как и для синей линии.

Теперь около 0700 экземпляра 1 (справа) это огромное увеличение чистого времени БД, которое, похоже, влияет и на фактическое время отклика рендера, но только на tomcat 1. Tomcat 0 в значительной степени не зависит от этого, поэтому он не может быть вызван сервером БД или сетью с обоими кошками, работающими на одном физическом оборудовании. Это должно быть проблемой программного обеспечения в домене Java.

Во время моих последних тестов я узнал что-то интересное: все ответы содержат заголовок "X-Powered-By: JSF/1.2, JSF/1.2". Некоторые (ответы на перенаправление, созданные WebFlow) даже имеют "JSF/1.2" три раза там. Я проследил части кода, которые устанавливали эти заголовки, и первый раз, когда этот заголовок установлен, вызван этим стеком:

... at org.ajax4jsf.webapp.FilterServletResponseWrapper.addHeader(FilterServletResponseWrapper.java:384)
at com.sun.faces.context.ExternalContextImpl.<init>(ExternalContextImpl.java:131)
at com.sun.faces.context.FacesContextFactoryImpl.getFacesContext(FacesContextFactoryImpl.java:108)
at org.springframework.faces.webflow.FlowFacesContext.newInstance(FlowFacesContext.java:81)
at org.springframework.faces.webflow.FlowFacesContextLifecycleListener.requestSubmitted(FlowFacesContextLifecycleListener.java:37)
at org.springframework.webflow.engine.impl.FlowExecutionListeners.fireRequestSubmitted(FlowExecutionListeners.java:89)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:255)
at org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:169)
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:183)
at org.springframework.webflow.mvc.servlet.FlowController.handleRequest(FlowController.java:174)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:920)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:827)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
... several thousands ;) more

Во второй раз этот заголовок устанавливается

at org.ajax4jsf.webapp.FilterServletResponseWrapper.addHeader(FilterServletResponseWrapper.java:384)   
at com.sun.faces.context.ExternalContextImpl.<init>(ExternalContextImpl.java:131)   
at com.sun.faces.context.FacesContextFactoryImpl.getFacesContext(FacesContextFactoryImpl.java:108)   
at org.springframework.faces.webflow.FacesContextHelper.getFacesContext(FacesContextHelper.java:46)   
at org.springframework.faces.richfaces.RichFacesAjaxHandler.isAjaxRequestInternal(RichFacesAjaxHandler.java:55)   
at org.springframework.js.ajax.AbstractAjaxHandler.isAjaxRequest(AbstractAjaxHandler.java:19)   
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.createServletExternalContext(FlowHandlerAdapter.java:216)   
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:182)   
at org.springframework.webflow.mvc.servlet.FlowController.handleRequest(FlowController.java:174)   
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)   
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)   
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)   
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:920)   
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:827)   
at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)

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

Приложение

Мой контрольный код процессора состоит из цикла, который вычисляет Math.tan и использует значение результата для изменения некоторых полей экземпляра сервлета (там нет волатильных/синхронизированных), а во-вторых выполняет несколько необработанных целочисленных вычислений. Это не сложно, я знаю, но хорошо... кажется, что-то показывает в чартах, однако я не уверен, что он показывает. Я обновляю поле, чтобы предотвратить HotSpot от оптимизации всего моего драгоценного кода;)

    long time2 = System.nanoTime();
    for (int i = 0; i < 5000000; i++) {
        double tan = Math.tan(i);
        if (tan < 0) {
            this.l1++;
        } else {
            this.l2++;
        }
    }

    for (int i = 1; i < 7500; i++) {
        int n = i;
        while (n != 1) {
            this.steps++;
            if (n % 2 == 0) {
                n /= 2;
            } else {
                n = n * 3 + 1;
            }
        }
    }
    // This execution time is written to the client.
    time2 = System.nanoTime() - time2;
4b9b3361

Ответ 1

Решение

Увеличьте максимальный размер кэша кода:

-XX:ReservedCodeCacheSize=256m

Фон

Мы используем ColdFusion 10, который работает на Tomcat 7 и Java 1.7.0_15. Наши симптомы были похожи на ваши. Иногда время отклика и использование ЦП на сервере увеличивались бы по многим причинам без видимых причин. Казалось, что процессор стал медленнее. Единственным решением было перезапустить ColdFusion (и Tomcat).

Начальный анализ

Я начал с рассмотрения использования памяти и журнала сборщика мусора. Не было ничего, что могло бы объяснить наши проблемы.

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

В выборке была выделена одна функция: get() в coldfusion.runtime.ConcurrentReferenceHashMap. Много времени было потрачено на это после замедления по сравнению с очень маленькими временами. Я потратил некоторое время на понимание того, как работает функция, и разработал теорию о том, что, возможно, возникла проблема с хеш-функцией, в результате чего появились огромные ведра. Используя кучи кучи, я смог увидеть, что самые большие ведра содержат только 6 элементов, поэтому я отбросил эту теорию.

Кэш кода

Наконец-то я попал на правильный путь, когда прочитал "Java Performance: The Definitive Guide". В нем есть глава о компиляторе JIT, в которой говорится о кодовом кэше, о котором я раньше не слышал.

Компилятор отключен

Когда вы отслеживаете количество выполненных компиляций (контролируется с помощью jstat) и размер кэша кода (контролируется плагином модулей памяти VisualVM), я видел, что размер увеличился до максимального размера (по умолчанию 48 МБ наша среда - значение по умолчанию зависит от Java-версии и Java-компилятора). Когда кеш кода заполнился, компилятор JIT был отключен. Я прочитал, что "CodeCache заполнен. Компилятор отключен". должен быть напечатан, когда это произойдет, но я не видел этого сообщения; возможно, версия, которую мы используем, не имеет этого сообщения. Я знаю, что компилятор был отключен, потому что количество выполненных компиляций перестало увеличиваться.

Продолжается оцифровка

Компилятор JIT может деоптимизировать ранее скомпилированные функции, которые будут снова выполнять функцию, которая будет выполняться интерпретатором (если функция не будет заменена улучшенной компиляцией). Деоптимизированная функция может быть собрана в мусор, чтобы освободить место в кэше кода.

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

У меня никогда не было -XX: + PrintCompilation, когда мы наблюдаем замедление, но я совершенно уверен, что я видел бы либо ConcurrentReferenceHashMap.get(), либо функцию, от которой он зависит, был бы деоптимизирован в это время.

Результат

Мы не видели замедление, так как мы увеличили максимальный размер кэша кода до 256 МБ, и мы также увидели общее улучшение производительности. В нашем кэше кода есть 110 МБ.

Ответ 2

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

ОБНОВЛЕНИЕ 1 Массовое редактирование после обновления контекста и экземпляра

Мы можем исключить:

  • GC (это повлияет на служебный поток CPU и увеличит скорость основного процессора)
  • Кварцевые задания (это может повлиять как на Tomcats, так и на тест CPU)
  • База данных (это повлияет на оба Tomcats)
  • Штормы сетевых пакетов и тому подобное (это повлияет на оба Tomcats)

Я считаю, что вы страдаете от увеличения латентности где-то в вашей JVM. Задержка - это когда поток ожидает (синхронно) ответа откуда-то - это увеличивает время отклика вашего сервлета, но бесплатно для процессора. Типичные задержки вызваны:

  • Сетевые звонки, в том числе
    • JDBC
    • EJB или RMI
    • JNDI
    • DNS
    • Файловые ресурсы
  • Чтение и запись на диск
  • Многопоточность
    • Чтение (и иногда запись в) очередей
    • synchronized метод или блок
    • futures
    • Thread.join()
    • Object.wait()
    • Thread.sleep()

Подтверждение того, что проблема заключается в задержке

Я предлагаю использовать коммерческий инструмент профилирования. Мне нравится [JProfiler] (http://www.ej-technologies.com/products/jprofiler/overview.html, доступна 15-дневная пробная версия), но сообщество Qaru также рекомендует YourKit. В этом обсуждении я буду использовать терминологию JProfiler.

Присоединяйтесь к процессу Tomcat, пока он работает нормально, и почувствуйте, как он выглядит в нормальных условиях. В частности, используйте высокоуровневые зонды JDBC, JPA, JNDI, JMS, сервлета, сокета и файла, чтобы узнать, сколько времени занимают операции JDBC, JMS и т.д. (screencast. Выполните это снова, когда сервер Выявление проблем и сравнение. Надеемся, вы увидите, что именно было замедлено. На приведенном ниже снимке экрана продукта вы можете увидеть время выполнения SQL-запроса с помощью JPA Probe:

JPA hotspots
(источник: ej-technologies.com)

Однако возможно, что зонды не изолировали проблему - например, это может быть проблема с многопоточностью. Перейдите в представление Threads для приложения; это отображает текущую диаграмму состояний каждого потока и того, выполняет ли он в ЦП, в Object.wait(), ожидает входа в блок synchronized или ожидает сетевого ввода-вывода. Когда вы знаете, какой поток или потоки демонстрируют проблему, перейдите к представлениям ЦП, выберите поток и используйте селектор состояний потоков, чтобы немедленно перейти к дорогостоящим методам и их стекам вызовов. [Screencast] ((screencast). Вы сможете углубиться в код своего приложения.

Это стек вызовов для рабочего времени:

enter image description here

И это то же самое, но с задержкой в сети:

enter image description here

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

Ответ 3

У нас была та же проблема, что и на Java 1.7.0_u101 (одна из версий, поддерживаемых Oracle, поскольку последняя публичная JDK/JRE 7 - это 1.7.0_u79), запущенная на сборщике мусора G1. Я не могу сказать, появляется ли проблема в других версиях Java 7 или других GC.

Наш процесс был Tomcat, работающий на Liferay Portal (я считаю, что точная версия Liferay здесь не представляет интереса).

Это поведение, которое мы наблюдали: с использованием -Xmx из 5 ГБ, размер пула корневого кода кеша сразу после запуска составлял около 40 МБ. Через некоторое время он упал примерно до 30 МБ (что является обычным явлением, поскольку во время запуска много кода, которое никогда не будет выполнено снова, поэтому ожидается, что через некоторое время он будет выведен из кэша). Мы заметили, что была какая-то деятельность JIT, поэтому JIT фактически заполнял кеш (по сравнению с размерами, о которых я упоминал позже, кажется, что размер небольшого кеша по отношению к размеру общей кучи помещает строгие требования в JIT, и это делает последние вызывают кэш довольно нервно). Однако через некоторое время больше никаких компиляций не было, и JVM стала мучительно медленной. Нам приходилось время от времени убивать наших Tomcats, чтобы получить адекватную производительность, и поскольку мы добавили больше кода на наш портал, проблема ухудшилась и ухудшилась (так как, по-моему, кеш кода получил насыщение быстрее).

Кажется, что в JVK 7 JVM есть несколько ошибок, которые заставляют его не перезапускать JIT (посмотрите на это сообщение в блоге: https://blogs.oracle.com/poonam/entry/why_do_i_get_message), даже в JDK 7, после аварийного флеша (в блоге упоминаются Java-ошибки 8006952, 8012547, 8020151 и 8029091).

Вот почему, увеличивая вручную код кэша до уровня, где аварийный флеш вряд ли когда-либо произойдет, "исправляет" проблему (я думаю, что это имеет место с JDK 7).

В нашем случае вместо того, чтобы пытаться настроить размер пула кода кеша, мы решили перейти на Java 8. Это, похоже, устранило проблему. Кроме того, теперь кеширование кода намного больше (размер запуска составляет около 200 МБ, а крейсерский размер достигает примерно 160 МБ). Как и ожидалось, после некоторого времени простоя размер пула кеша падает, чтобы снова встать, если какой-либо пользователь (или робот или что-то другое) просматривает наш сайт, вызывая больше кода для выполнения.

Я надеюсь, что вы найдете приведенные выше данные полезными.

Забыл сказать: я нашел очень полезную экспозицию, вспомогательные данные, логику вывода и вывод этого поста. Спасибо, действительно!

Ответ 4

Есть ли у кого-то идея, где искать?

  • Проблема может быть вне Tomcat/JVM- есть ли у вас пакетное задание, которое запускает и подчеркивает общий ресурс (ы), как общую базу данных?

  • Возьмите дамп потока и посмотрите, что делают java-процессы, когда время отклика приложения взрывается?

  • Если вы используете Linux, используйте инструмент, например strace, и проверьте, что делает Java-процесс.

Ответ 5

Вы проверили время JVM GC? Некоторые алгоритмы GC могут "приостанавливать" потоки приложений и увеличивать время отклика.

Вы можете использовать jstat утилиту для мониторинга статистики сбора мусора:

jstat -gcutil <pid of tomcat> 1000 100

Выше команда будет печатать статистику GC каждые 1 секунду в течение 100 раз. Посмотрите на колонки FGC/YGC, если число продолжает расти, что-то не так с вашими параметрами GC.

Возможно, вы захотите переключиться на CMS GC, если вы хотите, чтобы время отклика было низким:

-XX:+UseConcMarkSweepGC

Вы можете проверить дополнительные опции GC здесь.

Ответ 6

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

Если нет, я бы предложил запустить его с помощью профилировщика (JProfiler, yourkit и т.д.), эти инструменты могут легко указывать на ваши горячие точки.

Ответ 7

Вы используете Quartz, который управляет синхронизированными процессами, и это, по-видимому, происходит в определенное время.

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

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