背景

atop 是一款开源的单机性能监测工具,支持实时观测的同时、也支持读取历史文件排查问题。另外一个优点是除提供 CPU、MEM、DISK 等全局指标外,还提供进程、线程级别的各项指标监控数据。鉴于 atop 的这些优点,字节跳动基于社区的 atop 进行优化,目前已迭代 3 个版本,稳定运行接近三年。本文将和大家分享字节跳动内部 atop 工具的新特性及使用情况。

传统特性介绍What - atop 是什么

atop 本身是一个单机性能监测工具,每间隔 interval(实时监控默认间隔是 10s,而后台采集社区默认间隔是 600s,即 10min)时间去采集本机常用的全局指标和进程指标。直接执行atop即可展示,大致分为上下两部分,分别展示全局指标和进程指标。同时支持快捷键切换多种“界面模式”,用于专门查看进程的 CPU、内存、磁盘等指标信息。

直观展示

idea数据分层分析(线上系统的性能监控实践)(1)

运行方式

根据用户使用需求,能够以多种形式运行。一种是直接运行 atop 二进制,显示实时数据;一种是以服务形式(systemd 或 SysV Init)部署在物理机、虚拟机或容器里,作为常驻进程,采集数据写入磁盘,以天为分割单位计入不同文件;一种是使用atop -r $atop_log_file按需读取历史数据。是一款少见的能够支持查看详细历史记录的工具,这在定位非实时问题时尤其有帮助。

代码结构

idea数据分层分析(线上系统的性能监控实践)(2)

When - 什么时候使用 atop

atop 记录了很多指标,如全局的 cpu、CPL、MEM、DISK、NET、PSI,进程的 PID、PPID、TID、CMD、SYSCPU、USRCPU、CPUNR、RSIZE、PSIZE、RDDSK、WRDSK 等,称得上一个大而全的工具。而 atop 本身占有资源很少,并不会带来额外的性能开销。因此很多场景都可以使用 atop 来查看各种指标,进而帮助用户更好的了解业务进程在操作系统中的呈现。举例如下:

集群

目前上游还不支持 atop 指标在集群粒度的聚合,但字节内部提供 JSON 数据的输出,可通过数据处理一系列流程将隶属同一集群的所有机器的 atop 数据都入库存储(可选择性按时间对数据进行稀释)。并按照业务需求加以展示,如分别对全局常用指标和某类业务(多进程 PID 加以聚合)各项指标绘制成曲线图,用于观测 24h 时间周期内的数据变化;也可以用于统计基础服务的利用率。

单机

在线排查

业务高峰期,如果发现抖动,可直接运行atop综合查看全局指标和进程指标的哪项指标异常,进而定位排查问题。一般来说先观察全局指标来缩小范围,看是 CPU、MEM、磁盘读写、网络中的哪项引发的问题。常见问题有,如果总 CPU 的 sys 态及 user 态飙高、并且只有几个单 CPU 核很高,多半是绑核不均匀引起的;如果 CPL(CPU Load Average)不高但 CPU 的中断 irq 很高,多半是 io 操作引发的。

历史定位

前文提到过,常用的监控工具中,能够提供详细历史数据并且能高效保存的几乎没有;如果需要存储,需要人工干预、打通整个流程。而 atop 本身提供了日志存储功能,并自带日志压缩机制,尽量确保存储无压力。为保证历史日志不会将系统盘打满,字节开发了定制化存储位置和存储天数的功能,将在下文详细说明。

功能上线

atop 有个 interval 参数,可通过配置,来定制化数据采集的间隔,如 10s、甚至 1s。如果业务有新功能上线,想自测新功能对系统带来的影响,可以将 interval 设置成 1 秒,实时观测各指标的动态变化。

性能优化

atop 提供细粒度的进程态各项指标值的展示,在业务调优过程中,可参考进程态的数据变化来衡量调优是否符合预期。

告警辅助

atop 的数据比较全,有很多其他监控工具不具备的指标,如 oom-kill、per NUMA 指标等。可用于告警数据来源的补充。

