写点什么

Container 及其内部进程监控剖析

  • 2020-02-13
  • 本文字数:2917 字

    阅读完需:约 10 分钟

Container及其内部进程监控剖析

目前市场上的虚拟化技术种类很多,例如 moby(docker)、LXC、RKT 等等。在带来方便应用部署和资源充分利用的好处的同时,如何监控相应 Container 及其内部应用进程成为运维人员不可避免遇到的新情况。UAV.Container 从虚拟化技术的基础原理和 Linux 操作系统的内核特性出发,得到 Container 容器和内部进程的各维度监控数据,使无论是虚拟机或物理机运维人员,还是业务运维人员角度,都能得到合适的监控维度。


虚拟化技术从基础原理上主要是 cgroups、namespace 和 file system 的应用,而操作系统作为 cgroup 和 namespace 根节点,无论在 container 里启动何种应用,从内核角度上来说,肯定在操作系统有其一定的特征和表现形式。我们需要做的就是对这些特征做加工处理,以得到相应的监控数据。


下面我们以 docker 技术举例,其他虚拟化技术类似。

1. Container ID

Container ID 是一个 Container 的唯一标识。从容器监控的角度我们需要能得到该进程在哪个 Container 里运行。在操作系统层面,进程的 cgroup 的挂载情况就能有所体现。如图所示,我们在一个 ID 为 3411554ff684 的 Container 内部跑一个 Tomcat 进程。



由于 Container 的 pid namespace 是操作系统的 pid namespace 的子 namespace,那么该进程在操作系统级也应该有相应的 pid,用 docker top 命令验证一下:



该容器内进程在宿主机上的进程号为 1848。接下来进入/proc/1848/cgroup 下看看该进程的 cgroup 挂载情况



从 cgroup 文件里清楚的显示了实现了该容器的虚拟化技术、Container ID 和此 container 的资源挂载路径,对比一下这里面显示的 Container ID,和创建 Container 时的 ID 完全相同。这也验证了通过扫描宿主机进程的 cgroup 信息可以获得 Container ID。这样就将 pid 和 Container ID 做了关联。

2. CPU

虽然 cgroup 管控了该 cgroup 下所有进程的 CPU 使用情况,但从操作系统的角度上,不论进程是否隶属于某个子 cgroup 下,仍然是共用宿主机的 CPU。所以监控宿主机上该进程的 CPU 就能得到进程的 CPU 监控指标。


Linux 上常用的 CPU 监控命令是 top。top 对 CPU 监控的原理是在 time1 时刻获取 CPU 从启动时的累计总时间 countAll1 和 busy 总时间 countBusy1,再到 time2 时刻获取 CPU 总时间 countAll2 和 busy 总时间 countBusy2,最后用 busy 的时间差值减去总时间的差值得到了在 time1 到 time2 这个时间段内机器 CPU 的占用情况。也就是:


CPU 占用率(%) = (countBusy2 - countBusy1)/(countAll2 - countAll1) * 100


进程同理,在两个时刻分别得到每个进程的 busy 总时间 countProcBusy1 和 countProcBusy2,则得到进程 CPU 占用率:


进程 CPU 占用率(%) = (countProcBusy2 - countProcBusy1)/(countProcAll2 - countProcAll1)*100


宿主机从启动开始的 CPU 总时间片可以从/proc/stat 下获取:



第一行是总的 CPU 使用情况,具体参数的意思:


所以,选择当前为 time1,3 秒后为 time2,countAll = user + nice + system + idle + iowait + irq + softirq + stealstolean + guest + guest_nice。countBusy 为 countAll 减去 idle 的值,这样上面第一个公式的所有需要的值就齐了,可以直接计算。


第二行、第三行是每个逻辑 CPU 的使用情况,这里记下有两个逻辑 CPU,CPU 的逻辑核数与 CPU 显示模式 irix 和 solaris 有关。


接下来是 countProcBusy 的计算,进程的 CPU 时间片位于/proc/$pid/stat 下,如图所示:



