最近排查性能碰到由于上下文切换频繁导致性能下降的问题,这里做一个对上下文排查的学习记录。
在计算机科学领域,系统上下文切换是一项至关重要的操作,尤其在多任务操作系统中。Linux系统以其高度的稳定性和可伸缩性而著名,而系统上下文切换是其核心特性之一。在本文中,我们将深入探讨系统上下文切换的概念,以及如何使用vmstat工具来监视系统上下文切换的情况。
什么是系统上下文切换
系统上下文切换是指操作系统在不同进程或线程之间切换执行的过程。在多任务操作系统中,这是一项至关重要的任务,因为它允许多个程序共享处理器时间,以便它们似乎同时运行。系统上下文切换涉及保存当前进程的状态,切换到另一个进程,并将其状态还原,以便它可以继续执行。这是操作系统内核的关键职责之一,以确保公平的资源分配和系统的高效性。
vmstat
在Linux系统中,vmstat是一个非常有用的工具,用于监视系统性能,并且可以提供关于上下文切换的有用信息。您可以使用以下命令来运行vmstat并显示上下文切换统计信息:
vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b 交换 空闲 缓冲 缓存 si so bi bo in cs us sy id wa st
1 0 0 1956380 62880 877460 0 0 3692 312 572 1251 28 50 21 1 0
0 0 0 1956380 62880 877568 0 0 68 0 160 248 2 0 97 0 0
0 0 0 1956380 62880 877568 0 0 0 0 168 265 2 1 97 0 0
1 0 0 1956380 62880 877564 0 0 0 0 271 523 4 2 94 0 0
1 0 0 1956380 62880 877552 0 0 0 4 225 356 3 1 96 0 0
这将以每秒一次的频率输出系统性能信息,其中包括上下文切换的统计数据。在输出中,您将看到如下信息:
- cs(上下文切换):这是系统上下文切换的总数,包括进程切换和中断切换。
- in(中断数):这是自系统启动以来的中断总数。
- r(运行队列长度):这是正在运行的进程数。
- b(阻塞队列长度):这是等待资源的进程数。
举个栗子
我们在ubuntu下运行stress-ng -i 100模拟io加压,在模拟之前使用vmstat 1监控上下文切换。
我们可以看到cs从500左右涨到20000多以上,实际应用中碰到性能问题需要查上下文时就要使用vmstat来观察,如果确认了上下文切换比较频繁,那么如何确认是哪个应用导致的呢?这时候就需要pidstat了。这里我在另一个终端已经运行起来了。
运行pidstat -w 3 //每隔3秒输出一次关于进程上下文切换的统计信息
12时04分17秒 UID PID cswch/s nvcswch/s Command
12时04分20秒 0 14 1.33 0.00 ksoftirqd/0
12时04分20秒 0 15 29.33 0.00 rcu_preempt
12时04分20秒 0 16 0.33 0.00 migration/0
12时04分20秒 0 22 0.33 0.00 migration/1
12时04分20秒 0 23 3.00 0.00 ksoftirqd/1
12时04分20秒 0 35 2.00 0.00 kcompactd0
12时04分20秒 0 48 2.33 0.00 kworker/1:1H-kblockd
12时04分20秒 0 247 707.33 0.00 kworker/u256:29-flush-8:0
12时04分20秒 0 254 0.33 0.00 kworker/0:2H-kblockd
12时04分20秒 0 278 5.00 1.33 jbd2/sda3-8
12时04分20秒 0 380 3.33 0.00 irq/16-vmwgfx
12时04分20秒 127 613 4.00 0.00 systemd-oomd
12时04分20秒 0 642 12.67 0.67 vmtoolsd
12时04分20秒 130 921 0.33 0.00 vnstatd
12时04分20秒 0 1383 1.00 0.00 vmtoolsd
12时04分20秒 998 1576 1.00 0.00 pmproxy
12时04分20秒 0 4294 9.33 9.33 gnome-shell
12时04分20秒 0 4431 2.00 0.00 ibus-daemon
12时04分20秒 0 4506 10.33 0.33 vmtoolsd
12时04分20秒 0 4550 1.00 0.00 ibus-extension-
12时04分20秒 0 4615 1.00 0.00 ibus-engine-lib
12时04分20秒 0 4835 8.33 13.33 gnome-terminal-
12时04分20秒 0 5411 6.67 0.00 kworker/0:2-events
12时04分20秒 0 5796 42.33 0.00 kworker/u256:1-writeback
12时04分20秒 0 7105 8.00 0.00 kworker/1:3-events
12时04分20秒 0 7224 1.00 1.00 vmstat
12时04分20秒 0 7475 6.33 6.33 stress-ng
12时04分20秒 0 7476 6.33 7.00 stress-ng
12时04分20秒 0 7477 5.00 6.00 stress-ng
12时04分20秒 0 7478 5.33 5.00 stress-ng
12时04分20秒 0 7479 5.33 8.00 stress-ng
12时04分20秒 0 7480 5.67 5.67 stress-ng
12时04分20秒 0 7481 5.33 5.67 stress-ng
12时04分20秒 0 7482 4.33 4.67 stress-ng
12时04分20秒 0 7483 5.33 5.33 stress-ng
12时04分20秒 0 7484 5.33 4.67 stress-ng
12时04分20秒 0 7485 4.67 6.00 stress-ng
12时04分20秒 0 7486 4.67 7.00 stress-ng
12时04分20秒 0 7487 4.33 5.00 stress-ng
12时04分20秒 0 7488 4.67 5.33 stress-ng
12时04分20秒 0 7489 5.00 5.00 stress-ng
12时04分20秒 0 7490 4.00 6.33 stress-ng
12时04分20秒 0 7491 5.00 7.00 stress-ng
12时04分20秒 0 7492 5.67 7.00 stress-ng
12时04分20秒 0 7493 5.67 5.00 stress-ng
12时04分20秒 0 7494 5.67 6.33 stress-ng
12时04分20秒 0 7495 5.67 3.67 stress-ng
12时04分20秒 0 7496 5.00 6.00 stress-ng
12时04分20秒 0 7497 5.00 8.33 stress-ng
........后面还有很多stress-ng的进程
从结果中可以看到有很多stress-ng带来的上下文切换,这里面还有个占大头儿的kworker/u256:29-flush-8:0,占了707,他是做什么的呢?
kworker/u256:29-flush-8:0 是Linux内核中的一个内核线程,它用于执行与I/O刷新相关的任务。这个线程通常是由kworker进程池中的一个线程执行的,负责刷新磁盘缓存中的数据到存储设备,以确保数据的一致性和持久性。
具体来说,kworker/u256:29-flush-8:0 中的部分信息可以解释如下:
- kworker:这是内核工作线程的通用前缀。
- /u256:这是一个标识符,通常是一个数字,用于唯一标识内核工作线程。
- 29:这可能是该特定线程的标识号,用于标识线程在内核线程池中的位置。
- flush-8:0:这部分通常描述了该线程正在执行的任务,这里是"flush",可能表示磁盘数据刷新操作。8:0 可能涉及到与设备名称或块设备的相关信息。
这种类型的内核线程通常用于后台任务,以确保数据在内存和磁盘之间的同步。它在I/O操作中扮演了重要角色,帮助维护数据的一致性,并减少数据丢失的风险。所以可以确定是stress-ng模拟io加压带来的上下文切换。
非自愿与自愿切换
上面pidstat可以看到cswch/s nvcswch/s,这两个就是自愿上下文切换和非自愿上下文切换。
非自愿上下文切换(Non-Voluntary Context Switches)和自愿上下文切换(Voluntary Context Switches)是多任务操作系统中的两种不同类型的上下文切换,它们分别表示进程或线程切换执行的原因和方式。
(1) 自愿上下文切换(Voluntary Context Switches):
自愿上下文切换是由进程或线程自身发起的上下文切换,而不是被操作系统强制执行。这通常发生在以下情况下:
- 进程主动让出CPU,以便其他就绪状态的进程有机会执行。这可以是出于合作性多任务处理的目的,进程知道它已经执行了足够的时间,并主动让出CPU。
- 进程在执行期间需要等待某些事件的发生,如等待I/O操作完成。在这种情况下,进程可能会主动挂起自己,以便其他任务可以继续执行。
自愿上下文切换通常是进程协作和多任务处理的一部分,它有助于提高系统的效率和公平性。
(2) 非自愿上下文切换(Non-Voluntary Context Switches):
非自愿上下文切换是由操作系统强制执行的上下文切换,进程或线程被挂起并切换到就绪状态的其他进程或线程。它通常发生在以下情况下:
- 进程的时间片(CPU分配的时间段)已经用尽,操作系统需要将CPU分配给其他进程。
- 进程需要等待某些资源的可用性,如等待磁盘I/O、等待网络数据等。在这种情况下,进程被挂起,直到资源可用。
非自愿上下文切换是操作系统的一种管理方式,以确保多任务系统中的进程或线程都有机会获得CPU时间,防止某个任务长时间独占CPU。
总结起来,自愿上下文切换是由进程自身控制和触发的上下文切换,而非自愿上下文切换是由操作系统强制执行的,通常是为了分配资源和提高系统的效率。了解这两种上下文切换类型有助于理解多任务操作系统如何管理和调度进程,以确保资源的合理分配和性能的优化。
总结
系统上下文切换是多任务操作系统的核心功能之一,它确保了资源的公平分配和高效的多任务处理。通过使用vmstat工具,可以监视系统上下文切换的性能统计信息,以便更好地了解系统性能瓶颈问题。