1. 首页 > 电脑手机 >

dockercpu限制 docker限速

Docker之Linux Cgroup实践

Docker通过cgroup技术实现对容器资源的限制,在我们自己的应用中通过对某些不重要的应用做cpu、内存资源上限的限制来确保任何时候重要的应用有足够的资源使用。下面是对docker容器做cpu与内存资源限制的实践记录,环境为centos7.2+docker1.12.6。

Linux Cgroup最主要的作用是为一个进程组设置资源使用的上限,这些资源包括CPU、内存、磁盘、网络等。在linux中,Cgroup给用户提供的操作接口是文件系统,其以文件和目录的方式组织在/sys/fs/cgroup路径下。更多的cgroup介绍可以阅读 、 、

等文章。

通过一个简单的例子,对一个进程的cpu使用率做限制,操作如下:

这里同样以cpu设置为例,探索docker容器是如何通过cgroup做限制的

由此可知在创建一个容器时:

这里仅对最为常用的两个参数--cpu-period、--cpu-quota做设置,使用stress服务做验证

这里针对--memory,--memory-swap,--memory-swappiness三个参数做实践

实践一(不设置--memory与--memory-swap)

经过一段时间,容器并没有发生oom,stats命令中的MEM %参数的值一直是100.00%

可知容器只有在设置了memory限制之后,--oom-kill-disable才会起作用

实践二(设置--memory,不设置--memory-swap):

根据docker文档说明,这时容器可以使用到的最大的内存为2倍的memory的内存(memory=memory-swap, 2倍=memory+memory-swap)

此时,经过一段时间的检测,并没有发生oom,docker stats stress:

实践三(设置--memory与--memory-swap)

由docker文档知,memory-swap等于memory+swap的和,因此要求memory-swap >= memory(Minimum memoryswap limit should be larger than memory limit)

MEM %的值也一直是在100.00%以内浮动,另外也可知LIMIT仅是memory的值

当前实践的机器的swap为5G,因此这里设置用完5Gswap

设置使用系统的swap超出5G

通过设置memory-swappiness参数使得容器禁用系统交换空间

上述是对容器较为常用的cpu与内存的限制做了一些实践记录,了解了docker是如何通过linux cgroup对容器的资源做的限制。当然除了cpu、内存之外的其他资源的限制我们同样可以通过实践的方式一点一点去探索,求证。

Docker容器生产实践1——永远设置容器内存限制

在默认情况下,docker容器并不会对容器内部进程使用的内存大小进行任何限制。对于PaaS系统而言,或者对于直接使用docker的用户而言,这非常危险。如果哪个业务容器,出现了内存泄漏;那么它可能会危害到整个主机系统,导致业务app容器所在的主机出现oom。本文将介绍着眼于docker对内存资源的使用,解释背后的原理。同时也给出k8s上如何配置内存限制的方法。

通过下面参数可以为容器设置一个内存使用量硬大小,当超出这个大小时刻,linux系统会根据配置设置决定是否进入oom-killer状态。

docker run --name zxy-docker -m 1g -it busybox bash

单位为:b,k,m和g

如果设置了-m参数,通常情况下如果容器使用内存量超过了设置的硬水线,那么linux的oom-killer触发,它将根据oom-score对容器内部进程进行oom kill。但是不影响宿主机上其他进程。

这个参数设置一定需要在容器run或者create过程中使用了-m参数才可以设置。设置了-m参数,如果容器使用内存超限了,那么oom-kill将触发。如果设置了--oom-kill-disable, 那么容器不会oom,但是此时容器内部申请内存的进程将hang,直到他们可以申请到内存(容器内其他进程释放了内存) 。

绝对不要在没有使用-m的时候设置--oom-kill-disable 因为这会影响到宿主机的oom-killer

docker 设置容器的-m是通过设置memory cgoup的memory.limit_in_bytes实现的。在没有设置-m的时候这个值为-1,表示容器使用的内存不受限制。

