我们的生产服务器运行在 Debian Linux 下,托管多个繁忙的 Tomcat 实例、数据库和支持服务。系统运行稳定了几年,但最近我们似乎遇到了速度变慢和内存问题。
在此期间,Tomcat 托管的应用程序规模不断扩大,用户越来越多,Tomcat 实例也越来越多。看来我们开始超出机器的内存限制了。
我开始熟悉使用 htop 和 Java JMX 等工具进行内存监控,试图确定当前的内存需求。JVM 端识别的旋钮是用于设置堆空间最大值和初始大小的开关。内存监控参数是虚拟 VIRT 和保留内存 RES。
我现在的问题是找出我们在机器中需要多少内存,因为托管应用程序的优化工作可能需要一段时间才能成功。
将所有虚拟大小相加会得出物理内存的倍数,这可能不是一个好数字,因为内核可能会处理相同的部分,如公共库代码。
将所有保留大小相加应该接近实际内存使用量(减去共享内存使用量)。但这是一个动态过程的结果,其中内核和不同应用程序的内存分配以及诸如启动各种 Tomcat 实例的顺序之类的因素可能会发挥作用。
在我开始采用二分法试错法,增加 RAM 并测量最终的系统性能直到我们达到更平静的状态之前,我发布了这个问题,希望能有一种方法可以更好地估计 RAM 需求。
更新:
$ 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
$
答案1
正如 asktyagi 提到的,可能是因为您的主机上运行了太多应用程序。通常,在单个主机上运行许多 JVM 可能会导致各种资源争用,其中内存只是其中之一 - 另一个例子是 GC 线程争用 CPU、磁盘 IO 等。
您提到通过运行多个 Tomcat 进程进行扩展。您可能想试验一下多少个进程才是适合您的正确选择 - 为此,单独的负载测试环境可能是必不可少的。
要了解程序需要多少内存,需要进行适当的监控。您可以使用 VisualVm 等基本分析器在本地机器上开始试验,观察 GC 行为并尝试不同的 -Xmx 设置。您可能还想根据您的工作负载以及延迟/吞吐量要求的重要性尝试不同的 GC 算法(例如 Shenandoah)。
在集群上,您应该打开 GC 日志,并可能通过 Java Flight Recorder 启用低开销分析。稍后,您可以使用 jClarity 的 Censum 等工具从 GC 日志中获取见解。
需要理解的重要一点是,您不能仅通过查看当前内存消耗水平来“猜测”应用的内存需求 - JVM 会尝试消耗您提供的尽可能多的内存,因此如果它消耗了 10 GB,并不一定意味着它需要它。它可能只需要 1 GB 就足够了(而且由于 GC 暂停时间可以更短,因此性能会更好)。
附注:过度使用(表现为 OOM 杀手)可能是一件坏事(请参阅http://www.etalabs.net/overcommit.html),尤其是对于服务器机器——您可能希望完全禁用交换。
答案2
老实说,将所有东西都放在一个盒子里并不是一个好主意,而且很难计算所需的确切内存,因为它取决于托管的应用程序。我建议在应用程序前面使用 LB,并在不同的主机上托管您的应用程序。
如果您仍想计算内存,则需要根据线程数和流量报告获取应用程序的历史内存趋势。这也取决于其他因素,例如同一台机器上托管的其他应用程序是什么等等。
希望这会有所帮助。