目錄
1. 背景
2. 問題
3. 解決方案
3.1. 注意
4. 參考
1. 背景
????????在使用Kubernetes部署業(yè)務(wù)應(yīng)用的實際操作中,由于k8s集群的資源是有限的,為了防止部分應(yīng)用無節(jié)制地使用資源,我們會在Deployment.yaml文件中設(shè)置request,limit的資源限制大小。
????????在 Kubernetes 中,你可以通過設(shè)置 pod 的 spec.containers[].resources.requests 和 spec.containers[].resources.limits 來配置容器的資源需求和限制。以下是一個樣例:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: my-springboot-jdk11-demo-image
resources:
requests:
cpu: "0.5"
memory: "250Mi"
limits:
cpu: "2"
memory: "8192Mi"
在這個例子中:
- requests:這部分設(shè)置了容器啟動所需要的資源。在這個例子中,容器啟動所需的 CPU 是 0.5 個核心,內(nèi)存是 250 MiB。
- limits:這部分設(shè)置了容器所能使用的資源的最大值。在這個例子中,容器所能使用的最多的 CPU 是 2 個核心,內(nèi)存是 8192 MiB(8Gib)。
????????如果容器使用的資源超過了所設(shè)置的 limits,那么這個容器可能會被 Kubernetes 殺掉并重啟。
2. 問題
????????在現(xiàn)實中,我們有很多應(yīng)用使用java開發(fā),那必然會使用JDK基礎(chǔ)鏡像,在這個實際操作中,我們可能會遇到明明設(shè)置了Limit,但是容器的最大Memory就是上不去,卡在2.1Gib左右,這個和使用的基礎(chǔ)鏡像有關(guān)系,部分JDK基礎(chǔ)鏡像有的存在默認的Xmx和Xms值。或者說,JDK運行在容器中,它無法確定Pod的limit是多少。
- -Xmx<size>: 這個參數(shù)可以設(shè)置程序的最大內(nèi)存分配。比如,如果你想要設(shè)置最大內(nèi)存為1GB,你可以寫成-Xmx1024m或者-Xmx1g。
- -Xms<size>: 這個參數(shù)可以設(shè)置程序的初始化(最?。﹥?nèi)存分配。比如,如果你想要設(shè)置最小內(nèi)存為256MB,你可以寫成-Xms256m。
3. 解決方案
????????對于運行在容器中的Java應(yīng)用,于JDK 10及以后的版本,JVM可以自動識別并根據(jù)容器的內(nèi)存限制動態(tài)設(shè)置堆大小,無需再額外手動設(shè)置JVM的-Xmx和-Xms參數(shù)。
????????JDK 10及以后的版本默認開啟了-XX:+UseContainerSupport選項,默認使用容器的cgroup限制作為JVM的內(nèi)存限制。如果你使用的是JDK 8,可以使用-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap選項來讓JVM使用容器cgroup的內(nèi)存限制。
????????此外,你還可以通過使用比例設(shè)置JVM的內(nèi)存分配,例如,你可以使用-XX:MaxRAMPercentage和-XX:MinRAMPercentage參數(shù)來限制JVM使用的最大和最小內(nèi)存占比。這兩個參數(shù)設(shè)置的是JVM可用內(nèi)存占容器可用內(nèi)存的最大和最小百分比。
-XX:MaxRAMPercentage=80.0 -XX:MinRAMPercentage=5.0
# 注意
# -XX:+UseContainerSupport參數(shù)在JDK 10及以后的版本是默認開啟的
# 完整命令:-XX:+UseContainerSupport -XX:MaxRAMPercentage=80.0 -XX:MinRAMPercentage=5.0
# JDK8完整命令:-XX:+UnlockExperimentalVMOptions -XX:+UseContainerSupport -XX:MaxRAMPercentage=80.0 -XX:MinRAMPercentage=5.0
????????上述命令就設(shè)置了JVM使用最大內(nèi)存為容器內(nèi)存的80%,最小內(nèi)存為容器內(nèi)存的20%。這樣,無論你的pod限制如何變動,JVM都會按照這個比例動態(tài)調(diào)整。
????????在上述例子中,因為設(shè)置的容器內(nèi)存上限是8GB,所以JVM會設(shè)置最大堆大小(-Xmx)為8GB的80%,即6.4GB。最小堆大?。?Xms)為8GB的5%,即400MB
完整的Dockerfile如下:
FROM openjdk-11
ADD target/my-app-name.jar /app/app.jar
WORKDIR /app
ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=80.0 -XX:MinRAMPercentage=5.0"
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Dspring.profiles.active=$PROJECT_ENV -jar app.jar"]
EXPOSE 8080
3.1. 注意
????????在實際使用過程中,請注意,XX:MaxRAMPercentage=80.0是限制堆內(nèi)存最大值。我遇到一個項目出現(xiàn)這個問題,當時就提出這個問題,此處也記錄一下
問:我的container limit 是3000M, 設(shè)置-XX:MaxRAMPercentage=80.0之后,在壓力測試之后,從監(jiān)控上看,內(nèi)存還是能飚高到3000M,為何沒有限制???
????????這主要是因為Java程序的內(nèi)存使用不僅僅包括堆內(nèi)存(Heap),還包括了非堆內(nèi)存(Non-Heap),其中包括MetaSpace(元數(shù)據(jù)區(qū)),JVM堆棧,JVM本身代碼等等。?
MaxRAMPercentage
?這個參數(shù)只是設(shè)置了堆內(nèi)存(Heap)的大小,但并沒有限制非堆內(nèi)存(Non-Heap)。????????如果你看到的內(nèi)存占用達到了3000M,可能的情況是,堆內(nèi)存占用了你設(shè)置的比例(80%,即2400M),剩下的600M被非堆內(nèi)存占用了。
另外一個需要注意的地方,3000M的limit是設(shè)置給了整個容器,容器里不僅僅有這一個Java進程。也可能是其他進程占用了一部分內(nèi)存。
????????所以這意味著,如果你希望Java進程的最大內(nèi)存使用不超過一個確定的值,那么你需要將
MaxRAMPercentage
設(shè)置的更小一些,比如50%或60%等,以便為非堆內(nèi)存和其他進程留出足夠的空間。????????注意,一定要結(jié)合實際的應(yīng)用情況去做這個調(diào)整和選擇,避免設(shè)置過小影響了Java程序的運行性能。文章來源:http://www.zghlxwxcb.cn/news/detail-851624.html
4. 參考
ChatGPT文章來源地址http://www.zghlxwxcb.cn/news/detail-851624.html
到了這里,關(guān)于在Pod設(shè)置limit 的情況下,如何讓JDK容器適配的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!