例如:

`bash>docker run --name zxy-memorylimit -it -m 1g docker-build:12.06 bash

bash>docker inspect zxy-memorylimit|grep -i pid

“Pid”:24360

bash>cat /proc/24360/cgroup|grep memory

9:memory:/docker/xxxxx

bash>cd /sys/fs/cgroups/memory/docker/xxxx

bash> cat memory.limit_in_bytes

1073741824`

--oom-kill-disable参数实际设置的就是这是了同级目录之下的memory.oom_control,设置此参数就相当于做了如下动作

bash> echo 1 >memory.oom_control

对linux memory cgroup感兴趣的朋友可以参考:

一文

在上一节中,我们介绍了-m硬限制容器使用的内存资源。一旦设置了这个-m参数,那么容器内进程使用量超过这个数值,就会被杀或者hang住。docker还提供了一种soft limit就是--memory-reservation,单位和-m一致。当设置了这个参数以后, 如果宿主机系统内存不足,有新的内存请求时刻,那么linux会尝试从设置了此参数的容器里回收内存,回收的办法就是swap了。那么如果此容器还在继续使用内存,那么此容器会遇到很大的性能下降 。

通常实践是设置--memory-reservevation 的值小于-m的值。

和-m参数一致,此参数docker也是借助于memory cgroup的memory.soft_limit_in_bytes 实现。

2、一个进程是否使用了swap空间以及使用了多少swap空间,可以用/proc/$pid/smap中所有内存区域的swap值进行累加可以计算出

docker做的工作实际上是由runc完成的,docker 创建的hostconfig.json文件(也就是oci接口文件)中,有如下字段描述-m,--memory-reservation等内存资源限制参数:

memory MemoryReservation MemorySwap MemorySwappiness

下文节选自

limits:

cpu: 100m

memory: 100Mi

