Linux系统性能监控与问题排查

(《Linux System and Performance Monitoring》读记)

1 简介

性能调优是通过在操作系统的几个子系统之间寻求平衡来尽可能消除系统的瓶颈,通常有CPU、内存、IO和网络四个子系统。这些子系统之间是互相依赖的,因而问题的表象与实质之间可能存在一定的距离。

通常应用的类型可以分为IO密集型和CPU密集型两类,在进行调优之前首先了解应用的类型可以进行一个大方向的定位。

系统的表现是否异常与应用的正常状态和管理员的预期紧密相关,因此需要对系统的正常状态进行一个基线记录。通过与基线数据进行比较来寻找系统的异常点。

2 CPU

内核主要调度CPU对中断和进程(线程)进行处理,线程又分为内核线程和用户级线程。把它们按CPU处理的优先级由高到低进行排序:中断、内核线程、用户级线程。

当线程用完自己的时间片或者需要等待IO,则发生上下文切换,CPU将调度其它线程运行。上下文切换是一个耗时的操作,如果CPU忙于上下文切换,则可用于处理实际有意义的工作的时间自然就会变少。

当线程处于可运行状态,但CPU被其它线程占用因而暂时无法被调度时,将被放进运行队列中等待。运行队列的长度通常直接反映了系统负载状态。术语load(top命令或者uptime可以查看)用来描述系统负载状态。在一个双核系统上,如果有两个线程正在运行并且有4个线程在运行队列中等待,则系统的load为6。可见,当load值与CPU数(核、超线程)相同时系统处于最佳CPU利率状态(如果多个CPU被均衡使用),所有可运行的线程都能被即时调度。

CPU的利用率通常分为以下几种:

  • us (user time),运行用户级线程的时间,通常在进行实际的业务处理。
  • sy (system time),运行内核线程的时间,上下文切换等。
  • wa (wait io),等待IO的时间。
  • si (sof irq),处理软中断时间。
  • id (idle),CPU空闲。

对于CPU利用率的正常状态有以下几点预期:

  • 每个CPU上的运行队列长度不应超过3(最好尽可能不在运行队列中堆积线程,在load值达到CPU数之间就应进行扩容)。
  • 如果CPU已经被完全利用(100%),则应该呈现如下分布:65%~70%的us,30%~35%的sy以及0%~5%的id。
  • 如果CPU利用率满足上述分布,那么相对频繁的上下文切换是可以接受的。

通常可以使用vmstat和top来查看CPU的使用情况,mpstat可以看到每个CPU的使用情况(top也可以)。

进行CPU监控和问题排查时主要有以下几点:

  • 检查运行队列长度(load值)。
  • 检查CPU利用率是否满足前面所述的分布。
  • 如果CPU在系统态(sy)花费了过多时间,通常说明系统过载了。
  • 内核调度器会“惩罚”CPU密集型进程,“奖励”IO密集型进程。

3 内存

通常使用free、vmstat查看内存时剩余内存(free)都不会太多,因为Linux会把内存用作文件系统缓存(cached)和块设备写缓冲(buffers)。这是一种良好的运行状态,只要没有发生swap的使用。

内存按4KB的大小的页进行管理,将进程的虚拟内存地址映射到物理内存页。内存映射采用一种Lazy策略,进程启动时只映射必需的页,其余的页通过缺页异常(Page Fault)来载入。当进程访问某个虚拟内存地址,但是此地址尚未映射到物理页时引发缺页异常,然后系统将完成虚拟地址到物理页的映射。

缺页异常分为两种:Major Page Fault(MPF)和Minor Page Fault(MnPF)。如果进程需要的数据已经被加载到某个物理页中,但是尚未将物理页映射到进程的虚拟地址空间,则发生MnPF,只需要建立映射关系即可。如果进程所需数据不在内存,则发生MPF,需要找到一个空闲物理页,从磁盘上载入数据,然后与进程虚拟地址空间建立映射关系。由于MPF会发生IO,因此代价远高于MnPF。

连续运行两次以下命令(注意不要直接使用time),查看MPF和MnPF的次数可以帮助理解:

内核线程kswapd负责保证系统中有足够的空闲物理页可用。有两个内核参数pages_high和pages_low,当空闲物理页少于pages_low时,kswapd开始释放一些被占用的物理页,每次释放32个页,直到空闲物理页数量达到pages_high。在三种类型的物理页,kswapd对它们采取不同的处理策略:

  • Read Pages. 这些页是通过MPF从磁盘上加载的并且是只读的,包括二进制文件和库文件等。当空闲内存不足时,kswapd会直接steal这些页并放入空闲页链表中。如果之后系统需要这些页的内容,则再次通过MPF从磁盘进行加载。
  • Dirty Pages. 这些页与磁盘上的文件相关联,并且在内存中进行了修改,内核线程pdflush负责定期将这些页写入磁盘。当空闲内存不足时,kswapd将通知pdflush立即将这些页写入磁盘以释放占用的内存。
  • Anonymous Pages. 这些页与进程相关联,但是不与磁盘上的文件相关联,因而这些页不能被写入磁盘文件中。当空闲内存不足时,kswapd将这些页写入swap分区以释放内存。当之后系统需要这些页时,再从swap分区载入。由于会发生IO,因此代价很大。

