@RequestMapping(value = "/hello")
public String hello() {
List<byte[]> list = new ArrayList<>();
for (int i = 0; i < 50; i++) {
list.add(new byte[1024 * 1024 * 200]);
System.out.println("use " + 200 * (i + 1) + " M memory");
return "hello";
这里只给出http接口的简单定义,循环分配200M的内存。
DockerFile:
FROM centos:latest
ADD target/test-maven-api.jar /app.jar
ADD ./jdk-11.0.1 /var/local/jdk11
ENV JAVA_HOME /var/local/jdk11/bin
ENV PATH=$PATH:$JAVA_HOME
EXPOSE 8080
ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:InitialRAMPercentage=50 -XX:MaxRAMPercentage=80"
ENTRYPOINT java ${JAVA_OPTS} -jar /app.jar
因为对docker不太熟,简单写了一个DockerFile。使用centos作为基础镜像,然后将本地的jdk11导入到容器中。本来想直接基于jdk的基础镜像来做,但是仅有jdk9基础镜像,不知道是不是因为openjdk的原因。其次就是Java环境变量的设置以及定义了Java启动命令。这里定义了该Java应用的堆内存只能使用容器内50%-80%的内存。使用如下命令创建镜像并运行容器,限制了容器内存为1G:
docker build --rm -f "Dockerfile" -t java-springboot:latest .
docker run -m 1G -d -p 8080:8080 java-springboot
使用docker ps确认容器启动成功:
然后访问浏览器地址,并使用如下命令查看程序日志:
docker logs -f -t --tail 500 dd272
从这里可以看到,在申请800M内存时Jvm抛出OutOfMemory异常,这与预期相符,因为容器最大内存限制为1G,Jvm堆内存最大使用80%,也就是800M,所以申请800M内存失败了(Jvm本身及程序其他部分也会消耗一定的堆内存)。说明-XX:+UseContainerSupport参数确实生效了。
下面再看看不使用-XX:+UseContainerSupport的情况。我们仅需要替换之前DockerFile里的JAVA_OPTS参数即可:
ENV JAVA_OPTS="-Xms4g -Xmx4g"
看下日志:
这里申请的内存量超过了容器1G内存的限制,说明不使用-XX:+UseContainerSupport参数时Jvm无法感知容器内存限制的存在。并且由于超过容器内存限制,Jvm进程被容器kill了。至于为什么是1.6G时被kill了,原因还没有深究,应该与容器内存分配策略有关。
早期时候,容器内运行Java应用程序时,Jvm无法感知容器环境存在,所以对容器资源的限制比如内存或者cpu等都无法生效。原因是容器的资源管理使用了操作系统cgroup机制,但是Jvm无法感知cgroup。所以可能需要在jvm以及docker中指定两次内存限制。后来,在Jvm9及以后,Jvm开始了对容器资源限制的支持。在Jvm11中,可以使用-XX:+UseContainerSupport参数来制定...
如果容器资源没有设置任何 limits 并且Java没有设置额外参数的话,Java应用会默认使用宿主机 1/4 的内存作为 MaxHeapSize ,可通过如下命令验证:
$ docker run --rm -ti 129.0.4.40/common/jdk:8 java -XX:+PrintFlagsFinal -version | grep MaxHeapSize
基于Docker等容器方式运行Java应用时,容器的资源管理使用了操作系统cgroup机制,但是JVM无法感知cgroup。
也就是说在没有UseContainerSupport参数支持的JDK版本中,JVM是无法感知容器环境存在,对容器资源的限制比如内存或者cpu等都无法生效。在这种情况下,如果JVM申请的内存大于容器的内存,容器就会把当前进程kill掉,所以必须要让JVM感知到能使用的最大内存,这样可以及时进行GC。
UseContainerSupport作用
为了支持JVM感知cgroup..
docker-ingress-routing-daemon
Docker swarm守护程序,可修改入口网格路由以将真实的客户端IP暴露给服务容器:
纯粹通过路由和防火墙规则实施; 所以
无需运行traefik或其他反向代理等其他应用层; 所以
无需重新配置您现有的应用程序。
据我们所知,在编写docker-ingress-routing-daemon时,这是从docker服务启动的容器内访问客户端IP的最轻便的方法。
功能摘要:
支持为所有已发布服务或仅针对指定TCP或UDP端口上的指定服务使用传入流量上的路由替换docker的伪装
支持在服务容器内设置rp_filter=1 (严格)的最新内核(例如在Google Cloud映像中使用的内核)(尽管可以将其禁用)
自动安装内核调整,以提高生产中的IPVS性能
Docker Swarm的现成入口网格路由逻辑使用IPVS和
在rancher中部署完java应用之后,需要对java程序的jvm进行设置,这个非常重要,不然可能会引起比较严重的后果:容器无限制的重启或者主机的内存被耗尽。
在开始之前,先来看一个问题:
在容器中跑了一个java应用,那怎么来限制这个jvm的memory呢?
按照传统的思路对memory进行限制:
首先java应用的jvm内存限制可以通过-Xmx进行限制,容器的内存限制也是可以设置的,特别是对于kubernetes的容器,可以通过resource request/limit来设置一个memory可以使用
Java和Docker不是天然的朋友。 Docker可以设置内存和CPU限制,而Java不能自动检测到。使用Java的Xmx标识(繁琐/重复)或新的实验性JVM标识,我们可以解决这个问题。
虚拟化中的不匹配
Java和Docker的结合并不是完美匹配的,最初的时候离完美匹配有相当大的距离。对于初学者来说,JVM的全部设想就是,虚拟机可以让程序与底层硬件无关。
那么,把我们的Java应用打包到...
"Docker pull fearyncess/archlinux-x86:latest" 是一个命令,用于从Docker镜像仓库中拉取fearyncess/archlinux-x86镜像的最新版本。
Docker是一种容器化平台,可以将应用程序及其所有依赖项封装在一个独立的容器中,以便在不同的环境中运行。通过使用Docker,可以更轻松地部署、扩展和管理应用程序。
"pull" 是Docker的一个命令,用于在本地主机上拉取(下载)指定的镜像。当使用命令"Docker pull fearyncess/archlinux-x86:latest"时,Docker将连接到Docker镜像仓库,并查找名为"fearyncess/archlinux-x86"的镜像的最新版本。如果本地主机上没有该镜像,Docker将下载该镜像到本地。
在这个特定的例子中,我们拉取的是一个名为"fearyncess/archlinux-x86"的镜像,该镜像基于x86架构,并且使用标签"latest"表示最新版本。拉取最新版本意味着获取该镜像的最新更新和功能。
总之,Docker pull fearyncess/archlinux-x86:latest是一条命令,用于从Docker镜像仓库中下载最新版本的fearyncess/archlinux-x86镜像,以供后续在本地主机上部署和使用。
【sql server】解决 com.microsoft.sqlserver.jdbc.SQLServerException: Incorrect syntax near '@P0'.
Eric_YS:
【Grpc(一)】Java 何如理解StreamObserver?
tongxintong:
【MySQL(一)】WAL 机制
aiforyi: