前言 在虚拟化场景下,经常会用到steal time来判断虚拟机的vCPU执行是否被抢占,进而来衡量虚拟机的性能指标。同时,在延迟敏感型的业务上(例如redis),会用sched delay来分析延迟突刺类问题。 这里我们来分析steal time以及进程的sched delay的原理和实现。再进一步延伸到atop对sched delay的支持,做到带外监控。 分析 schedstat中的run delay 在进程的proc目录下,存在文件/proc/<PID>/schedstat 在内核文档中可以找到下面的描述
可以知道,第二列是在runqueue上的等待时间,就是调度延迟,即run delay。 同样,我们可以在/proc/<PID>/task/<TID>/schedstat找到每一线程的调度延迟。 run delay的实现 代码选择linux-4.14,linux-4.14/kernel/sched/stats.h
从这段逻辑中,可以知道,在一个task被切换走的时候,它依然是RUNNING状态的话,那么就会记录它的last_queued的时间戳。 我们知道,内核把一个task被切换走,要么是task主动发起的,要么是被动的。如果task依然是RUNNING状态的话,那么它必然是被动切换走的:即task还想继续运行,但是没有得到调度。那么到达下一次执行的时间间隔就是run delay。
当task被调度到的时候,因为记录了它的上一次被动切换的时间,即可计算出来这段时间差,就算出来了这段run delay的时间。 所以,通过统计一个task被切换走的时间,以及切换执行的时间,计算出来时间间隔做统计,即run delay。 steal time的实现 代码选自linux-4.14/arch/x86/kvm/x86.c
在vCPU开始执行之前,计算run delay的信息,保存差值到steal time中,通过共享内存同步给虚拟机,在虚拟机中即可以通过共享内存获取到steal time。 steal time的问题 理论上来说,top命令看到的st为0是最好的情况。但是实际的运行过程中,会有各种各样的原因导致st会有少量的波动。在top命令中,我们看到的是聚合的数据值,并不总是可以反映出来问题。 例如在40C的虚拟机上,平均40%左右的的st通常可以被接受的,平均每个vCPU大约1%左右。但是,如果steal time完全的体现在一个vCPU上的话,就意味着这个vCPU有40%的时间是不能执行的,那么就是很严重的问题了。 所以对于steal time的监控,最好也可以做到per vCPU级别,而非只是整体的平均值。 atop的改进 atop原本并不支持run delay的监控,作者提交了patch,对atop做了支持。目前最新的版本中已经合入了代码,maintainer也做了额外的一些改进。下载最新的代码编译执行即可。目前run delay出现在了sched页面,即进入atop后按s键,会多出来一列RDELAY。按y键可以查看per thread级别信息。
测试的代码是5个线程的进程cpubench(手写的测试代码),以及stress -c 5,绑定到相同的5个cpu上运行的结果。 atop的改进可以带来的价值?作者目前可以想到在几个地方:1, 虚拟化场景下监控,带外监控vCPU的run delay可以知道vCPU的执行情况。 2, redis/memcached等延迟敏感型的数据库,用来排查延迟突刺问题。3, 在线业务,尤其是docker环境下。cgroup中提供了throttle计数,虽然可以反映出来被throttle的频率间接反映出来对业务的影响,但是run delay更能体现出来和业务延迟的具体数据是否match,进一步精细化的判断。