经常发现生产环境CPU运行很高,我们想知道到底是什么代码这么消耗CPU
TOP命令
此时我们经常使用top来找到 CPU 使用率比较高的一些线程
容器中的docker
备注: 如果是docker 中的top命令。需要关注,一般来说不需要,挂载内容的多少一般和镜像有关。一般的redhat/ubuntu镜像都是会挂载内存CPU信息的,精简的dokcer镜像信息会少些,有时top得到的信息不全面。为什么docker top命令是这样
所以docker不能做到操作系统资源隔离,比如/proc 、/sys 、/dev/sd*等目录未完全隔离,SELinux、time、syslog等所有现有Namespace之外的信息都未隔离。
Docker是利用CGroups实现资源限制的,只能限制资源消耗的最大值,而不能隔绝其他程序占用自己的资源;
在Docker容器中执行top、free等命令,会发现看到的资源使用情况都是宿主机的资源情况,而我们需要的是这个容器被限制了多少CPU,内存,当前容器内的进程使用了多少;
在容器里修改/etc/sysctl.conf,会收到提示”sysctl: error setting key ‘net.ipv4….’: Read-only file system”;
程序运行在容器里面,调用API获取系统内存、CPU,取到的是宿主机的资源大小;
对于多进程程序,一般都可以将worker数量设置成auto,自适应系统CPU核数,但在容器里面这么设置,取到的CPU核数是不正确的,例如Nginx,其他应用取到的可能也不正确,需要进行测试。
JVM默认的最大Heap大小是系统内存的1/4,假若物理机内存为10G,如果你不手动指定Heap大小,则JVM默认Heap大小就为2.5G。JavaSE8(<8u131)版本前还没有针对在容器内执行高度受限的Linux进程进行优化,JDK1.9 以后开始正式支持容器环境中的CGroups内存限制,JDK1.10 这个功能已经默认开启,可以查看相关。熟悉JVM内存结构的人都清楚,JVM Heap是一个只增不减的内存模型,Heap的内存只会往上涨,不会下降。在容器里面使用Java,如果为JVM未设置Heap大小,Heap取得的是宿主机的内存大小,当Heap的大小达到容器内存大小时候,就会触发系统对容器OOM,Java进程会异常退出。
Docker从1.8开始可以通过CGroups信息挂载进容器内部。在k8s中,如果指定了request和limit参数
当为Pod指定了requests,其中 requests.cpu 会作为–cpu-shares 参数值传递给 docker run 命令,当一个宿主机上有多个容器发生CPU资源竞争时这个参数就会生效,参数值越大,越容易被分配到CPU,requests.memory 不会作为参数传递给Docker,这个参数在Kubernetes的资源QoS管理时使用;
当为Pod指定了limits,其中 limits.cpu 会作为 --cpu-quota 参数的值传递给 docker run 命令,docker run 命令中另外一个参数 --cpu-period 默认设置为100000,通过这两个参数限制容器最多能够使用的CPU核数,limits.memory 会作为 --memory 参数传递给docker run命令,用来限制容器内存,目前Kubernetes不支持限制Swap大小,建议在部署Kubernetes时候禁用Swap。
# 读取CPU核数,除以100000得到的就是容器核数
cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us
# 获取容器内存使用情况(USAGE) 除以1024 (KB) 除以1024 M
cat /sys/fs/cgroup/memory/memory.usage_in_bytes
# 获取容器内存使用情况(LIMIT)
cat /sys/fs/cgroup/memory/memory.limit_in_bytes
# 获取容器是否被设置了OOM,是否发生过OOM oom_kill_disable默认为0,表示打开了oom killer,就是当内存超时会触发kill进程。可以在使用docker run时候指定disable oom,将此值设置为1,关闭oom killer
# under_oom 这个值仅仅是用来看的,表示当前的CGroups的状态是不是已经oom了,如果是,这个值将显示为1。
cat /sys/fs/cgroup/memory/memory.oom_control
# 获取磁盘的IO
cat /sys/fs/cgroup/blkio/blkio.throttle.io_service_bytes
# 获取容器虚拟网卡入/出流量
cat /sys/class/net/eth0/statistics/rx_bytes
cat /sys/class/net/eth0/statistics/tx_bytes
最高的PID转换成16进制的nid
printf '%x\n' pid