精华内容
下载资源
问答
  • 1. 前言文末有福利前两天有同事发现,通过华为云 ServiceStage 的流水线部署基于模板创建的 CSEJavaSDK demo 服务时,会在容器启动过程中报错。初步排查是由于 JVM 占用的内存超出了 docker 内存配额的上限,导致...

    1. 前言

    文末有福利

    前两天有同事发现,通过华为云 ServiceStage 的流水线部署基于模板创建的 CSEJavaSDK demo 服务时,会在容器启动过程中报错。初步排查是由于 JVM 占用的内存超出了 docker 内存配额的上限,导致容器被 kill 掉。于是我们需要排查一下问题出在哪里,为什么以前没有这类问题,而现在却发生了。

    2. 基本定位

    要确定 docker 容器内存超限问题的直接原因并不难。直接进入docker容器,执行 top 命令,我们发现宿主机是一台8核16G的机器,而且 docker 并不会屏蔽这些信息,也就是 JVM 会认为自己工作于一台 16G 内存的机器上。而查看 demo 服务的 Dockerfile,发现运行服务时并没有对 JVM 的内存进行任何限制,于是 JVM 会根据默认的设置来工作 —— 最大堆内存为物理内存的1/4(这里的描述并不完全准确,因为 JVM 的默认堆内存大小限制比例其实是根据物理内存有所变化的,具体内容请自行搜索资料),而基于模板创建的 ServiceStage 流水线,在部署应用堆栈的时候会把 docker 容器的内存配额默认设置为 512M,于是容器就会在启动的时候内存超限了。至于以前没有碰到过这种问题的原因,只是因为以前没将这么高规格的 ECS 服务器用于流水线部署应用堆栈。

    在查询过相关资料后,我们找到了两种问题解决方案,一个是直接在 jar 包运行命令里加上 -Xmx 参数来指定最大堆内存,不过这种方式只能将 JVM 堆内存限制为一个固定的值;另一个方法是在执行 jar 包时加上 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap 参数,让 JVM 能够感知到docker容器所设置的 cgroup限制,相应地调整自身的堆内存大小,不过这个特性是 JDK 8u131 以上的版本才具备的。

    最终,我们提醒 ServiceStage 流水线的同学将 CSEJavaSDK demo 的创建模板做了改进,在 Dockerfile 中将打包的基础镜像版本由原先的 java:8u111-jre-alpine 升级为了 openjdk:8u181-jdk-alpine,并且在运行服务 jar 包的命令中加上了 -Xmx256m 参数。问题至此已经解决了。

    3. 进一步的探究

    虽然问题已经解决,但是在好奇心的驱使下,我还是打算自己找个 demo 实际去触发一下问题,另外看看从网上搜到的解决方法到底好不好用 : )

    3.1 准备工作

    创建云上工程

    483df07eea07?from=groupmessage

    首先需要在华为云 ServiceStage 创建一个云上工程。

    在 ServiceStage -> 应用开发 -> 微服务开发 -> 工程管理 -> 创建云上工程中,选择“基于模板创建”,语言选择 Java, 框架选择 CSE-Java (SpringMVC),部署系统选择“云容器引擎CCE”,给你的云上工程取一个名字,比如test-memo-consuming,最后选择存放代码的仓库,就可以完成云上工程的创建了。

    之后云上工程会根据你的选项自动地生成脚手架代码,上传到你指定的代码仓库中,并且为你创建一条流水线,完成代码编译、构建、打包、归档镜像包的操作,并且使用打好的 docker 镜像包在 CCE 集群中部署一个应用堆栈。

    创建云上工程和流水线不是本文的重点,我就不详细讲操作了 : )。同一个应用堆栈的实例可以部署多个,在这里为了实验方便就按照默认值1个来部署。

    483df07eea07?from=groupmessage

    由于云上工程已经改进了脚手架代码的模板,不会再出现内存超限的问题,所以我们现在能看到 demo 服务已经正常的跑起来,微服务实例已经注册到服务中心了。

    483df07eea07?from=groupmessage

    登录到 demo 服务所部署的容器,使用curl命令可以调用 demo 服务的 helloworld 接口,可以看到此时服务已经可以正常工作。

    增加实验代码

    为了能够触发微服务实例消耗更多的内存,我在项目代码中增加了如下接口,当调用/allocateMemory接口时,微服务实例会不停申请内存,直到 JVM 抛出 OOM 错误或者容器内存超限被 kill 掉。

    private HashMap cacheMap = new HashMap<>();

    @GetMapping(value = "/allocateMemory")

    public String allocateMemory() {

    LOGGER.info("allocateMemory() is called");

    try {

    for (long i = 0; true; ++i) {

    cacheMap.put("key" + i, new long[1024 * 1024]);

    }

    } catch (Throwable t) {

    LOGGER.info("allocateMemory() gets error", t);

    }

    return "allocated";

    }

    此时用来打镜像包的基础镜像是openjdk:8u181-jdk-alpine,jar 包启动命令中加上了-Xmx256m参数。

    执行流水线,应用堆栈部署成功后,调用/allocateMemory接口触发微服务实例消耗内存,直到 JVM 抛出 OOM 错误,可以在 ServiceStage -> 应用上线 -> 应用管理中选择相应的应用,点击进入概览页面,查看应用使用内存的情况。

    483df07eea07?from=groupmessage

    应用使用的内存从 800M+ 陡然下降的时间点就是我重新打包部署的时间,而之后由于调用/allocateMemory接口,内存占用量上升到了接近 400M,并且在这个水平稳定了下来,显示-Xmx256m参数发挥了预期的作用。

    3.2 复现问题

    现在将 demo 工程中的 Dockerfile 修改一下,将基础镜像改为 java:8u111-jre-alpine,并且删除启动命令中的-Xmx256m参数,将其提交为noLimit_oldBase分支,推送到代码仓库中。然后编辑流水线,将 source 阶段的任务所使用的代码分支改为noLimit_oldBase分支,保存并重新运行流水线,将新的代码打包部署到应用堆栈中。

    483df07eea07?from=groupmessage

    在微服务实例列表中查询到新的微服务实例的 endpoint IP 后,调用/allocateMemory接口,观察内存情况,内存从接近 400M 突然掉下去一下,然后又上升到约 450M 的时间点就是修改代码后的微服务实例部署成功的时间点,之后内存占用量突然下跌就是因为调用/allocateMemory接口导致容器内存超限被 kill 掉了。

    如果你事先使用docker logs -f命令查看容器日志的话,那么日志大概是这个样子的

    2018-11-23 15:40:04,920 INFO SCBEngine:152 - receive MicroserviceInstanceRegisterTask event, check instance Id...

    2018-11-23 15:40:04,920 INFO SCBEngine:154 - instance registry succeeds for the first time, will send AFTER_REGISTRY event.

    2018-11-23 15:40:04,925 WARN VertxTLSBuilder:116 - keyStore [server.p12] file not exist, please check!

    2018-11-23 15:40:04,925 WARN VertxTLSBuilder:136 - trustStore [trust.jks] file not exist, please check!

    2018-11-23 15:40:04,928 INFO DataFactory:62 - Monitor data sender started. Configured data providers is {com.huawei.paas.cse.tcc.upload.TransactionMonitorDataProvider,com.huawei.paas.monitor.HealthMonitorDataProvider,}

    2018-11-23 15:40:04,929 INFO ServiceCenterTask:51 - read MicroserviceInstanceRegisterTask status is FINISHED

    2018-11-23 15:40:04,939 INFO TestmemoconsumingApplication:57 - Started TestmemoconsumingApplication in 34.81 seconds (JVM running for 38.752)

    2018-11-23 15:40:14,943 INFO AbstractServiceRegistry:258 - find instances[1] from service center success. service=default/CseMonitoring/latest, old revision=null, new revision=28475010.1

    2018-11-23 15:40:14,943 INFO AbstractServiceRegistry:266 - service id=8b09a7085f4011e89f130255ac10470c, instance id=8b160d485f4011e89f130255ac10470c, endpoints=[rest://100.125.0.198:30109?sslEnabled=true]

    2018-11-23 15:40:34,937 INFO ServiceCenterTaskMonitor:39 - sc task interval changed from -1 to 30

    2018-11-23 15:47:03,823 INFO SPIServiceUtils:76 - Found SPI service javax.ws.rs.core.Response$StatusType, count=0.

    2018-11-23 15:47:04,657 INFO TestmemoconsumingImpl:39 - allocateMemory() is called

    Killed

    可以看到allocateMemory方法被调用,然后 JVM 还没来得及抛出 OOM 错误,整个容器就被 kill 掉了。

    这里也给大家提了一个醒:不要以为自己的服务容器能启动起来就万事大吉了,如果没有特定的限制,JVM 会在运行时继续申请堆内存,也有可能造成内存用量超过 docker 容器的配额!

    3.3 让 JVM 感知 cgroup 限制

    前文提到还有另外一种方法解决 JVM 内存超限的问题,这种方法可以让 JVM 自动感知 docker 容器的 cgroup 限制,从而动态的调整堆内存大小,感觉挺不错的。我们也来试一下这种方法,看看效果如何 ; )

    回到demo项目代码的master分支,将 Dockerfile 中启动命令参数的-Xmx256m替换为-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap,提交为useCGroupMemoryLimitForHeap分支,推送到代码仓库里。再次运行流水线进行构建部署。

    483df07eea07?from=groupmessage

    等 demo 服务部署成功后,再次调用/allocateMemory接口,容器的内存占用情况如上图所示(最右边的那一部分连续曲线),内存上升到一定程度后,JVM 抛出了 OOM 错误,没有继续申请堆内存。看来这种方式也是有效果的。不过,仔细观察容器的内存占用情况,可以发现容器所使用的内存仅为不到 300M,而我们对于这个容器的内存配额限制为 512M,也就是还有 200M+ 是闲置的,并不会被 JVM 利用。这个利用率,比起上文中直接设置-Xmx256m的内存利用率要低 : ( 。推测是因为 JVM 并不会感知到自己是部署在一个 docker 容器里的,所以它把当前的环境当成一个物理内存只有 512M 的物理机,按照比例来限制自己的最大堆内存,另一部分就被闲置了。

    如此看来,如果想要充分利用自己的服务器资源,还是得多花一点功夫,手动调整好-Xmx参数。

    这里也为大家准备了一节视频:

    视频详情

    干货列表

    1,Docker安装过程的各种坑

    2,完成Docker仓库环境搭建

    3,增加模板基础镜像,供JAVA应用项目使用

    4,将定制化的镜像上传到仓库及注意事项

    5,Dockfile详解,结合Java应用程序,将JAVA应用服务镜像发布到仓库

    6,企业常用技能Maven打包创建本地镜像,推送仓库及部署;

    7,创建Java应用服务容器,完成代码到容器的发布及应用自启

    8,演示测试

    什么是Docker?

    docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux服务器上,可以实现虚拟化,容器是完全使用沙箱(沙盒)机制,相互之间不会有任何接口。

    那些在玩docker的大佬

    京东:http://www.infoq.com/cn/news/2015/06/jd-618-docker

    腾讯内部:http://www.infoq.com/cn/articles/tencent-millions-scale- docker-application-practice

    阿里巴巴:http://www.infoq.com/cn/news/2015/07/paas-tae-dock

    Docker性能

    Docker容器启动速度秒级,基于操作系统内核技术,对现有基础设施的侵入较少,所有实现在内核中完成,所以性能几乎与原生一致,依赖简单,与进程无本质区别

    正确理解Docker内部流程

    483df07eea07?from=groupmessage

    Docker线上环境操作流程

    Docker实战

    1,Docker安装过程的各种坑

    2,完成Docker仓库环境搭建

    3,增加模板基础镜像,供JAVA应用项目使用

    4,将定制化的镜像上传到仓库及注意事项

    5,Dockfile详解,结合Java应用程序,将JAVA应用服务镜像发布到仓库

    6,企业常用技能Maven打包创建本地镜像,推送仓库及部署;

    7,创建Java应用服务容器,完成代码到容器的发布及应用自启

    资料获取方式

    加群即可获取 群号:923116658

    展开全文
  • 在实际生产环境中,我们是不能触碰到服务器的,只能通过SSH等手段进行远程连接,通过网络传输进行内存cpu日志等查看工作,通过对其分析,再定位代码部分的问题,那这么jar包是如何运行到服务器上的?JVM堆栈的设置又...

    在实际生产环境中,我们是不能触碰到服务器的,只能通过SSH等手段进行远程连接,通过网络传输进行内存cpu日志等查看工作,通过对其分析,再定位代码部分的问题,那这么jar包是如何运行到服务器上的?JVM堆栈的设置又是什么?日志输出查看又是什么?这就是十分真实的生产环境下的工作。

    1通过Maven将SpringBoot打成Jar包

    在本机已经测试好代码后,首先在pom.xml文件中添加

        <build>        <plugins>            <plugin>                <groupId>org.springframework.bootgroupId>                <artifactId>spring-boot-maven-pluginartifactId>            plugin>        plugins>    build>

    在IDE中点击Maven的package进行自动打包

    25e99c06d97c4f8d62708b0ce6de1864.png

    就会在项目目录下生成一个target目录,里面有一个xxxx.jar包

    79e31399359ad205d4ac50c8757b2964.png

    2

    将Jar包放置Linux服务器

    可以通过xftp这类网络文件传输工具,进行远程连接Linux服务器后将Jar包传输到远程服务器.

    3Linux服务器上开启SpringBoot服务

    手动开启方法:

    1. 找到Jar包所在的目录

    2. 通过 java -jar xxx.jar > consoleMsg.out & 让日志输出到consoleMsg.out文件中 & 表示后台运行,这样正在使用的shell就不会被占用掉

    3.  通过 ps aux|grep xxx 可以看到正在运行的Java服务和占用的端口以及PID

    4

    杀掉进程和重启进程

    在很多时候我们需要强杀掉进程并重启该服务

    1. ps aux | grep xxx.jar 可以得到该进程的PID

    2. kill -9 PID 进行进程强杀

    3. java -jar xxx 重新手动启动

    5

    设置JVM堆栈大小

    可以通过命令行shell启动Jar包的时候手动进行设置

    java -jar -Xmx1024M -Xms256M spring-boot-01-1.0-SNAPSHOT

    -Xmx 表示JVM最大的内存

    -Xms 表示JVM初始内存

    961e26df90b5317ccb7e0ff7c7d40784.pngEND
    展开全文
  • 也就是只要pod内应用需要, 完全可以占满宿主机的cpu和内存, 如果是这种情况, 当有大量的服务一起部署时, 相互之间是会相互影响的, 所以k8s也有相应的办法限制pod及里面容器的cpu和内存准备工作# 创建namespace ...

    默认的情况下, k8s不会限制pod的cpu和内存的, 也就是只要pod内应用需要, 完全可以占满宿主机的cpu和内存, 如果是这种情况, 当有大量的服务一起部署时, 相互之间是会相互影响的, 所以k8s也有相应的办法限制pod及里面容器的cpu和内存

    准备工作

    # 创建namespace xxx

    kubectl create namespace xxx

    # 下载官方提供的示例文件

    wget https://k8s.io/docs/tasks/configure-pod-container/limits.yaml

    # 内容如下

    ##############################

    apiVersion: v1

    kind: LimitRange

    metadata:

    name: mylimits

    spec:

    limits:

    - max:

    cpu: "2"

    memory: 1Gi

    min:

    cpu: 200m

    memory: 6Mi

    type: Pod

    - default:

    cpu: 300m

    memory: 200Mi

    defaultRequest:

    cpu: 200m

    memory: 100Mi

    max:

    cpu: "2"

    memory: 1Gi

    min:

    cpu: 100m

    memory: 3Mi

    type: Container

    ##############################

    Pod相关限制

    cpu最大限制2核, 最小200MHZ

    内存最大限制1G, 最小6M

    Container相关限制

    cpu最大限制2核, 最小200MHZ

    内存最大限制1G, 最小6M

    默认启动cpu最大限制300MHZ, 内存最大限制200M

    创建指定namespace资源限制

    kubectl create -f limits.yaml -n xxx

    # 查看创建好的资源限制

    kubectl get limits -n xxx

    之后在这个namespace下创建的Pod及容器都遵循这个规则

    在创建容器的配置文件中指定

    spec:

    containers:

    - image: gcr.io/google_containers/serve_hostname

    imagePullPolicy: Always

    name: kubernetes-serve-hostname

    resources:

    limits:

    cpu: "1"

    memory: 512Mi

    requests:

    cpu: "1"

    memory: 512Mi

    如果按照这个规范, 相关的容器会限制在这个范围内

    如果两者都配置?

    有些时候, 我们大部分容器遵循一个规则就好, 但有一小部分有特殊需求, 这个时候, 小部分的就需要单独在容器的配置文件中指定. 这里有一点要注意的是, 单独在容器中配置的参数是不能大于指定的k8s资源限制, 否则会报错, 容器无法启动

    PS: 对于一些java项目, 必须设置java虚拟机的参数, 而且这个参数不能大于容器设置的限定值, 否则容器会因为内存过大不停的重启

    展开全文
  • 1. 前言前两天有同事发现,通过华为云 ServiceStage 的流水线部署基于模板创建的 CSEJavaSDK demo 服务时,会在容器启动过程中报错。初步排查是由于 JVM 占用的内存超出了 docker 内存配额的上限,导致容器被 kill ...

    1. 前言

    前两天有同事发现,通过华为云 ServiceStage 的流水线部署基于模板创建的 CSEJavaSDK demo 服务时,会在容器启动过程中报错。初步排查是由于 JVM 占用的内存超出了 docker 内存配额的上限,导致容器被 kill 掉。于是我们需要排查一下问题出在哪里,为什么以前没有这类问题,而现在却发生了。

    2. 基本定位

    要确定 docker 容器内存超限问题的直接原因并不难。直接进入docker容器,执行 top 命令,我们发现宿主机是一台8核16G的机器,而且 docker 并不会屏蔽这些信息,也就是 JVM 会认为自己工作于一台 16G 内存的机器上。而查看 demo 服务的 Dockerfile,发现运行服务时并没有对 JVM 的内存进行任何限制,于是 JVM 会根据默认的设置来工作 —— 最大堆内存为物理内存的1/4(这里的描述并不完全准确,因为 JVM 的默认堆内存大小限制比例其实是根据物理内存有所变化的,具体内容请自行搜索资料),而基于模板创建的 ServiceStage 流水线,在部署应用堆栈的时候会把 docker 容器的内存配额默认设置为 512M,于是容器就会在启动的时候内存超限了。至于以前没有碰到过这种问题的原因,只是因为以前没将这么高规格的 ECS 服务器用于流水线部署应用堆栈。

    在查询过相关资料后,我们找到了两种问题解决方案,一个是直接在 jar 包运行命令里加上 -Xmx 参数来指定最大堆内存,不过这种方式只能将 JVM 堆内存限制为一个固定的值;另一个方法是在执行 jar 包时加上 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap 参数,让 JVM 能够感知到docker容器所设置的 cgroup 限制,相应地调整自身的堆内存大小,不过这个特性是 JDK 8u131 以上的版本才具备的。

    最终,我们提醒 ServiceStage 流水线的同学将 CSEJavaSDK demo 的创建模板做了改进,在 Dockerfile 中将打包的基础镜像版本由原先的 java:8u111-jre-alpine 升级为了 openjdk:8u181-jdk-alpine,并且在运行服务 jar 包的命令中加上了 -Xmx256m 参数。问题至此已经解决了。

    3. 进一步的探究

    虽然问题已经解决,但是在好奇心的驱使下,我还是打算自己找个 demo 实际去触发一下问题,另外看看从网上搜到的解决方法到底好不好用 : )

    3.1 准备工作

    创建云上工程

    首先需要在华为云 ServiceStage 创建一个云上工程。

    在 ServiceStage -> 应用开发 -> 微服务开发 -> 工程管理 -> 创建云上工程中,选择“基于模板创建”,语言选择 Java, 框架选择 CSE-Java (SpringMVC),部署系统选择“云容器引擎CCE”,给你的云上工程取一个名字,比如test-memo-consuming,最后选择存放代码的仓库,就可以完成云上工程的创建了。

    之后云上工程会根据你的选项自动地生成脚手架代码,上传到你指定的代码仓库中,并且为你创建一条流水线,完成代码编译、构建、打包、归档镜像包的操作,并且使用打好的 docker 镜像包在 CCE 集群中部署一个应用堆栈。

    创建云上工程和流水线不是本文的重点,我就不详细讲操作了 : )。同一个应用堆栈的实例可以部署多个,在这里为了实验方便就按照默认值1个来部署。

    由于云上工程已经改进了脚手架代码的模板,不会再出现内存超限的问题,所以我们现在能看到 demo 服务已经正常的跑起来,微服务实例已经注册到服务中心了。

    登录到 demo 服务所部署的容器,使用curl命令可以调用 demo 服务的 helloworld 接口,可以看到此时服务已经可以正常工作。

    增加实验代码

    为了能够触发微服务实例消耗更多的内存,我在项目代码中增加了如下接口,当调用/allocateMemory接口时,微服务实例会不停申请内存,直到 JVM 抛出 OOM 错误或者容器内存超限被 kill 掉。 private HashMap cacheMap = new HashMap<>();

    @GetMapping(value = "/allocateMemory")

    public String allocateMemory() {

    LOGGER.info("allocateMemory() is called");

    try {

    for (long i = 0; true; ++i) {

    cacheMap.put("key" + i, new long[1024 * 1024]);

    }

    } catch (Throwable t) {

    LOGGER.info("allocateMemory() gets error", t);

    }

    return "allocated";

    }

    此时用来打镜像包的基础镜像是openjdk:8u181-jdk-alpine,jar 包启动命令中加上了-Xmx256m参数。

    执行流水线,应用堆栈部署成功后,调用/allocateMemory接口触发微服务实例消耗内存,直到 JVM 抛出 OOM 错误,可以在 ServiceStage -> 应用上线 -> 应用管理中选择相应的应用,点击进入概览页面,查看应用使用内存的情况。

    应用使用的内存从 800M+ 陡然下降的时间点就是我重新打包部署的时间,而之后由于调用/allocateMemory接口,内存占用量上升到了接近 400M,并且在这个水平稳定了下来,显示-Xmx256m参数发挥了预期的作用。

    3.2 复现问题

    现在将 demo 工程中的 Dockerfile 修改一下,将基础镜像改为 java:8u111-jre-alpine,并且删除启动命令中的-Xmx256m参数,将其提交为noLimit_oldBase分支,推送到代码仓库中。然后编辑流水线,将 source 阶段的任务所使用的代码分支改为noLimit_oldBase分支,保存并重新运行流水线,将新的代码打包部署到应用堆栈中。

    在微服务实例列表中查询到新的微服务实例的 endpoint IP 后,调用/allocateMemory接口,观察内存情况,内存从接近 400M 突然掉下去一下,然后又上升到约 450M 的时间点就是修改代码后的微服务实例部署成功的时间点,之后内存占用量突然下跌就是因为调用/allocateMemory接口导致容器内存超限被 kill 掉了。

    如果你事先使用docker logs -f命令查看容器日志的话,那么日志大概是这个样子的

    2018-11-23 15:40:04,920 INFO SCBEngine:152 - receive MicroserviceInstanceRegisterTask event, check instance Id...

    2018-11-23 15:40:04,920 INFO SCBEngine:154 - instance registry succeeds for the first time, will send AFTER_REGISTRY event.

    2018-11-23 15:40:04,925 WARN VertxTLSBuilder:116 - keyStore [server.p12] file not exist, please check!

    2018-11-23 15:40:04,925 WARN VertxTLSBuilder:136 - trustStore [trust.jks] file not exist, please check!

    2018-11-23 15:40:04,928 INFO DataFactory:62 - Monitor data sender started. Configured data providers is {com.huawei.paas.cse.tcc.upload.TransactionMonitorDataProvider,com.huawei.paas.monitor.HealthMonitorDataProvider,}

    2018-11-23 15:40:04,929 INFO ServiceCenterTask:51 - read MicroserviceInstanceRegisterTask status is FINISHED

    2018-11-23 15:40:04,939 INFO TestmemoconsumingApplication:57 - Started TestmemoconsumingApplication in 34.81 seconds (JVM running for 38.752)

    2018-11-23 15:40:14,943 INFO AbstractServiceRegistry:258 - find instances[1] from service center success. service=default/CseMonitoring/latest, old revision=null, new revision=28475010.1

    2018-11-23 15:40:14,943 INFO AbstractServiceRegistry:266 - service id=8b09a7085f4011e89f130255ac10470c, instance id=8b160d485f4011e89f130255ac10470c, endpoints=[rest://100.125.0.198:30109?sslEnabled=true]

    2018-11-23 15:40:34,937 INFO ServiceCenterTaskMonitor:39 - sc task interval changed from -1 to 30

    2018-11-23 15:47:03,823 INFO SPIServiceUtils:76 - Found SPI service javax.ws.rs.core.Response$StatusType, count=0.

    2018-11-23 15:47:04,657 INFO TestmemoconsumingImpl:39 - allocateMemory() is called

    Killed

    可以看到allocateMemory方法被调用,然后 JVM 还没来得及抛出 OOM 错误,整个容器就被 kill 掉了。

    这里也给大家提了一个醒:不要以为自己的服务容器能启动起来就万事大吉了,如果没有特定的限制,JVM 会在运行时继续申请堆内存,也有可能造成内存用量超过 docker 容器的配额!

    3.3 让 JVM 感知 cgroup 限制

    前文提到还有另外一种方法解决 JVM 内存超限的问题,这种方法可以让 JVM 自动感知 docker 容器的 cgroup 限制,从而动态的调整堆内存大小,感觉挺不错的。我们也来试一下这种方法,看看效果如何 ; )

    回到demo项目代码的master分支,将 Dockerfile 中启动命令参数的-Xmx256m替换为-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap,提交为useCGroupMemoryLimitForHeap分支,推送到代码仓库里。再次运行流水线进行构建部署。

    等 demo 服务部署成功后,再次调用/allocateMemory接口,容器的内存占用情况如上图所示(最右边的那一部分连续曲线),内存上升到一定程度后,JVM 抛出了 OOM 错误,没有继续申请堆内存。看来这种方式也是有效果的。不过,仔细观察容器的内存占用情况,可以发现容器所使用的内存仅为不到 300M,而我们对于这个容器的内存配额限制为 512M,也就是还有 200M+ 是闲置的,并不会被 JVM 利用。这个利用率,比起上文中直接设置-Xmx256m的内存利用率要低 : ( 。推测是因为 JVM 并不会感知到自己是部署在一个 docker 容器里的,所以它把当前的环境当成一个物理内存只有 512M 的物理机,按照比例来限制自己的最大堆内存,另一部分就被闲置了。

    如此看来,如果想要充分利用自己的服务器资源,还是得多花一点功夫,手动调整好-Xmx参数。

    4. 参考资料

    展开全文
  • 前两天有同事发现,通过华为云 ServiceStage 的流水线部署基于模板创建的 CSEJavaSDK demo 服务时,会在容器启动过程中报错。初步排查是由于 JVM 占用的内存超出了 docker 内存配额的上限,导致容器被 kill 掉。于是...
  • JAVA虚拟机的内存模型

    2020-05-16 15:59:45
    一.JAVA虚拟机运行时内存区域划分 1.栈 1.1.虚拟机栈 线程私有 虚拟机栈描述的是JAVA方法执行的内存模型,每个方法在执行时会创建一个栈帧,用于存储局部变量(基本类型、引用类型、returnAddress)、操作数...
  • 案例发生现场有一天突然收到线上的一个报警:某台机器部署的一个服务突然之间就不...这个时候在机器的日志中发现了如下的一些信息:nio handle failed java.lang.OutOfMemoryError: Direct buffer memoryat org.ec...
  • mac下打开FTP服务MAC下打开FTP服务 周银辉 mac下一般用smb服务来进行远程文件访问,但要用FTP的话,高版本的mac os默认关掉了,可以用如下命令打开: sudo -s launchctl load -w ...PAT乙级 1032&period; 挖掘机技术...
  • 我正在通过java nio接口读取文件,直接读取到流.这将启动异步http请求并在将来处理这些请求.每10,000条记录,我将此结果上传到服务器并清除记录,这样可以清除内存消耗.我从字节数组开始,它不断地保留在内存中. http...
  • Baisics:  JAVA NIO使用,基于通道和缓冲区的IO方式,使用Native函数库直接分配堆外内存(allocateDirect),...内存的分配不受Java堆大小的影响,限制于服务器的内存,JVM调优设置JVM堆内存大小是需注意 转...
  • Java 内存管理

    2014-03-25 17:56:23
    java虽然是自动回收内存,但是应用程序,尤其服务器程序最好根据业务情况指明内存分配限制。否则可能导致应用程序宕掉。举例说明含义:-Xms128m表示JVM Heap(堆内存)最小尺寸128MB,初始分配-Xmx512m表示JVM Heap(堆...
  • java虽然是自动回收内存,但是应用程序,尤其服务器程序最好根据业务情况指明内存分配限制。否则可能导致应用程序宕掉。-Xms128m:表示JVM Heap(堆内存)最小尺寸128MB,初始分配-Xmx512m:表示JVM Heap(堆内存)最大...
  • Java堆外内存及导致的溢出错误

    千次阅读 2017-05-11 10:54:25
    除了Java堆和永生代之外,还有一些区域会占用较多的内存,而这些内存总和可能受到操作系统进程最大的内存限制。比如,一个服务器内存2G,其中1.6G分配给Java堆,另外的0.4G分配给操作系统和下面的区域,那么0.4G很...
  • 前几天往 MongoDB 中写入了几个 G 的数据,发现...今天本来只是准备想办法限制一下 MongoDB 的内存占用的,可惜很多事情不折腾不行啊。系统中安装的是 Debian 9 官方 apt 源提供的 MongoDB 包,3.2 的。在配置文件中...
  • 斯蒂芬大帝java虽然是自动回收内存,但是应用程序,尤其服务器程序最好根据业务情况指明内存分配限制。否则可能导致应用程序宕掉。-Xms128m:表示JVM Heap(堆内存)最小尺寸128MB,初始分配-Xmx512m:表示JVM Heap(堆...
  • 什么叫Java内存模型?现代计算机通过指令的重排序来提升计算机的性能,而没有限制条件的指令重排序会使得程序的行为不可预测,JMM就是通过一系列的操作规则限制指令重排序的方式使得指令重排序不会破坏JMM提供的可见...
  • 我的应用程序在docker容器中运行,它使用scala并使用“OpenJDK 64位服务器VM(内置25.102-b14,混合模式)”,其Xmx设置为16GB,容器内存限制为24Gb,运行后为某些容器被杀的时间:Last State: TerminatedReason: ...
  • 在突发大量内存的请求期间,哪些工具或最佳实践可用于在Java服务中正常降级服务? 有问题的应用程序是多线程的。 处理每个请求所需的工作量可能相差很大,并且不容易拆分和并行化。我很担心编写与堆使用和GC有关的...
  • 我们的linux服务器上有4GB,但我们目前只能使用~1.8GB的java服务器,这是下面列出的第一个java进程. (200 MB是免费的,所以我们最大可以使用1.6GB 0.2GB)当我们使用更多时,机器崩溃了.因此我们指定-Xmx1600m和-XX:...
  • 自己部署的线上springboot服务总是内存飙高,尤其是在30个以上的请求并发的时候,内存会立马大涨,并出现报错:- ma" X5 q6 Njava.lang.OutOfMemoryError: Java heap space后来通过一步一步排查发现了导致这个问题的...
  • 我在AWS上的小型/中型机器上运行多个微服务(Spring cloud ...我试图通过这样做来限制这些容器可以使用的内存量:docker run -m 500M --memory-swap 500M -d my-service:latest此时,我的服务(带有一个单一端点的标...
  • Tomcat 6 限制内存使用量

    千次阅读 2010-09-05 23:01:00
    安装为服务的Tomcat 6内存使用量限制只能通过注册表项来修改:Windows Registry Editor Version 5.00[HKEY_LOCAL_MACHINE/SOFTWARE/Apache Software Foundation/Procrun 2.0/Tomcat6/Parameters/Java]"JvmMs"=dword:...
  • 今天发现一个服务的单元测试无法正常跑起来,使用jconsole发现老年代被塞满,框架加载的东西超出老年代限制无法GC导致的 该问题在gradle4.10不存在,在gradle6.5发生 思路 gradle官方文档说默认最大堆内存为512MB,...
  • 容器何时销毁现在很多服务采用容器化运行,一个容器中...例如:创建并运行一个Java容器,容器中运行某个jar文件作为服务。当容器中的这个Java进程终止时,容器也会销毁。服务进程的关闭结束或异常终止,一般可以通过...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 512
精华内容 204
关键字:

java服务限制内存

java 订阅