docker读不到cpu数量

docker读不到cpu数量,第1张

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

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

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

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

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

所以就考虑第二种情况,cpu负载问题导致超时,于是先用top观察负载。发现load average值大概在8左右,但是发现这个负载值时机器的总平均负载,没办法查看当前docker容器的情况,但是这也不影响我做出正确的推断,配置的cpu核心数为05-1,宿主机和cpu核心数为16,相对16核心数8的负载算正常范围,忽然间又想到这个负载时基于进程级别的,要是我应用的线程数过多,而docker限制了cpu核心数,那么这里会不会出现问题呢?也就是当我进程中的一个线程在使用cpu时其它线程用不了,尽管cpu还有空闲,但是进程内的线程就不断产生上下文切换,导致探针超时,这个也完全有可能,于是按用top -H -p pid 查看线程情况,发现好家伙开了300多个线程,才配置05到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核心数重启完美解决此问题。

 Device Year Class 的主要功能是根据 CPU核数、时钟频率 以及 内存大小 对设备进行分级。代码很简单,只包含两个类:DeviceInfo-> 获取设备参数,YearClass-> 根据参数进行分级。下表是 Facebook 公司提供的分级标准,其中Year栏表示分级结果。Year Cores Clock RAM2008 1 528MHz 192MB2009 n/a 600MHz 290MB2010 n/a 10GHz 512MB2011 2 12GHz 1GB2012 4 15GHz 15GB2013 n/a 20GHz 2GB2014 n/a >2GHz >2GB关于输出年份的计算方法可以参考源码,本文只把一些比较常用的功能抽取出来做一个简要介绍。获取 CPU 核数我们都知道,Linux 中的设备都是以文件的形式存在,CPU 也不例外,因此 CPU 的文件个数就等价与核数。Android 的 CPU 设备文件位于/sys/devices/system/cpu/目录,文件名的的格式为cpu\d+。12345678910root@generic_x86_64:/sys/devices/system/cpu # ls <b>cpu0</b> cpufreqcpuidlekernel_maxmodaliasofflineonlinepossiblepowerpresentuevent统计一下文件个数便可以获得 CPU 核数。1234567891011121314151617181920212223242526272829303132333435public static int getNumberOfCPUCores() {if (BuildVERSIONSDK_INT <= BuildVERSION_CODESGINGERBREAD_MR1) {// Gingerbread doesn't support giving a single application access to both cores, but a// handful of devices (Atrix 4G and Droid X2 for example) were released with a dual-core// chipset and Gingerbread; that can let an app in the background run without impacting// the foreground application But for our purposes, it makes them single corereturn 1;}int cores;try {cores = new File("/sys/devices/system/cpu/")listFiles(CPU_FILTER)length;} catch (SecurityException e) {cores = DEVICEINFO_UNKNOWN;} catch (NullPointerException e) {cores = DEVICEINFO_UNKNOWN;}return cores;}private static final FileFilter CPU_FILTER = new FileFilter() {@Overridepublic boolean accept(File pathname) {String path = pathnamegetName();//regex is slow, so checking char by charif (pathstartsWith("cpu")) {for (int i = 3; i < pathlength(); i++) {if (pathcharAt(i) < '0' pathcharAt(i) > '9') {return false;}}return true;}return false;}};回到顶部获取时钟频率获取时钟频率需要读取系统文件 -/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq或者/proc/cpuinfo。我的 Android 模拟器中并没有cpuinfo_max_freq文件,因此只能读取/proc/cpuinfo。/proc/cpuinfo包含了很多 cpu 数据。processor : 0vendor_id : GenuineIntelcpu family : 6model : 70model name : Intel(R) Core(TM) i7-4770HQ CPU @ 220GHzstepping : 1cpu MHz : 0000cache size : 1024 KBfdiv_bug : nohlt_bug : nof00f_bug : nocoma_bug : nofpu : yesfpu_exception : yescpuid level : 4wp : yes代码如下:public static int getCPUMaxFreqKHz() {int maxFreq = DEVICEINFO_UNKNOWN;try {for (int i = 0; i < getNumberOfCPUCores(); i++) {String filename ="/sys/devices/system/cpu/cpu" + i + "/cpufreq/cpuinfo_max_freq";File cpuInfoMaxFreqFile = new File(filename);if (cpuInfoMaxFreqFileexists()) {byte[] buffer = new byte[128];FileInputStream stream = new FileInputStream(cpuInfoMaxFreqFile);try {streamread(buffer);int endIndex = 0;//Trim the first number out of the byte bufferwhile (buffer[endIndex] >= '0' && buffer[endIndex] <= '9'&& endIndex < bufferlength) endIndex++;String str = new String(buffer, 0, endIndex);Integer freqBound = IntegerparseInt(str);if (freqBound > maxFreq) maxFreq = freqBound;} catch (NumberFormatException e) {//Fall through and use /proc/cpuinfo} finally {streamclose();}}}if (maxFreq == DEVICEINFO_UNKNOWN) {FileInputStream stream = new FileInputStream("/proc/cpuinfo");try {int freqBound = parseFileForValue("cpu MHz", stream);freqBound = 1000; //MHz -> kHzif (freqBound > maxFreq) maxFreq = freqBound;} finally {streamclose();}}} catch (IOException e) {maxFreq = DEVICEINFO_UNKNOWN; //Fall through and return unknown}return maxFreq;}回到顶部获取内存大小如果 SDK 版本大于等于JELLY_BEAN,可以通过ActivityManager来获取内从大小。 ActivityManagerMemoryInfo memInfo = new ActivityManagerMemoryInfo();ActivityManager am = (ActivityManager) cgetSystemService(ContextACTIVITY_SERVICE);amgetMemoryInfo(memInfo);如果版本低于JELLY_BEAN,则只能读取系统文件了。FileInputStream stream = new FileInputStream("/proc/meminfo");totalMem = parseFileForValue("MemTotal", stream);完整代码如下: @TargetApi(BuildVERSION_CODESJELLY_BEAN)public static long getTotalMemory(Context c) {// memInfototalMem not supported in pre-Jelly Bean APIsif (BuildVERSIONSDK_INT >= BuildVERSION_CODESJELLY_BEAN) {ActivityManagerMemoryInfo memInfo = new ActivityManagerMemoryInfo();ActivityManager am = (ActivityManager) cgetSystemService(ContextACTIVITY_SERVICE);amgetMemoryInfo(memInfo);if (memInfo != null) {return memInfototalMem;} else {return DEVICEINFO_UNKNOWN;}} else {long totalMem = DEVICEINFO_UNKNOWN;try {FileInputStream stream = new FileInputStream("/proc/meminfo");try {totalMem = parseFileForValue("MemTotal", stream);totalMem = 1024;} finally {streamclose();}} catch (IOException e) {}return totalMem;}}

以上就是关于docker读不到cpu数量全部的内容,包括:docker读不到cpu数量、如何获取 Android 设备的CPU核数,时钟频率以及内存大小、等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/10088951.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-05
下一篇 2023-05-05

发表评论

登录后才能评论

评论列表(0条)

保存