我正在运行包含JVM(java8u31)的Docker容器。这些容器被部署为kubernetes集群中的吊舱。我经常为豆荚腾出空间,库伯内特斯杀死豆荚并重新启动。我在寻找这些OOM的根本原因时遇到了问题,因为我是库伯内特斯的新手。
>
-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -Xms700M -Xmx1000M -XX:MaxRAM=1536M -XX:MaxMetaspaceSize=250M
这些容器作为有状态集部署,下面是资源分配
resources:
requests:
memory: "1.5G"
cpu: 1
limits:
memory: "1.5G"
cpu: 1
因此,分配给容器的总内存与MaxRam匹配
如果我使用-XX:HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=/etc/opt/jmx/java_-pid%p.hprof
,那就没用了,因为pod会被杀死,重新创建,一旦有OOM,就会启动,所以pod内的一切都会丢失
获得线程或HEAP转储的唯一方法是SSH到pod中,这也是我不能接受的,因为pod是在OOM之后重新创建的,所以我在OOM时没有内存占用。我SSHOOM,这没有多大帮助。
我还使用Visual alVM,jHat分析了代码,但没有找到大量的内存占用,这可能会导致JVM中运行的线程消耗太多内存或可能泄漏的结论。
感谢任何帮助解决库伯内特斯抛出的OOM。
感谢@VAS的评论。感谢kubernetes的链接。
经过几次测试后,我认为如果使用-XX:UseCGroupMemoryLimitForHeap,那么指定XMX不是一个好主意,因为XMX会覆盖它。我还在做更多的测试
因为我的需求是在docker容器中运行JVM。正如@Eugene在帖子中提到的,我做了一些测试。考虑到在JVM中运行的每个应用html" target="_blank">程序都需要堆和一些本机内存,我认为我们需要指定-XX:UnlockExperimentalVMOptions,XX:UseCGroupMemoryLimitForHeap,-XX:MaxRAMFraction=1(只考虑容器内运行的JVM,同时也有风险)-XX:MaxRAM(我认为如果MaxRAMFraction为1,我们应该指定它,以便为本机内存保留一些)
几项测试:
根据下面的docker配置,考虑到您只有JVM在容器内运行,docker被分配了1 GB。考虑到docker分配给1G,我也想分配一些给进程/本机内存,我想我应该使用MaxRam=700M,这样我就有300 MB的本机内存。
$docker run-m 1GB openjdk:8u131 java-XX:UnlockExperimentalVMOptions-XX:UseCGroupMemoryLimitForHeap-XX:MaxRAMFraction=1-XX:MaxRAM=700M-XshowSettings:vm-version vm设置:最大堆大小(估计):622.50M工效学机器类别:使用vm的服务器:openjdk 64位服务器vm
现在指定XX:MaxRAMFraction=1可能会导致死亡:
参考资料:https://twitter.com/csanchez/status/940228501222936576?lang=en-XX:MaxRAMFraction=1在集装箱环境中安全生产吗?
以下内容会更好,请注意,我已经删除了MaxRAM,因为MaxRAMFraction
$docker run-m 1GB openjdk: 8u131 java-XX: Unlock实验-VMOptions-XX: UseCGroupMemoryLimitForHeap-XX: MaxRAMFraction=2-Xshow设置: vm版本VM设置:最大堆大小(估计):455.50M人体工程学机器类:使用VM的服务器: OpenJDK 64位服务器VM
这为本机提供了500米的剩余空间,例如,可以通过指定-XX:MaxMetaspaceSize:
$docker run-m 1GB openjdk:8u131 java-XX:UnlockExperimentalVMOptions-XX:UseCGroupMemoryLimitForHeap-XX:MaxRAMFraction=2-XX:MaxMetaspaceSize=200M-XshowSettings:vm-version vm设置:最大堆大小(估计):455.50M工效学机器类别:使用vm的服务器:openjdk 64位服务器vm
从逻辑上讲,根据上述参考,指定-XX: MaxRAMFraction是有意义的
我还在做更多的测试,将更新这些结果或发布。谢谢
如果您能够在Java 11(或10)而不是8上运行,那么内存限制选项已经得到了很大的改进(而且JVM支持cgroups)。只需使用-XX:MaxRAMPercentage
(范围0.0100.0):
$ docker run -m 1GB openjdk:11 java -XshowSettings:vm -XX:MaxRAMPercentage=80 -version
VM settings:
Max. Heap Size (Estimated): 792.69M
Using VM: OpenJDK 64-Bit Server VM
openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment (build 11.0.1+13-Debian-2)
OpenJDK 64-Bit Server VM (build 11.0.1+13-Debian-2, mixed mode, sharing)
这样,您就可以轻松地为堆指定80%的可用容器内存,这在旧选项中是不可能的。
当pod中的应用程序达到资源设置的内存限制时。限制。内存或命名空间限制,库伯内特斯重新启动pod。
以下文章介绍了限制资源的库伯内特斯部分:
Java应用程序消耗的内存不限于堆的大小,您可以通过指定以下选项来设置堆的大小:
-Xmssize Specifies the initial heap size.
-Xmxsize Specifies the maximum heap size.
Java应用程序需要一些额外的内存来实现元空间、类空间、堆栈大小,而JVM本身需要更多的内存来完成垃圾回收机制、JIT优化、堆外分配、JNI代码等任务。很难以合理的精度预测JVM的总内存使用量,所以最好的方法是在正常负载的实际部署中测量它。
我建议您将库伯内特斯pod限制设置为双Xmx
大小,检查您是否不再获得OOM,然后逐渐减小到开始获得OOM时的点。最终值应该在这些点之间的中间。
您可以从Prometheus这样的监控系统中的内存使用统计中获得更精确的值。
另一方面,您可以通过指定可用选项的数量来限制java内存的使用,如下所示:
-Xms<heap size>[g|m|k] -Xmx<heap size>[g|m|k]
-XX:MaxMetaspaceSize=<metaspace size>[g|m|k]
-Xmn<young size>[g|m|k]
-XX:SurvivorRatio=<ratio>
更多细节可以在以下文章中找到:
限制JVM内存使用的第二种方法是根据RAM(或MaxRAM)的数量计算堆大小。这篇文章很好地解释了它的工作原理:
默认大小基于机器上的内存量,可以使用-XX:MaxRAM=N
标志进行设置。通常,JVM通过检查机器上的内存量来计算该值。但是,JVM将客户机编译器的MaxRAM
限制为1 GB
,32位服务器编译器限制为4 GB
,64位编译器限制为128 GB
。最大堆大小是最大内存的四分之一。这就是为什么默认堆大小可能会有所不同:如果机器上的物理内存小于MaxRAM,则默认堆大小为该大小的四分之一。但是,即使有数百GB的RAM可用,JVM默认使用的最大内存也是32GB
:128GB的四分之一。默认的最大堆计算实际上是这样的:
Default Xmx=MaxRAM/MaxRAMFraction
因此,也可以通过调整-XX:MaxRAMFraction=N
标志的值来设置默认的最大堆,该标志默认为4
。最后,为了保持有趣,还可以将-XX:ErgoHeapSizeLimit=N
标志设置为JVM应该使用的最大默认值。默认情况下,该值为0
(意味着忽略它);否则,如果该限值小于MaxRAM/MaxRAMFraction
,则使用该限值。
初始堆大小的选择是相似的,尽管它的复杂性较少。初始堆大小值是这样确定的:
Default Xms=MaxRAM/InitialRAMFraction
从默认的最小堆大小可以得出结论,InitialRAMFraction
标志的默认值是64
。如果该值小于5 MB
,或者严格地说,小于-XX:OldSize=N
(默认值为4 MB
)加上-XX:NewSize=N
(默认值为1 MB
)指定的值,就会出现一个警告。在这种情况下,旧大小和新大小之和被用作初始堆大小。
本文为您提供了一个很好的起点,可以开始为面向web的应用程序调整JVM:
PostgreService.yaml 已创建服务的终结点为 然后我在pod(kubectl exec-it mark-dummy-pod bash)内运行ping172.31.6.149,但不工作。(ping localhost正在工作)
如何使用命令行列出特定实例组节点中运行的所有节点? 例如,如果我有instancegroup“foo”,它有三个节点:N1、N2和N3,它们依次有在N1上运行的pods A和B,在N2上运行的pods C、D和E,在N3上运行的pods F....我如何使用Kops/Kubectl使用输入“foo”和输出“a、B、C、D、E、f”进行查询? 我知道您可以查询一个特定的节点并列出其中的所有节点,但我
我们有一个应用程序,其中包含 4 个 pod,并使用负载均衡器运行!我们想尝试滚动更新,但我们不确定当 Pod 出现故障时会发生什么!文档不清楚!特别是《豆荚的终止》中的这句话: Pod将从服务的endpoint列表中删除,并且不再被视为复制控制器的运行Pod集的一部分。缓慢关闭的Pod可以继续为流量提供服务,因为负载平衡器(如服务代理)将它们从轮换中删除。 因此,如果有人能在以下问题上指导我们:
我希望我的pod在一段时间后(例如每周或每月)从我的部署中优雅地回收。如果我知道库伯内特斯命令,我知道我可以为此添加一个cron作业。 问题是在库伯内特斯做这件事的最好方法是什么,哪个命令会让我实现这个目标? 非常感谢你在这件事上帮助我。
我在一个有3个节点的kubernetes集群上运行nginx。 我想知道是否有任何好处,例如,有4个豆荚和限制他们的CPU/MEM约。节点容量的1/4相对于每个节点运行一个pod,限制CPU/MEM,以便pod可以使用整个节点的资源(为了简单起见,我们将cubernet服务排除在等式之外)。 我的感觉是,豆荚越少,开销就越小,每个节点使用1个豆荚应该是性能最好的? 提前致谢
环境*Kubernetes 1.9.3*使用在AWS(专用网络拓扑)上运行的kops(V1.8)创建的集群*网络:weave-net*集群:1主,3节点 事件实例时间线 > 我们已经使用kops执行了滚动集群更新,以使用我们构建的新AMI(基于kops AMI k8s-1.8-debian-jessie-amd64-hvm-ebs-2017-11-27)启动节点和主机。调整kops AMI从来都不