How - 如何使用 atop

atop 针对全局指标和进程指标分别提供了很多快捷键,供用户查看更多的指标。接下来列举一些常见问题,详细参数可以通过man atop进行查看。

如何使用 atop?如何查看历史数据?

用户可直接运行 atop 命令查看实时的信息,也可以通过 atop -r /var/log/atop/atop_$date 文件查看历史信息。读取文件时有多种交互方式,比如-b 代表从什么时刻开始读,-e 代表读取到什么时刻(在社区支持分钟级别读取的基础上,字节内部支持秒级别读取)。快捷键说明如下图:

快捷键说明b输入时间,格式为"12:23"(时:分)t前进 10sT后退 10sg按 CPU 使用率排序,默认排序方式m按内存使用率降序排列d按磁盘使用率降序排列y查看线程信息j查看 container 聚合信息c查看详细的 command linel定制化查看每个 CPU 核/每个磁盘/每个网卡的信息f展示全局指标中 fixed 的指标Q根据进程状态过滤,如 R|S|D|Z 等I按照 PID 进行搜索(注:大写的 i)

非 root 用户是否可以查看日志?

可以,默认有读权限。但是安装包、重启服务、修改日志存储天数等还是需要 root 权限。但非 root 用户按 d 无权限实时查看进程的磁盘信息。这是因为非 root 用户默认被禁止读取其他用户的/proc/$pid/io 文件,反映到 atop 代码里就是没有设置相关标志位,导致无法查看磁盘。

但查看历史文件数据可以打消这个魔咒,也就是说非 root 用户可以通过atop -r /var/log/atop/atop_$date 查看磁盘相关数据,毕竟 atop 写日志时是以 root 用户在运行。

atop 如何查看线程信息

默认只有进程信息展示,按 y 可查看线程。如下图,白色为进程,黄色为该进程的所有线程。再次按 y,线程展示消失。

idea数据分层分析(线上系统的性能监控实践)(3)

netatop:记录进程态网络指标

进程态网络相关的指标是通过定制化安装 netatop kernel module 完成的。本质上是通过 netfilter hook 获取进程数据,额外有个 netatopd daemon 负责数据记录及压缩。在数据量比较大的场景,会影响到性能,因此默认不开启该功能。如果开启,可以按 n 查看 per 进程的网络指标。

磁盘常见问题字节版新特性一览NUMA 聚合

随着云原生场景的推进,各云厂商正尝试将不同特征的业务(如优先级不同、延迟敏感度不同的多个业务)混部在同一台物理机上,尽量充分地将机器的物理资源利用起来,以提高单机的资源利用率。常见的混部场景有在离线混部,而常用的混部手法是将不同业务绑定不同 NUMA,从物理上达到隔离。那么查看 NUMA 粒度而不是整机粒度的 CPU、MEM 等指标则更有意义。基于这迫切的需求,字节内部实现了 NUMA 的监控粒度,相关代码已被社区接收,展示效果如下:

https://github.com/Atoptool/atop/pull/163

  • 支持 per NUMA 粒度内存相关信息查看

例:一台 4NUMA 的机器,其 NUM(Memory per NUMA)展示如下图

idea数据分层分析(线上系统的性能监控实践)(4)

  • 支持查看 per NUMA 内存碎片化,使用百分比展示

例:如上图 NUM 的 frag 字段。

  • 支持 per NUMA 粒度 CPU 相关指标的聚合

例:一台 4NUMA,运行了虚拟机的 arm 机器上,其 NUC(CPU per NUMA)展示如下图

idea数据分层分析(线上系统的性能监控实践)(5)

JSON 格式输出

前文提到过,目前社区不支持 atop 指标在集群粒度的聚合;除此之外,atop 作为一个单机工具,如果业务想查看某台服务器的监控,需要申请权限登录到机器上,这在某些场景下比较受限。因此想到有没有一种方式,针对拥有某个集群机器权限的同学来说,可以直接查看该集群内所有机器的 atop 数据,而无需再走工单申请单台机器权限,即网页版 atop。