内核线程pdflush负责定期将脏页刷盘。pdflush的工作周期是由内核参数vm.dirty_background_ratio控制的,当脏页占据内存的比例超过指定的值时,pdflush将被唤醒并刷盘。系统调用fsync()和sync()可以立即将脏页刷盘。

关于内存的性能监控和优化有以下几点:

  • MPF越少系统响应时间越短,说明缓存得到有效利用。
  • 只要没有触发对swap分区的使用,空闲内存处于较低水平是一种良好的运行状态(用于buffers和cached)。
  • 如果swap分区被使用,通常说明系统内存不够用了。

 4 I/O

机械盘一次随机寻道时间大约8~10ms,通常机械盘的IOPS为100~200之间。SSD则有普通的数千IOPS到Fushion-io近千万IOPS。

顺序I/O与随机I/O。随机I/O是杀手。

对于I/O性能问题的排查,通常使用工具sar、vmstat和iostat查看系统总体的运行状态和I/O状态,然后再用iotop查找占用I/O的进程。

关于I/O的性能监控:

  • 如果CPU花在wait I/O上的时间比较多,磁盘通常过载了。
  • 对系统磁盘能够承受的IOPS心里要有底。
  • 了解应用的I/O类型,顺序还是随机。
  • 监控swap分区的使用,确保swap分区没有占用I/O资源。

5 网络

网络的监控和问题排查比较复杂,因为涉及到很多外部的不可控的链路和系统。这里主要列出一些可用的工具和相应的使用场景。

使用ethtool查看和修改网卡的配置,比如网卡支持的工作模式及当前接入的链路速率等。

使用iptraf可以查看系统当前的网络流量,可以分网卡和网络连接。

使用netperf对网络的实际吞吐量进行测试。在一端运行服务端netserver,另一端使用netperf进行测试。

工具iperf与netperf的作用和使用方式相似,但是iperf可以显示更多的关于网络协议栈的参数。

使用tcpdump抓包,然后使用tcptrace对数据进行分析。tcptrace可以对指定的单个链接进行详细分析,包括重传、窗口大小等。

使用netstat和ss查看当前的所有网络连接及其状态,包括发送和接收缓冲区等。

关于网络监控和性能问题:

  • 检查所有网络接口的配置,确保它们工作在预期的模式。
  • 检查所有网络接口的吞吐量,确保它们与所接入网络的速度相符。
  • 检查网络的延时和重传,确保网络处于良好的运行状态。

6 其他

关于工具还有很多:比如dstat可以展示系统总体的运行统计信息,nmon是一个方便、直观、多能的监控工具。

确认问题所在的位置以后可以使用strace、systemtap等对进程进行跟踪,搞清楚进程到底在做什么事情。

性能问题的排查主要还是合理利用各种工具的输出,对这些信息进行有效的关联,结合硬件、系统以及应用的运行机制进行综合分析。

References

1. Linux System and Performance Monitoring.
2. IOPS. http://en.wikipedia.org/wiki/IOPS
3. Page Fault. http://en.wikipedia.org/wiki/Page_fault

 

Read More

Linux和Windows双系统时间不一致的问题

Linux和Windows做双系统的时候,发现两个系统中的时间不一致。表现为在一个系统中将时间校准以后,重启到另外一个系统中发现时间不对,相差8个小时。

昨天晚上突然想到会不会是两个系统启动时读取BIOS时间(RTC, Real Time Clock)的处理不一样,查了一下资料,还真是这样。问题就在BIOS中存储的时间只是一个值,而不能存储与这个时间值相关的其它信息(比如这个时间值是UTC还是localtime,时区信息等)。Linux和Windows对这个时间值的解释是不一样的,前者通常是当作UTC时间,而Windows则当作本地时间。这样,在Linux中使用NTP校准时间以后,写入BIOS的时间值是UTC时间,重启到Windows,读取这个时间值,当作本地时间来解析,由于北京时间是UTC+8,因此就差了8个小时。

只要把两个系统对BIOS时间的解析方式配置为一致的就可以了。通常Linux下都是使用UTC,systemd默认也是使用UTC,因此我把Windows配置成使用UTC。

修改Windows注册表,增加如下DWORD数值项(这个注册表项默认是没有的,自己新建一个),并且把它的值设置为1:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation\RealTimeIsUniversal

Arch的Wiki上说Windows改用UTC以后,应该关闭Windows的“联网更新时间”。Google其它资料也有说使用UTC的时候Windows联网更新系统时间以后没有写入BIOS。但是我在Windows 8.1上试了一下,联网更新时间以后BIOS时间也被更新成了正确的UTC时间值,因此我还是开着“联网更新时间”。

将两个系统都配置为使用UTC以后,进入BIOS看到的时间与北京时间相差8小时,这是正常的,因为此时BIOS里面是UTC时间。

References
1. Time – ArchWiki, https://wiki.archlinux.org/index.php/time
2. Why does Windows keep your BIOS clock on local time?
3. Windows 7 Internet Time Update and RealTimeIsUniversal (UTC) registry hack

Read More