Я использую несколько серверов Tomcat, на которых мы развертываем приложения, которые пишут и реализуют наши кодировщики. Проблема в том, что на некоторых наших серверах, особенно на тех, которые имеют несколько запросов, память заполняется очень быстро, и сервер начинает плохо работать, если вообще работает. Я новичок в этой роли, и мой предшественник упоминает, что это связано с тем, что код в приложениях написан неправильно, что он съедает всю память ... что достаточно справедливо, но мне интересно, могу ли я что-нибудь сделать с смягчите или устраните это, поскольку в настоящее время реализованное решение до тех пор, пока код не будет улучшено, представляет собой несколько еженедельных перезапусков tomcat, что, на мой взгляд, кажется излишним! (не каламбур)
Ниже приведен вывод htop перед тем, как tomcat необходимо убить и перезапустить (и это еще одна вещь, чаще всего Tomcat нельзя попросить вежливо выйти, вы должны убить его -9, не уверен, что это нормально)
Я проверил некоторые Ресурсы но я не смог найти ничего конкретного, что могло бы решить мою проблему, так что любой хороший опыт будет приветствоваться!
Я включил изображение, так как вы можете видеть, что процесс, кажется, повторяется несколько раз, но он использует не более 300 гигабайт памяти, как говорили некоторые люди, а только 7 гигабайт, не совсем понимая, что это значит.
На самом деле это может быть проблема с htop, как если бы вы сделали ps, вы можете увидеть только следующий процесс:
root 5215 3.4 64.8 8310716 5301436 ? Sl Nov04 146:25 /usr/bin/java -Djava.util.logging.config.file=/opt/tomcat/conf/logging.properties -Djava.awt.headless=true -Xms5G -Xmx5G -XX:PermSize=512m -XX:MaxPermSize=512m -XX:NewSize=1G -XX:MaxNewSize=1G -Duser.langua
В любом случае, чтобы вернуться к моей точке, он слишком легко перегружается, есть ли способы предотвратить это в Tomcat версии 7.0.28?
Вот server.xml
<?xml version='1.0' encoding='utf-8'?>
<Server port="8105" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.core.JasperListener" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<Environment name="databasePlaceHolder" type="java.lang.String" value="com_xxx_yyy_au"/>
<Environment name="com.xxx.databasename" type="java.lang.String" value="com_xxx_yyy_au"/>
<Environment name="com.xxx.JMS.url" type="java.lang.String" value="tcp://localhost:61616"/>
<Environment name="remoteServerURL" type="java.lang.String" value="https://yyy.xxx.com/"/>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector port="8109" protocol="AJP/1.3" redirectPort="0443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
Это содержимое файла setenv.sh:
JAVA_OPTS = "- Djava.awt.headless = true -Xms5G -Xmx5G -XX: PermSize = 512m -XX: MaxPermSize = 512m -XX: NewSize = 1G -XX: MaxNewSize = 1G -Duser.language = en -Duser.region = ГБ "
JAVA_OPTS = "$ {JAVA_OPTS} -XX: + UseParallelGC -XX: + PrintGCDetails -XX: + PrintGCDateStamps -XX: + PrintTenuringDistribution"
Что касается ошибки htop, я думаю, вы включили информацию о потоке, поэтому каждая запись java, которую вы видите, является потоком одного и того же процесса. Чтобы проверить это, переключите «показывать темы» (для переключения нажмите «H»).
На скриншоте htop я заметил, что на вашем сервере 8 ГБ ОЗУ, поэтому, если вы ограничили JVM до 5 ГБ + PermGen + некоторые накладные расходы, все должно быть в порядке, если не запущены другие процессы, требовательные к памяти.
Следующее, что нужно проверить, - это сборщик мусора, в зависимости от вашей версии java есть флаг (по крайней мере, в oracle java / openjdk), который заставляет JVM регистрировать каждое событие GC, обычно это: -verbose:gc -XX:+PrintGCDateStamps -Xloggc:SOMEFILENAME
и проверьте, даже увеличивается ли активность GC, в случае утечки памяти вы увидите, что сборка мусора становится все более частой с течением времени, пока он не использует весь ЦП, пытаясь освободить память без успеха, и вы можете получить исключения из памяти в своих журналах . В этот момент вы должны kill -9
приложение как для вас проблема. Но теперь у вас будет журнал посмертной активности GC, чтобы доказать, есть утечки памяти или нет.
Затем, если у вас развернуто более одного приложения, попробуйте разделить приложения каждое в одном экземпляре tomcat, если это возможно. Или включите дамп кучи при нехватке памяти.
Что касается того, что делать без возможности исправления кода, ну, если есть утечки памяти, настройте мониторинг на частоте GC, например, если есть 3 попытки полного GC в минуту, автоматически перезапустите tomcat.
Уродливо, но если других вариантов нет, то можно спать по ночам.
Поскольку я не вижу полных аргументов командной строки, используемых для запуска JVM, и не знаю характера приложений, которые вы развернули там, я могу только догадываться, что ваши приложения создают множество «долгоживущих» объектов, которые попадают в oldgen, и вам там не хватает памяти. Кроме того, сбор сборщика мусора в пространстве oldgen довольно дорого стоит, и, возможно, ваша JVM в какой-то момент не успевает за запусками сборщика мусора и останавливается.
Сказав это, я могу предложить следующие параметры настройки JVM.
Удалите два ниже:
-XX:NewSize=1G
-XX:MaxNewSize=1G
И добавьте следующее:
-XX:+UseParallelOldGC
-XX:SurvivorRatio=10
-XX:NewRatio=2
Если проблема не решена, продолжайте увеличивать NewRatio до 3, 4, 5 и посмотрите, когда JVM станет достаточно стабильным, чтобы продолжить работу без каких-либо проблем. Кроме того, я не уверен, зачем вам нужно 512 МБ размера перманента, т.е. -XX:PermSize=512m
. Посоветуйтесь с разработчиками вашего приложения, действительно ли им нужно так много, и, если возможно, уменьшите их.
Кроме того, когда возникает проблема, перед тем, как убить процесс, запустите следующую команду и опубликуйте здесь вывод, который даст подсказки людям, пытающимся вам здесь помочь. (примечание: вы должны работать как root).
jmap -heap <pid_of_jvm>
PS: вывод htop, как объяснил @Fredi, правильный, он ошибочно помечает идентификаторы потока LWP как PID.