1 性能

在平常开发工作中, 我们实际上很少去关注程序运行的时长, 程序运行的健壮性, 程序运行的资源损耗, 如果程序遇到问题, 大不了关闭调试, 关闭进程, 重新来一遍. 犹记得大四学习的软件工程, 软件开发流程的瀑布模型: 需求分析->设计->实现->测试->整合测试->部署->维护. 在代码开发开发阶段的主要关注点是功能的实现, 关于性能损耗会在设计阶段或者后续测试维护才考虑.

对于小公司, 开发者往往负责了设计, 实现, 测试,整合测试的大部分工作, 因为时间分配的问题, 导致很多项目在前期往往没有很好的考虑程序的性能问题, 只能在后期根据项目的具体使用量来进行优化. 那么,对于一个准备运行或者已运行在线上的项目, 我们有如下的疑问:

  • 我们如何做基准测试, 估计程序的最高处理负载?
  • 我们如何监控线上程序运行性能?
  • 我们如何有针对性的优化线上程序?

这三个问题时刻伴随着每一个开发者, 确保自己开发的程序能够健壮无误的运行在线上. 这篇文章我们主要简单的介绍性能测试工具, 性能监控工具, 性能调整工具. 之后重点介绍一下strace命令.

参考: linux工具介绍

2 工具

让我们首先了解一下各种工具在整个系统中的定位, 从而加深工具的用途, 在排查问题的时候有针对性的根据不同的命令进行排查. 当然, 大部分情况下, 我们仅仅需要了解其中的几个工具, 然后形成自己的工作流就可以, 就像基于VIM而形成的开发工具链, 基于IDE而形成的便捷的开发工具链, 各有各有的优势, 萝卜青菜各有所爱.

A) 让我们先看一下性能基准测试工具:

optimize-benchmark-tool

其中: ab用于web api的压力测试; sysbench是高性能MYSQL极力推荐的模块化, 跨平台的多性能测试工具, 用于IO, 内存, CPU, 数据库的性能测试; openssl用于提供加密传输功能; dd用于磁盘IO测试, 另外还用于增加缓存; ping和traceroute用于ICMP协议的网络连通性测试.

B) 让我们了解一下性能观察监控工具:

optimize-observability-tool

其中: netstatlsof在查找进程占用协议端口, 占用文件资源方面是运维开发人员利器, 记住, linux中一切皆是文件; top, htop, free, sar, vmstat等用于实时监控系统所有进程资源占用以及系统总资源配置; iostat, iotop用于监控进程IO占用情况; tcpdump用于网络数据包的抓取和捕获, 这个在线上处理网络请求的时候非常有用; swapon用于系统swap的增加, 常常用于机器内存不足的情况下; ethtool, netstat则用于网卡硬件设备检测工作.

C) 让我们了解一下系统性能优化调整工具:

optimize-tunning-tool

在了解了上述各种与系统性能相关的工具, 之后, 让我们重点了解一下strace, ltrace, 让我们带着问题往下了解相关知识点:

  • strace是什么? 原理是什么?
  • strace能够解决何种问题? 在何种应用场景中使用
  • strace如何排查问题?

3 strace

3.1 介绍

场景: 在线程进程运行过程中, 有时候会发生进程不知名的卡顿, segment fault, 运行速度变慢等, 向此类疑难问题常常无法在线下测试环境中复现, 无法快速的通过代码来定位, 这时候就需要一些系统性能检测工具.

原理: strace用来 跟踪一个进程的系统调用或信号产生的情况, ltrace用来跟踪进程调用库函数的情况. 其中strace常常结合ps, lsof来查看某一个具体进程的系统调用以及信号触发情况. 其中strace和ltrace的原理都是类似, 使用ptrace(拦截系统调用)系统调用跟踪调试运行中的进程, 依赖于系统支持.

在介绍完strace相关的原理以及应用场景之后, 让我们了解一下strace命令的用法, 其常用命令如下:

1
2
3
4
-f: 除了跟踪当前进程外, 还跟踪其子进程
-o file: 将输出信息写到文件file中, 而不是显示到标准错误输出stderr
-D: 显示调用时间戳
-p pid: 绑定到一个由pid对应的正在运行的进程, 此参数常用来调试后台进程

其中strace命令的输出说明:

1
2
3
brk(0)                                  = 0x8062aa8
brk(0x8063000) = 0x8063000
mmap2(NULL, 4096, PROT_READ, MAP_PRIVATE, 3, 0x92f) = 0x40016000

其中每一行都是一条系统调用, 等号左边是系统调用的函数名及其参数, 右边是该调用的返回值.

3.2 例子

现在让我们介绍一个排查线上python进程卡死的实例.

a) 查看卡死进程ID, 并查看系统调用堆栈

1
2
3
ps -ef|grep visa_schedule
# 查看进程
strace -p <pid>

输出如下:

1
2


可以了解到整个进程一直卡死在读取24描述符, 那么如何知道24描述是干嘛呢?

b) 查看进程打开的某一个fd描述符

1
2
3
4
5
6
7
8
9
10
# 进入进程文件夹
cd /proc/<pid>/fd

# 查看进程当前的状态
cat status
# 查看进程堆栈信息
cat stack

# 查看该进程打开的所有描述符
ls -l

c) 利用lsof查看某一个文件描述符或者某一个进程的资源

1
2
3
4
5
# 查看进程打开的所有文件
lsof -p <pid>

# 查看所有打开24描述符的进程
lsof -d 24

参考:

strace查看进程卡死