这个文件里面体现了很多进程的相关信息。其中第 14、15、16、17 个参数与 CPU 有关。


所以,countProcBusy = utime + stime + cutime + cstime,该值包括其所有线程的 cpu 时间。而 countProcAll2-countProcAll1=3s,通过两个时刻的 countProcBusy 和 countProcAll,进程 CPU 的占用率就能得到了。


其中需要注意的问题有两点:


1).jiffies 实际上指的是内核时钟使用的节拍总数,所以这里的 jiffies 需要换算成秒才能应用上面的除法公式。


2).刚刚我们谈到 CPU 显示模式 irix 和 solaris,简单来说 irix 模式就是机器有 N 个逻辑 CPU,CPU 显示上限就是 N*100%,solaris 模式就是不管机器有多少逻辑 CPU,CPU 显示上限就是 100%,而/proc/$pid/stat 显示的是计算了所有逻辑 CPU 时间的,所以两种显示方式意味着计算方法稍有差异,solaris 模式的结果需要在上面进程 CPU 占用率公式基础之上除以逻辑核数。

3. 内存

进程内存的监控有两个维度的数据:一是物理占用内存大小,二是进程内存占用百分比的大小。


进程内存占用率(%) = 进程物理内存占用大小 / 宿主机总内存大小 * 100


与 CPU 类似,/proc/$pid/status 文件记录了进程物理内存使用情况,其中 VmRSS 即为该进程目前所占实际物理内存的大小。



/proc/meminfo 文件下记录了机器内存占用情况,这个文件很长,截取其中的一部分展示一下,MemTotal 就是宿主机总内存大小:



这样,这个进程的物理内存占用和机器总内存就都得到了,相应的进程内存的占用率也就得到了。

4. 磁盘 IO

磁盘 IO 获取也很简单,/proc/$pid/io 已经帮我们把这个进程的 io 情况记录下来了,但是与 CPU 类似,io 文件里存的也是该进程从启动到现在的 io 总量,那么:


磁盘 I/O(bytes/秒) = (time2 时刻 I/O – time1 时刻 I/O) / (time2 – time1)



其中的 read_bytes 和 write_bytes 分别为该进程从启动到目前为止的读取字节数和写入字节数,分别取 2 个时刻的值,根据上面的公式,就得到了该进程的磁盘 IO。

5. 端口号和连接数

由于 Network Namespace 对网络做了隔离,所以如果进程在 Container 内部运行,该进程的端口信息也应该是进程本身监听的端口号,而不是真正实际对外的端口,而 Container 内外端口的映射机制是由应用的虚拟化技术本身控制的,这就避免不了与实现容器的虚拟化技术打交道了,那么问题就转化成获取容器内进程本身监听的端口了。


/proc/$pid/net/tcp(tcp6,udp,udp6)就对端口号和连接数做了相应的历史记录。这些文件格式都类似,以 tcp6 举例



解释几个关键的 key:


因为 st = 0A 代表 listen,所以从其中挑选出 st = 0A 的数据,取出对应的 inode 号,这里这个 inode 号是 socket 号,则问题转换为了这个进程是否还存在这个 socket 号代表的 socket。在/proc/$pid/fd 下有该进程所有的 fd(file descriptor),截取一段举个例子。



每个文件描述符后面的软链实际上就是打开的文件,以 socket 开头的就是这个进程打开的 socket,在中括号中间的部分就是 socket 号。拿着这个 socket 号和上面 tcp6 里获得的 inode 号做一个匹配,如果对应上,那么 tcp6 里的 st = 0A 的端口就是这个进程监听的。至于容器内外端口的映射,这就需要根据应用的虚拟化技术的映射方法来获取了。连接数计算与端口扫描是同理的,区别只在于需要对 st = 01(establish)进行扫描计数累加。

总结:

  1. 上面的方法将容器内所有进程的 CPU、内存、磁盘 IO、端口号和连接数都拿到了。根据 Container ID 就可以对不同的 Container 的对应数据做加和,就获得了 Container 级的监控数据。

  2. 在容器内的进程是通过在操作系统级别反映出的 pid 和 Container ID 的对应关系来关联的。这样就可以通过读取/proc 下的文件来获取监控数据。