考虑到数据处理过程中 JSON 数据的强兼容性,敲定将 atop 的原始数据以 JSON 数据输出:支持输出到终端,以及写本地 unix domain socket。针对前者,主要是用于本机的一些数据调试,也可以与其他组件打通,如数据报警等。针对本地 UDS,atop 作为 server 端,提供一种数据输出的能力;另外需要引入 client 端、监听并获取 atop 数据,同时作为数据源端、与数据处理打通、将本机 atop 数据流过数据通路落入数据库,供业务方使用。整体流程如下:

idea数据分层分析(线上系统的性能监控实践)(6)

用法如下:

Currently we support three types of output: 1. atop -O stdio 2. atop -O only 3. atop -O unixsock -w /path/to/file 10 //Make unixsock non-block to make sure this will not block main engine. And if the unix remote server re-launches, atop will re-connect and continue to work. Usage examples: ./atop ./atop -P ALL ./atop -O only // overwrite parseout, show json to stdio only ./atop -O stdio -P ALL // both parseout and json stdio ./atop -O stdio -w atop.log // print to stdio, as well as file ./atop -O unixsock // overwrite parseout, show json to unixsock ./atop -O unixsock -P ALL // both parseout and json unixsock ./atop -O unixsock -w atop.log // write json to unixsock and file And the detail JSON output format is as follows: { "ip": "a.b.c.d", "timestamp": 1565256314, "CPU": { "hertz": 100, ... "cpu_nums": 40 }, "cpu": [ { "hertz": 100, ... "cpu_id": 0 }, ... { "hertz": 100, ... "cpu_id": 39 } ], ... "PRC": [ { "pid": 1, "p_name": "(systemd)" }, ... { "pid": 73, "p_name": "(migration/12)" } ] }

交互界面改进

虽然 atop 的指标很全,且有历史记录可以查询,但依旧有不少声音提到 atop 做的还有欠缺。比如无法将所有 CPU 的使用情况同时展示,即使将显示器横过来也不能解决,这在高达 128 核的物理机上尤其头痛。为解决这个痛点,参考类似 htop 的展示方式,结合 atop 本身代码,从零开始用 ncurses 加以绘制,展示效果如下。目前只支持 CPU 和 MEM 的展示,如有其他需求,欢迎联系我们。

支持类似 htop 直观的展示所有 CPU 和内存的使用情况,但新增 NUMA 粒度的支持。一是解决因 CPU 核数太多展示不全的问题;进一步可以纵览所有 CPU 的负载,直观判断绑核是否有问题

  • 双 NUMA 使用 bar 展示

idea数据分层分析(线上系统的性能监控实践)(7)

  • 双 NUMA 使用百分比展示

idea数据分层分析(线上系统的性能监控实践)(8)

//注:上面两张图为压测场景 user态:stress -c 20 sys态:iperf -s -i 1 && iperf -c $ip -i 6 -t 600 //numactl -H的结果如下

idea数据分层分析(线上系统的性能监控实践)(9)

  • 4NUMA 使用 bar 展示

idea数据分层分析(线上系统的性能监控实践)(10)

  • 4NUMA 使用百分比展示

idea数据分层分析(线上系统的性能监控实践)(11)

日志相关

前面提到,atop 支持历史日志的记录,这在定位排查非实时问题时非常有帮助。然而在字节内部,曾因 atop 日志过大引发过比较严重的问题。起因是 atop 默认会将日志写到/var/log/atop 目录下,并且记录所有的进程、线程信息到日志里。有些业务服务器(如 Java 业务)动辄每 10 秒几万个线程,一天的日志量高达几 G,7 天高达几十 G,如果服务器本身的系统盘存储空间很紧张,就会造成系统盘打满、登录不上机器的严重后果。

为解决日志相关的问题,字节内部在新版本中推出了以下特性:

  • 默认只存储每个进程的 top100 线程

