У нас есть производственные серверы, работающие под Debian Linux, на которых размещены несколько загруженных экземпляров Tomcat, базы данных и службы поддержки. Системы работали стабильно в течение нескольких лет, но в последнее время мы, кажется, наблюдаем замедление и проблемы с памятью.
За это время приложения, размещенные на Tomcats, выросли в размерах, увеличилось количество пользователей, больше экземпляров Tomcat. Похоже, мы начинаем работать с ограничениями памяти машины.
Я начал знакомиться с мониторингом памяти с помощью таких инструментов, как htop и Java JMX, пытаясь определить текущие требования к памяти. Обозначенные регуляторы на стороне JVM являются переключателями, например, для установки максимального и начального размера пространства кучи. Параметры мониторинга памяти - виртуальная VIRT и зарезервированная память RES.
Моя проблема теперь состоит в том, чтобы выяснить, сколько памяти нам нужно в машинах, поскольку усилия по оптимизации размещенных приложений могут занять некоторое время.
Суммирование всех виртуальных размеров дает кратную физическую память и, вероятно, не очень хорошее число, потому что ядро может обрабатывать идентичные части, такие как общий код библиотеки.
Суммирование всех зарезервированных размеров должно быть близко к фактическому использованию памяти, за исключением использования общей памяти. Но это результат динамического процесса, в котором может играть роль распределение памяти ядром и различными приложениями и прочее, например порядок запуска различных экземпляров Tomcat.
Прежде чем я начну использовать метод проб и ошибок пополам, увеличивая ОЗУ и измеряя результирующую производительность системы, пока мы не достигнем более спокойной воды, я опубликовал этот вопрос в надежде, что могут быть средства для более точной оценки требований к ОЗУ.
Обновить:
$ cat /proc/meminfo
MemTotal: 66075980 kB
MemFree: 2117304 kB
Buffers: 396328 kB
Cached: 9286764 kB
SwapCached: 794700 kB
Active: 53198584 kB
Inactive: 10075240 kB
Active(anon): 50010632 kB
Inactive(anon): 3587764 kB
Active(file): 3187952 kB
Inactive(file): 6487476 kB
Unevictable: 5604 kB
Mlocked: 5604 kB
SwapTotal: 4194300 kB
SwapFree: 324 kB
Dirty: 49460 kB
Writeback: 72 kB
AnonPages: 52802056 kB
Mapped: 89356 kB
Shmem: 4448 kB
Slab: 388132 kB
SReclaimable: 324892 kB
SUnreclaim: 63240 kB
KernelStack: 11360 kB
PageTables: 126924 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 37232288 kB
Committed_AS: 47441088 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 386700 kB
VmallocChunk: 34325801336 kB
HardwareCorrupted: 0 kB
AnonHugePages: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 93868 kB
DirectMap2M: 8259584 kB
DirectMap1G: 58720256 kB
$
Как упоминал асктяги, возможно, на вашем хосте просто запущено слишком много приложений. В общем, запуск множества JVM на одном хосте может вызвать всевозможные конфликты за ресурсы, где память является только одним из них - другой пример - потоки сборщика мусора, конкурирующие за ЦП, дисковый ввод-вывод и т. Д.
Вы упомянули, что выполняете масштабирование, выполняя несколько процессов Tomcat. Вы можете поэкспериментировать, сколько процессов вам подходит - для этого, вероятно, необходима отдельная среда нагрузочного тестирования.
Чтобы узнать, сколько памяти требуется вашей программе, необходим надлежащий мониторинг. Вы можете начать экспериментировать на своем локальном компьютере с базовым профилировщиком, таким как VisualVm, наблюдая за поведением GC и пробуя различные настройки -Xmx. Вы также можете попробовать другой алгоритм GC (например, Shenandoah) в зависимости от вашей рабочей нагрузки и того, насколько важны требования к задержке / пропускной способности.
В кластере вам следует включить журналы сборки мусора и, возможно, включить профилирование с минимальными затратами через Java Flight Recorder. Позже вы можете использовать такие инструменты, как jClarity's Censum, чтобы получить представление о журналах GC.
Важно понимать, что вы не можете просто «угадать» требования к памяти вашего приложения, глядя на текущие уровни потребления памяти - JVM будет пытаться использовать столько памяти, сколько вы ей даете, поэтому, если она потребляет 10 ГБ, ей не нужно значит ему это нужно. Он может быть вполне удовлетворен всего лишь 1 ГБ (и даже более производительным, поскольку паузы GC могут быть короче).
В качестве побочного примечания, чрезмерная приверженность (проявляющаяся убийцей OOM) может быть плохой вещью (см. http://www.etalabs.net/overcommit.html), особенно для серверных машин - вы можете полностью отключить свопинг.
Честно говоря, не стоит хранить все в одном ящике, также сложно рассчитать точную требуемую память, потому что это зависит от размещенных приложений. Я бы рекомендовал использовать LB перед приложением и размещать ваше приложение на разных хостах.
Если вы по-прежнему хотите рассчитать объем памяти, вам необходимо получить статистические данные о тенденциях использования памяти приложений на основе количества потоков и отчетов о трафике. Это также зависит от других факторов, таких как другие приложения, размещенные на том же компьютере и т. Д.
Надеюсь, это поможет.