本文转载自宜信技术学院网站。


原文链接:http://college.creditease.cn/detail/178


2020-02-13 21:471066

评论

发布
暂无评论
发现更多内容

在API 接口的设计中数据的安全性和完整性,该如何保证?

伤感汤姆布利柏

在Vue3中如何实现四种全局状态数据的统一管理?

不在线第一只蜗牛

JavaScript vue.js 前端

云桌面VS传统PC:企业用户该如何取舍

青椒云云电脑

云桌面

天猫商品描述API返回值中的商品参数对比与竞品分析

技术冰糖葫芦

API 接口 API 文档 API 测试 API 性能测试

繁星·数智思享会第2期:流程挖掘,全知视角驱动业务增长

望繁信科技

流程挖掘 流程资产 流程智能 望繁信科技 数字换转型

浙江鲲鹏昇腾产业与人才创新论坛成功举办!

Geek_2d6073

什么是iPaaS?iPaaS选型、落地及案例分析

RestCloud

数据集成 应用集成 ipaas

打造你的专属语音助手,基于函数计算托管 CosyVoice 语音模型

阿里巴巴云原生

阿里云 云原生 函数计算

解锁保险新世界-带你走进保险基本法

京东科技开发者

活动预告|博睿数据将受邀出席GOPS全球运维大会上海站!

博睿数据

通义灵码 AI 程序员来了!丨阿里云云原生 9 月产品月报

阿里巴巴云原生

阿里云 云原生 通义灵码

博睿数据Bonree ONE全面适配HarmonyOS NEXT,守护鸿蒙原生应用稳健前行

博睿数据

Mac专用投屏工具:AirServer 7 for Mac 激活版

你的猪会飞吗

AIrserver7 Mac软件下载站 AirServer 7 mac激活版

拍立淘API返回值在商品数据分析中的应用

代码忍者

pinduoduo API API 性能测试

软件测试学习笔记丨二叉树:添加练习

测试人

软件测试

Code Review:探索工程实践之道

京东科技开发者

淘宝商品详情API返回值:深度挖掘其业务价值

代码忍者

pinduoduo API API 性能测试

精准监控,高效运营 —— 商品信息实时分析为商家带来新机遇

技术冰糖葫芦

API 接口 API 文档 API 测试 pinduoduo API API 性能测试

基于 Nginx 的大型互联网集群架构与实战方案

EquatorCoco

nginx 架构 运维

一文读懂HyperWorks的耦合求解功能

智造软件

CAE altair hyperworks

「软件设计哲学」于延保代码改造中的实践

京东科技开发者

登顶!智源BGE首开国产模型Hugging Face月度下载全球第一

智源研究院

如何挑选CDN加速器节点网络?

Ogcloud

CDN 网络加速 CDN加速 企业网络加速 CDN网络加速

3个步骤轻松集成Push Kit,实现App消息推送

快乐非自愿限量之名

人工智能 深度学习 HarmonyOS

没有方向盘和踏板,特斯拉发布无人驾驶出租车;字节豆包推出 AI 智能体耳机 Ola Friend丨 RTE 开发者日报

声网

内核级流量治理引擎Kmesh八大新特性解读

华为云开发者联盟

服务网格 ebpf Sidecar Kmesh

数据仓库 Palo 2.0 for Apache Doris 冷热分离原理分析

Baidu AICLOUD

数据仓库 数据仓库服务

Spring Boot3集成 LiteFlow 实现业务流程编排

江南一点雨

老韩运维知识解析系列02:深入理解网络监控指标与实战应用

Geek_a83400

Python:条件分支 if 语句全讲解

不在线第一只蜗牛

Python

阿里云可观测 2024 年 9 月产品动态

阿里巴巴云原生

阿里云 云原生 可观测

Container及其内部进程监控剖析_行业深度_周新宇_InfoQ精选文章