`

其中limits节限制memory设置的就是docker 容器的-m,而且k8s仅仅使用了-m参数其他参数都没有使用。

06-Docker资源限制

默认情况下,容器没有资源限制,可以使用主机内核调度程序允许的尽可能多的给定资源,Docker 提供了控制容器可以限制容器使用多少内存或CPU 的方法,设置 docker run 命令的运行时配置标志。

其中许多功能都要求宿主机的内核支持Linux 功能,要检查支持,可以使用 docker info 命令,如果内核中禁用了某项功能,可能会在输出结尾处看到警告,如下所示:

对于Linux 主机,如果没有足够的内存来执行其他重要的系统任务,将会抛出OOM (Out of Memory Exception,内存溢出、内存泄漏、内存异常), 随后系统会开始杀死进程以释放内存,凡是运行在宿主机的进程都有可能被kill,包括Dockerd和其它的应用程序,如果重要的系统进程被Kill,会导致和该进程相关的服务全部宕机。

linux 会为每个进程算一个分数,最终它会将分数最高的进程kill。

Docker 可以强制执行硬性内存限制,即只允许容器使用给定的内存大小。

dockercpu限制 docker限速dockercpu限制 docker限速


Docker 也可以执行非硬性内存限制,即容器可以使用尽可能多的内存,除非内核检测到主机上的内存不够用了。

这些选项中的大多数采用正整数,后跟 b、k、m、g 后缀,以表示字节、千字节、兆字节或千兆字节。

--memory-swap , 只有在设置了 --memory 后才会有意义。使用Swap,可以让容器将超出限制部分的内存置换到磁盘上,

不同的 --memory-swap 设置会产生不同的效果:

假如一个容器未做内存使用限制,则该容器可以利用到系统内存最大空间,默认创建的容器没有做内存资源限制。

启动两个工作进程,每个工作进程最大允许使用内存256M,且宿主机不限制当前容器最大内存:

接着宿主机限制容器最大内存使用:

宿主机cgroup 验证:

--memory-reservation

宿主机cgroup 验证:

一个宿主机,有几十个核的CPU,但是宿主机上可以同时运行成百上千个不同的进程用以处理不同的任务,多进程共用一个CPU 的核心依赖计数就是为可压缩资源,即一个核心的CPU 可以通过调度而运行多个进程,但是同一个单位时间内只能有一个进程在CPU 上运行,那么这么多的进程怎么在CPU 上执行和调度的呢?

Linux kernel 进程的调度基于CFS(Completely Fair Scheduler),完全公平调度

默认情况下,每个容器对主机CPU 周期的访问权限是不受限制的,但是我们可以设置各种约束来限制给定容器访问主机的CPU周期,大多数用户使用的是默认的CFS 调度方式,在Docker 1.13 及更高版本中,还可以配置实时优先级。

参数 :

对于一台2核的服务器,如果不做限制,容器会把宿主机的CPU 全部占完:

在宿主机使用 dokcer stats 命令查看容器运行状态:

在宿主机查看CPU 限制参数:

宿主机CPU 利用率:

只给容器分配最多1核宿主机CPU 利用率

宿主机cgroup 验证:

当前容器状态:

宿主机CPU利用率:

容器运行状态:

宿主机CPU利用率:

启动两个容器,stress1 的 --cpu-shares 值为1000 , stress2 的 --cpu-shares 为500,观察最终效果, --cpu-shares 值为1000 的 stress1的CPU 利用率基本是 --cpu-shares 为500 的 stress1的 2 倍:

验证容器运行状态:

宿主机cgroups验证:

动态修改CPU shares的值

--cpu-shares 的值可以在宿主机cgroup 动态修改,修改完成后立即生效,其值可以调大也可以减小。

验证修改后的容器运行状态:

Docker项目部署内存占用过高的问题解决

本文主要针对docker来部署java程序的时候,常常会出现内存占有很大的问题,通过调整docker的配置来限制内存占用

测试环境下服务器的配置为24核64G内存,启动微服务,在没有进行内存限制的时候,我们通过 docker stats 命令查看一下微服务的内存占用,如下图

我们看一下Dockerfile文件的配置

对应的启动脚本 start.sh 的配置如下:

我们再看一下docker-compose的配置

配置中都没有对docker内存以及jvm内存做任何限制,导致了我们docker容器启动,占用内存过大的问题

首先我们对java启动时jvm内存大小做个调整,增加jvm启动参数 -Xms1024M -Xmx1024M -Xmn256M -Xss256K

调整后的启动脚本 start.sh 如下:

调整完jvm启动参数之后,重新启动容器,结果如下:

发现内存使用上已经根据我们调整的大小降了下来

到这里,问题基本解决,不过看到容器的内存限制还是62G,这样显然还是不合理的,我们也要对容器进行调整,调整方式有两种

直接指定容器最多使用 200M 物理内存和 200M swap。

其中mem_limit用于控制容器默认启动时会使用 1/16*物理内存的现象,导致几个服就占满了全部内存。

v3版本中,配置如下:

注意 deploy 仅 docker deploy stack 生效

或使用 docker-compose --compatibility up 生效

配置完成之后,重启docker服务,如下图:

容器内存限制发生了变化,达到了我们的预期效果

1. JVM常用启动参数

2. 如何限制docker容器的内存大小

3. 在Docker Compose file 3下限制CPU与内存

docker读不到cpu数量

看了很多书都说docker来部署应用可以隔离系统资源互不影响,直到这段时间出现的一系列问题又颠覆了我的认知。

发现docker并不能隔离真正隔离系统资源。最近k8s中的某一个应用总是被强制重启,由于监控体系没有完善,找了好久都没有找到原因,之前也有其它应用类似的问题是应为metaspace溢出导致的,但是此次事务毫无报错,严重时一天重启三次。有时候又一连好几天个把月没有问题。为了不让五一小长假的美好心情被破坏,觉定把这个问题彻底解决掉,好吧其实放假的第一天就被破坏了,当天重启了3次,为了后续的美好日子,决定把它根因找出来。看k8s日志发现每次重启都是健康检查失败导致重启,于是推断以下几种可能:

jvm 频繁GC导致进程stw挂起liveless prob探针超时

系统cpu负载过高导致处理超时

正对两种情况进行对应排查,有时候排查问题也是有点小麻烦,只能绕着想点其它办法,比如skywalking和arthas的冲突问题,比如docker包只打了jre,好吧就只能打印GC日志来观察情况了,排查过程就不讲了,反正排查半天最后发现内存方面没有问题。

所以就考虑第二种情况,cpu负载问题导致超时,于是先用top观察负载。发现load average值大概在8左右,但是发现这个负载值时机器的总平均负载,没办法查看当前docker容器的情况,但是这也不影响我做出正确的推断,配置的cpu核心数为0.5-1,宿主机和cpu核心数为16,相对16核心数8的负载算正常范围,忽然间又想到这个负载时基于进程级别的,要是我应用的线程数过多,而docker限制了cpu核心数,那么这里会不会出现问题呢?也就是当我进程中的一个线程在使用cpu时其它线程用不了,尽管cpu还有空闲,但是进程内的线程就不断产生上下文切换,导致探针超时,这个也完全有可能,于是按用top -H -p pid 查看线程情况,发现好家伙开了300多个线程,才配置0.5到1核的cpu 这个确实有点过分了。在观察的过程中发现间隔一分钟cpu使用率还会暴涨一次,好吧这个应用是个定时任务,每隔1分钟就会有10几个定时任务同时进来然后开3个线程处理这个10几个定时任务,每个线程进来又开了cpu核心x10个线程去处理子任务,那么如果此时有大量业务数据需要处理就会产生大量的上下文切换,就非常有可能导致探针请求超时。但是按道理说探针超时10秒这个也不太可能吧?

于是接着想到假如cpu又被其它docker容器的进程占用了呢?也就是说当前应用除了跟自己抢占资源外还需要跟其它的进程抢占资源,所以有可能等待更久。也就是这个应用本身是个cpu密集型的应用,给的cpu过少了。看代码的过程中又发现一个坑爹的地方,应用配置的默认线程数是cpu核心数*10,由于docker容器中获取cpu核心数不准确的问题,导致cpu核心数获取到的是宿主机真正核心数16 也就是说实际上是3个线程各自开了160个线程在处理业务,意味着高峰期线程数可能达到480+其它线程的数量,这才导致了探针超时,因为轮半天可能每轮到它执行。

给线程池设置个参数,别开160个线程,外加增加cpu核心数重启完美解决此问题。

docker 如何限制和查看container 内存 和cpu

1. 通过top命令查看机器目前已消耗内存及cpu使用数量,linux下输入top,然后在输入1就会出现cpu使用情况

2. docker 启动时限制cpu 和内存,--cpus 设置使用cpu数量 -m 设置使用内存

设置目的是为了不影响其他服务正常运行。

docker run -i -d --cpus 4 -m 12GB -v $PWD:/celery_works/aa image ID jupyter notebook --allow-root --ip 0.0.0.0

备注:通过top命令查看cpu和内存使用情况,设置合理的cpu和内存确保不影响正常服务的运行

dockercpu限制 docker限速dockercpu限制 docker限速


3. 查看 启动的container占用cpu 和内存

docker stats contrainer id

4. 容器用完后记得删除,使用docker kill contrainer id命令删除不用的container

5. 总结:

1. top命令查看空闲的内存和cpu

2. docker 启动时限制cpu和内存

dockercpu限制 docker限速dockercpu限制 docker限速


3. docker stats 查看容器消耗cpu和内存

4. 容器用完后记得删除,通过docker kill 命令删除

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至836084111@qq.com 举报,一经查实,本站将立刻删除。

联系我们

工作日:9:30-18:30,节假日休息