根据日常排查问题来看,一般只关心 topM 的进程或每个进程的 topN 线程。观察每个进程,通常超过 top100 线程的 CPU 或 MEM 都处于不活跃状态,对于排查问题来说意义不大,没必要记录到日志。据此字节内部引入-H 参数,通过指定-H 100 可以过滤掉 top100(按照 CPU/MEM/DISK 比例之和倒叙排列)之外的线程,大大减少了日志存储量,尤其适用于线程数目多达几千或几万的 Java 业务场景。

  • 使用 systemd timer 控制 daily 日志重定位

引用上游最新的 atop-rotate.timer 和 atop-rotate.service,取代之前的 cronjob。避免某些机器修改时区后未重启 cron.service,导致 cron 服务重启时间未遵守本机时间,写 atop 日志时间出错。

  • 支持用户修改 atop 日志存储时间,默认存储为最近 7 天

上游默认存储天数为 30 天,在实际排查问题时必要性不大,反而浪费了系统盘的存储空间。如有需要,可以通过 atop-json 机制将本机日志传输到统一的存储池子中,采取数据稀释的方式(如保留 topM 进程、按时间顺序增大记录间隔等)进行保存。字节内部在 atoprc 中引入generations变量,表示存储天数为generations 2天。

例:echo 'generations 1' >> /etc/atoprc && systemctl restart atop代表只保留存储最近 3 天的日志

  • 支持用户修改 atop 日志存储位置,默认是/var/log/atop

有些服务器虽然系统盘存储空间小,但数据盘有多块,容量高达几 T,针对这种场景,用户可以通过修改 atop 日志存储位置,来缓解存储压力。字节内部在 atoprc 中引入 logpath 变量,标识日志存储目录。

例:echo 'logpath /data00/log/atop' >> /etc/atoprc && systemctl restart atop将日志存储到/data00/log/atop目录下

  • 限制 atop 日志存储总量为 10G,超过 10G 会按照时间倒序删除日志文件
  • 解决因 systemd 没能 daily 重启 atop 服务,导致持续写相同文件,导致单个文件过大的问题
其他指标及特性
  • 通过-b/-e 参数指定时间范围时支持精确到秒
  • 新增 compact_stall、allocastall、InCsumErrors 等指标
  • 关闭 perfevent 采集 instr 和 cycle 两项指标的功能,释放 PMU 给其它专用工具,如 perf
  • 修复低于 4.19 内核,用户态读取/proc/$pid/cpuset 文件遇到 css offline、导致永久陷入内核态的问题
  • 修复/run/pacct_source 文件过大,导致 tmpfs 被占满的问题
落地使用情况

到目前为止,字节已稳定运行接近三年,覆盖公司全量服务器,推出 3 个版本。

字节内部目前在用代码已 push 到相关分支,欢迎使用:

  • https://github.com/bytedance/atop/commits/bytedance-internal-v2.6.0+byted2

相关 repo 请访问:

  • https://github.com/bytedance/atop

其中 master 分支紧跟社区 atop 的 master 分支,其余分支是一些已推社区但尚未被合入的特性或 bug fix(如 Fix atop stuck when reading offline css 虽然本质上是内核的 bug,但可以通过修改 atop 代码加以规避,避免重启服务器)。

合作与共建

新版本 atop 的部分特性已经推社区并被上游接收,接下来还会将其余特性继续推上游,更好的回馈社区。


关于字节跳动系统部 STE 团队:

字节跳动系统部 STE 团队 (STE=System Technologies & Engineering,系统技术与工程) 一直致力于操作系统内核与虚拟化、系统基础软件与基础库的构建和性能优化、超大规模数据中心的系统稳定性和可靠性建设、新硬件与软件的协同设计等基础技术领域的研发与工程化落地,具备全面的基础软件工程能力,为字节上层业务保驾护航。同时,团队积极关注社区技术动向,拥抱开源和标准。

更多招聘信息,可邮件联系 chenziying@bytedance.com 获取。

,