docker读不到cpu数量

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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核心数重启完美解决此问题。
参考技术A 看了很多书都说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核心数重启完美解决此问题。
参考技术B 可能是因为docker容器中没有安装cpuinfo工具,可以尝试在docker容器中安装cpuinfo工具,然后使用命令“cat /proc/cpuinfo”来查看CPU数量。

docker容器之限制CPU

1、容器如何对CPU进行限制?

默认设置下,所有容器可以平等地使用 host CPU 资源并且没有限制。
Docker 可以通过 -c 或 --cpu-shares 设置容器使用 CPU 的权重。如果不指定,默认值为 1024。
与内存限额不同,通过 -c 设置的 cpu share 并不是 CPU 资源的绝对数量,而是一个相对的权重值。某个容器最终能分配到的 CPU 资源取决于它的 cpu share 占所有容器 cpu share 总和的比例。
换句话说:通过 cpu share 可以设置容器使用 CPU 的优先级。
比如在 host 中启动了两个容器:
docker run --name "container_A" -c 1024 ubuntu
docker run --name "container_B" -c 512 ubuntu
container_A 的 cpu share 1024,是 container_B 的两倍。当两个容器都需要 CPU 资源时,container_A 可以得到的 CPU 是 container_B 的两倍。
需要特别注意的是,这种按权重分配 CPU 只会发生在 CPU 资源紧张的情况下。如果 container_A 处于空闲状态,这时,为了充分利用 CPU 资源,container_B 也可以分配到全部可用的 CPU。

2、如何用progrium/stress来测试容器对CPU的限制?

a、启动 container_A,cpu share 为 1024:
技术图片

--cpu 用来设置工作线程的数量。因为当前 host 只有 1 颗 CPU,所以一个工作线程就能将 CPU 压满。如果 host 有多颗 CPU,则需要相应增加 --cpu 的数量。
b、启动 container_B,cpu share 为 512:
技术图片

c、在 host 中执行 top,查看容器对 CPU 的使用情况:
技术图片

d、现在暂停 container_A:
docker pause container_a
e、top 显示 container_B 在 container_A 空闲的情况下能够用满整颗 CPU:
技术图片

3、如何设置容器的CPU不共享,就使用其中的两个CPU?

试试 --cpuset-cpus

4、容器创建完成后还可以进行CPU和内存的相关设置吗?

只能在创建的时候设置。执行docker run后就没有办法修改了。
















以上是关于docker读不到cpu数量的主要内容,如果未能解决你的问题,请参考以下文章

win8的ntoskrnl.exe非常占CPU和狂读硬盘怎么解决

centos8系统安装后,插网线读不到网络怎么办

mysql读不到数据库里的数据

Spring Data Redis怎么读不到我刚才设进去的值?

Spring Data Redis怎么读不到我刚才设进去的值?

gulp-sass:错误 - 找不到要导入的文件或不可读