写点什么

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:471240

评论

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

3分钟全面了解API Moke

优测云服务平台

Mock API 编排 Mock 服务 API 接口 API 测试

作为新手小白,你应该了解的五个3DMAX的使用干货小技巧!

Finovy Cloud

3ds Max

直播预告 | 博睿学院:探索ES在日志场景的应用

博睿数据

可观测性 博睿数据 智能运维AIOps 博睿学院

面向金融科技方向选手!一级学会背书,AI选股与可视分析大赛来啦

飞桨PaddlePaddle

人工智能 百度 paddle 飞桨 百度飞桨

几种常用到的 Hybrid App 技术框架

Onegun

flutter React Native Hybrid

什么是多运行时架构?

互联网工科生

分布式 服务化 单机

Footprint Analytics 宣布 20+ 链 API 免费增速,助力熊市 buidler

Footprint Analytics

区块链 NFT Footprint

加强Web应用程序安全:防止SQL注入

树上有只程序猿

sql Web ORM

开放原子开源基金会理事长孙文龙一行赴山东大学考察交流

开放原子开源基金会

开源 开放原子开源基金会

统一观测|借助 Prometheus 监控 ClickHouse 数据库

阿里巴巴云原生

阿里云 云原生 Prometheus Clickhouse

【AI模型系列】中国AI大模型峰会“封神之作”,不容错过的大模型机遇

颜淡慕潇

AI大模型 峰会 WAVE SUMMIT

代码随想录Day23 - 二叉树(九)

jjn0703

TE智库 |《中国CLM(合同全周期管理)市场产业全景研究报告》发布,看合同管理赋能企业战略落地

TE智库

高并发与性能优化的神奇之旅

互联网工科生

性能优化 数据 高并发

火山引擎数智平台旗下DataWind升级半年报 6大功能助力企业数据消费

字节跳动数据平台

数据库 大数据 企业号 8 月 PK 榜

【参赛有奖】云原生编程挑战赛·赛道 2 邀你来战!

阿里巴巴云原生

阿里云 阿里云云原生

如何在Windows上将iOS应用上传到App Store

Last Week in Milvus

Zilliz

非结构化数据 开源社区 Milvus Zilliz

Seata 1.7.0 正式发布,大幅度提升稳定性

阿里巴巴云原生

阿里云 云原生 seata

证券机构数据治理实践,实现数据的“管、 治、用”

袋鼠云数栈

数字化转型 金融

开放原子开源基金会理事长孙文龙一行赴浪潮考察交流

开放原子开源基金会

开源

阿里云率先荣获容器集群稳定性先进级认证

阿里巴巴云原生

阿里云 云原生 容器服务

分布式系统常见理论讲解

越长大越悲伤

分布式 后端 一致性

RocketMQ 在业务消息场景的优势详解

阿里巴巴云原生

阿里云 RocketMQ 云原生

代码随想录Day35 - 贪心算法(四)

jjn0703

信科技AntDB数据库专家参加向量数据库首次技术标准研讨会

亚信AntDB数据库

数据库 AntDB AntDB数据库 企业号 7 月 PK 榜

大模型真的会“好事多模”吗?

白洞计划

多模态 大模型

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