大数据运维 - Linux 之 软中断(softirq )

本文详细介绍了Linux中的软中断,包括中断的基本概念、软中断的由来和具体定义。软中断用于处理网络IO,以解决硬中断在处理大量网络包时可能导致的系统实时性下降问题。软中断与硬中断的主要区别在于中断来源和处理方式。此外,文中还探讨了软中断可能带来的危害以及如何通过top和vmstat命令进行监控和排查。
摘要由CSDN通过智能技术生成

一、什么是软中断

1. 什么是中断为什么要用中断

① 什么是interrupt?

interfere in someone else’s activity 就是干扰其它人的事情。这就是所谓interrupt的本质。从计算机的语境来说就是硬件干扰CPU的事情。CPU的什么事情呢?CPU只有一件事情那就是执行指令。这里有这么几件事需要思考:既然硬件能干扰到CPU的正常的指令执行,那么CPU就必须能感知到干扰信号,所谓的干扰信号就是这里所说的中断信号。CPU的工作粒度是机器指令级别,那么在每条机器指令执行结束后都会检查一下是否中断信号产生。

通俗来说,你正在打开电脑浏览网页,突然微信闪动有消息发过来,你立马去用鼠标把网页最小化去打开微信回微信,回完微信后继续浏览网页。这就是一次中断。
在这里插入图片描述

② 为什么要用中断系统

1、提高计算机系统效率。计算机系统中处理机的工作速度远高于外围设备的工作速度。通过中断可以协调它们之间的工作。当外围设备需要与处理机交换信息时,由外围设备向处理机发出中断请求,处理机及时响应并作相应处理。不交换信息时,处理机和外围设备处于各自独立的并行工作状态。

2、维持系统可靠正常工作。现代计算机中,程序员不能直接干预和操纵机器,必须通过中断系统向操作系统发出请求,由操作系统来实现人为干预。

主存储器中往往有多道程序和各自的存储空间。在程序运行过程中,如出现越界访问,有可能引起程序混乱或相互破坏信息。为避免这类事件的发生,由存储管理部件进行监测,一旦发生越界访问,向处理机发出中断请求,处理机立即采取保护措施。

3、满足实时处理要求。在实时系统中,各种监测和控制装置随机地向处理机发出中断请求,处理机随时响应并进行处理。

4、提供故障现场处理手段。处理机中设有各种故障检测和错误诊断的部件,一旦发现故障或错误,立即发出中断请求,进行故障现场记录和隔离,为进一步处理提供必要的依据。

③ 中断 (故障现场处理手段)

隔离变化

有没有意识到,中断处理前面这部分的设计是何等的简单优美。人是高度智能化的,能够对遇到的各种意外情况做有针对性的处理,计算机相比就差距甚远了,它只能根据预定的程序进行操作。对于计算机来说,硬件支持的,只能是中断这种电信号传播的方式和CPU对这种信号的接收方法,而具体如何处理这个中断,必须得靠操作系统实现。操作系统支持所有事先能够预料到的中断信号,理论上都不存在太大的挑战,但在操作系统安装到计算机设备上以后,肯定会时常有新的外围设备被加入系统,这可能会带来安装系统时根本无法预料的“意外”中断。如何支持这种扩展,是整个系统必须面对的。

而硬件和软件在这里的协作,给我们带来了完美的答案。当新的设备引入新类型的中断时,CPU和操作系统不用关注如何处理它。CPU只负责接收中断信号,并引用中断服务程序;而操作系统提供默认的中断服务——一般来说就是不理会这个信号,返回就可以了——并负责提供接口,让用户通过该接口注册根据设备具体功能而编制的中断服务程序。如果用户注册了对应于一个中断的服务程序,那么CPU就会在该中断到来时调用用户注册的服务程序。这样,在中断来临时系统需要如何操作硬件、如何实现硬件功能这部分工作就完全独立于CPU架构和操作系统的设计了。

而当你需要加入新设备的时候,只需要告诉操作系统该设备占用的中断号、按照操作系统要求的接口格式撰写中断服务程序,用操作系统提供的函数注册该服务程序,设备的中断就被系统支持了。

中断和对中断的处理被解除了耦合。这样,无论是你在需要加入新的中断时,还是在你需要改变现有中断的服务程序时、又或是取消对某个中断支持的时候,CPU架构和操作系统都无需作改变。

保存当前工作“现场”

在中断处理完毕后,计算机一般来说还要回头处理原先手头正做的工作。这给中断的概念带来些额外的“内涵”。注一“回头”不是指从头再来重新做,而是要接着刚才的进度继续做。这就需要在处理中断信号之前保留工作“现场”。“现场”这个词比较晦涩,其实就是指一个信息集,它能反映某个时间点上任务的状态,并能保证按照这些信息就能恢复任务到该状态,继续执行下去。再直白一点,现场不过就是一组寄存器值。而如何保护现场和恢复场景是中断机制需要考虑的重点之一。

每个中断处理都要经历这个保存和恢复过程,我们可以抽象出其中的步骤:

  1. 保存现场

  2. 执行具体的中断服务程序

  3. 从中断服务返回

  4. 恢复现场

上面说过了,“现场”看似在不断变化,没有哪个瞬间相同。但实际上组成现场的要素却不会有任何改变。也就是说,只要我们保存了相关的寄存器状态,现场就能保存下来。而恢复“现场”就是重新载入这些寄存器。换句话说,对于任何一个中断,保护现场和恢复现场所做的都是完全相同的操作。

既然操作相同,实现操作的过程和代码就相同。减少代码的冗余是模块化设计的基本准则,实在没有道理让所有的中断服务程序都重复实现这样的功能,应该将它作为一种基本的结构由底层的操作系统或硬件完成。而对中断的处理过程需要迅速完成,因此,Intel CPU的控制器就承担了这个任务,非但如此,上面的所有步骤次序都被固化下来,由控制器驱动完成。保存现场和恢复现场都由硬件自动完成,大大减轻了操作系统和设备驱动程序的负担。

2. 软中断由来

CPU正常情况下都是专心处理用户的进程的,当外部的硬件或软件有消息想要通知CPU,就会通过中断请求(interrupt request,IRQ)的方式来进行。比如当你的鼠标有了点击产生,再比如磁盘设备完成了数据的读取的时候,都会通过中断通知CPU工作已完成。

但是当中断机制应用到网络IO的时候,就产生了一点点问题。网络包收到后的处理工作,不像鼠标、键盘、磁盘IO读取完成那样简单,而是要进行大量的内核协议栈的处理,最终才能放到进程的接收缓存区中。假如只用一种中断(硬终端)的方式来处理网络IO,由于硬中断的优先级又比较高,这样CPU就会忙于处理大量的网络IO而不能及时响应键盘鼠标等事情,导致操作系统实时性变差,你会感觉机器以卡一卡的。

所以现代的Linux又发明了软件中断,配合硬中断来处理网络IO。 硬中断你可以理解只是个收包的,把包收取回来放到“家里”就完事,很快就能完成,这样不耽误CPU响应其它外部高优先级的中断。而软中断优先级较低,负责将包进行各种处理,完成从驱动层、到网络协议栈,最终把处理出来的数据放到socker的接收buffer中。

3. 具体什么是软中断

1、一般来说编程异常引起的通常叫做软中断。
2、软中断是通讯进程之间用来模拟硬中断的 一种信号通讯方式。
3、 中断源发中断请求或软中断信号后,CPU或接收进程在适当的时机自动进行中断处理或完成软中断信号对应的功能
4、软中断是软件实现的中断,也就是程序运行时其他程序对它的中断;而硬中断是硬件实现的中断,是程序运行时设备对它的中断。

二、软中断与硬中断区别

硬中断:

  1. 硬中断是由硬件产生的,比如,像磁盘,网卡,键盘,时钟等。每个设备或设备集都有它自己的IRQ(中断请求)。基于IRQ,CPU可以将相应的请求分发到对应的硬件驱动上(注:硬件驱动通常是内核中的一个子程序,而不是一个独立的进程)。

  2. 处理中断的驱动是需要运行在CPU上的,因此,当中断产生的时候,CPU会中断当前正在运行的任务,来处理中断。在有多核心的系统上,一个中断通常只能中断一颗CPU(也有一种特殊的情况,就是在大型主机上是有硬件通道的,它可以在没有主CPU的支持下,可以同时处理多个中断。)。

  3. 硬中断可以直接中断CPU。它会引起内核中相关的代码被触发。对于那些需要花费一些时间去处理的进程,中断代码本身也可以被其他的硬中断中断。

  4. 对于时钟中断,内核调度代码会将当前正在运行的进程挂起,从而让其他的进程来运行。它的存在是为了让调度代码(或称为调度器)可以调度多任务。

软中断:

  1. 软中断的处理非常像硬中断。然而,它们仅仅是由当前正在运行的进程所产生的。

  2. 通常,软中断是一些对I/O的请求。这些请求会调用内核中可以调度I/O发生的程序。对于某些设备,I/O请求需要被立即处理,而磁盘I/O请求通常可以排队并且可以稍后处理。根据I/O模型的不同,进程或许会被挂起直到I/O完成,此时内核调度器就会选择另一个进程去运行。I/O可以在进程之间产生并且调度过程通常和磁盘I/O的方式是相同。

  3. 软中断仅与内核相联系。而内核主要负责对需要运行的任何其他的进程进行调度。一些内核允许设备驱动的一些部分存在于用户空间,并且当需要的时候内核也会调度这个进程去运行。

  4. 软中断并不会直接中断CPU。也只有当前正在运行的代码(或进程)才会产生软中断。这种中断是一种需要内核为正在运行的进程去做一些事情(通常为I/O)的请求。有一个特殊的软中断是Yield调用,它的作用是请求内核调度器去查看是否有一些其他的进程可以运行。

  5. 对于软中断,I/O操作是由内核中的I/O设备驱动程序完成的:
    对于I/O请求,内核会将这项工作分派给合适的内核驱动程序,这个程序会对I/O进行队列化,以可以稍后处理(通常是磁盘I/O),或如果可能可以立即执行它。通常,当对硬中断进行回应的时候,这个队列会被驱动所处理。当一个I/O请求完成的时候,下一个在队列中的I/O请求就会发送到这个设备上。

  6. 软中断所经过的操作流程是比硬中断的少,换句话说,对于软中断就是:进程 ->内核中的设备驱动程序;对于硬中断:硬件->CPU->内核中的设备驱动程序。
    软中断比硬中断少了一个硬件发送信号的步骤。产生软中断的进程一定是当前正在运行的进程,因此它们不会中断CPU。但是它们会中断调用代码的流程。
    如果硬件需要CPU去做一些事情,那么这个硬件会使CPU中断当前正在运行的代码。而后CPU会将当前正在运行进程的当前状态放到堆栈(stack)中,以至于之后可以返回继续运行。这种中断可以停止一个正在运行的进程;可以停止正处理另一个中断的内核代码;或者可以停止空闲进程。

三、软中断的危害与排查

1) 查看软中断总耗时
首先用top命令可以看出每个核上软中断的开销占比,是在si列

top
top - 19:51:24 up 78 days,  7:53,  2 users,  load average: 1.30, 1.35, 1.35  
Tasks: 923 total,   2 running, 921 sleeping,   0 stopped,   0 zombie  
Cpu(s):  7.1%us,  1.4%sy,  0.0%ni, 90.1%id,  0.1%wa,  0.2%hi,  1.2%si,  0.0%st  
Mem:  65872372k total, 64711668k used,  1160704k free,   339384k buffers  
Swap:        0k total,        0k used,        0k free, 55542632k cached

如上图所示,CPU大约花费了1.2%的时钟周期在软中断上,也就是说每个核要花费12ms。
us, user: 运行(未调整优先级的) 用户进程的CPU时间
sy,system: 运行内核进程的CPU时间
ni,niced:运行已调整优先级的用户进程的CPU时间
wa,IO wait: 用于等待IO完成的CPU时间
hi:处理硬件中断的CPU时间
si: 处理软件中断的CPU时间
st:这个虚拟机被hypervisor偷去的CPU时间(译注:如果当前处于一个hypervisor下的vm,实际上hypervisor也是要消耗一部分CPU处理时间的)。

2)查看软中断次数(vmstat)
再用vmstat命令可以看到软中断的次数

$ vmstat 1
procs -----------memory---------- —swap-- -----io---- --system-- -----cpu------
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 1231716 339244 55474204 0 0 6 496 0 0 7 3 90 0 0
2 0 0 1231352 339244 55474204 0 0 0 128 57402 24593 5 2 92 0 0
2 0 0 1230988 339244 55474528 0 0 0 140 55267 24213 5 2 93 0 0
2 0 0 1230988 339244 55474528 0 0 0 332 56328 23672 5 2 93 0 0
每秒大约有56000次左右的软中断(该机器上是web服务,网络IO密集型的机器,其它中断可以忽略不计)。

类别项目含义说明
Procs(进程r等待执行的任务数展示了正在执行和等待cpu资源的任务个数。当这个值超过了cpu个数,就会出现cpu瓶颈。
d等待IO的进程数量
Memory(内存)swpd正在使用虚拟的内存大小,单位k
free空闲内存大小
buff已用的buff大小,对块设备的读写进行缓冲
cache已用的cache大小,文件系统的cache
inact 非活跃内存大小,即被标明可回收的内存,区别于free和active 具体含义见:概念补充(当使用-a选项时显示)
active活跃的内存大小 具体含义见:概念补充(当使用-a选项时显示)
Swapsi每秒从交换区写入内存的大小(单位:kb/s)
so 每秒从内存写到交换区的大小
IObi每秒读取的块数(读磁盘)块设备每秒接收的块数量,单位是block,这里的块设备是指系统上所有的磁盘和其他块设备,现在的Linux版本块的大小为1024bytes
bo 每秒写入的块数(写磁盘)块设备每秒发送的块数量,单位是block
systemin每秒中断数,包括时钟中断这两个值越大,会看到由内核消耗的cpu时间sy会越多秒上下文切换次数,例如我们调用系统函数,就要进行上下文切换,线程的切换,也要进程上下文切换,这个值要越小越好,太大了,要考虑调低线程或者进程的数目
cs每秒上下文切换数
CPU(以百分比表示)us用户进程执行消耗cpu时间(user time)us的值比较高时,说明用户进程消耗的cpu时间多,但是如果长期超过50%的使用,那么我们就该考虑优化程序算法或其他措施了
sy系统进程消耗cpu时间(system time)sys的值过高时,说明系统内核消耗的cpu资源多,这个不是良性的表现,我们应该检查原因。这里us + sy的参考值为80%,如果us+sy 大于 80%说明可能存在CPU不足
Id空闲时间(包括IO等待时间)一般来说 us+sy+id=100
wa等待IO时间wa过高时,说明io等待比较严重,这可能是由于磁盘大量随机访问造成的,也有可能是磁盘的带宽出现瓶颈。

3)计算每次软中断的耗时
该机器是16核的物理实机,故可以得出每个软中断需要的CPU时间是=12ms/(56000/16)次=3.428us

从实验数据来看,一次软中断CPU开销大约3.4us左右

软中断的上下文切换
前文我们计算出了一个相对比较精确的开销时间。这个时间里其实包含两部分,一是上下文切换开销,二是软中断内核执行开销。 其中上下文切换和系统调用、进程上下文切换有很多相似的地方。让我们将他们进行一个简单的对比:

1.和系统调用开销对比
《深入理解Linux内核-第五章》开头的一句话,很形象地把中断和系统调用两个不相关的概念联系了起来,巧妙地找到了这二者之间的相似处。“你可以把内核看做是不断对请求进行响应的服务器,这些请求可能来自在CPU上执行的进程,也可能来自发出中断的外部设备。老板的请求相当于中断,而顾客的请求相当于用户态进程发出的系统调用”。

软中断和系统调用一样,都是CPU停止掉当前用户态上下文,保存工作现场,然后陷入到内核态继续工作。二者的唯一区别是系统调用是切换到同进程的内核态上下文,而软中断是则是切换到了另外一个内核进程ksoftirqd上。

而事实上,早期的系统调用也还真的是通过汇编指令int(中断)来实现的,当用户态进程发出int $0x80指令时,CPU切换到内核态并开始执行system_call函数。后来大家觉得系统调用实在是太慢了,因为int指令要执行一致性和安全性检查。后来内核又该用了Intel提供的“快速系统调用”的sysenter指令,才算是和中断脱离了一点点干系。而软中断必须得进行这些检查,所以从这点上来看,中断的开销应该是比系统调用的开销要多的。

根据前文的实验结果,系统调用开销是200ns起步。没看过这个文章的同学可以关注我,然后从历史文章里找。
2.和进程上下文切换开销对比
和进程上下文切换比较起来,进程上下文切换是从用户进程A切换到了用户进程B。而软中断切换是从用户进程A切换到了内核线程ksoftirqd上。 而ksoftirqd作为一个内核控制路径,其处理程序比一个用户进程要轻量,所以上下文切换开销相对比进程切换要稍一些。大家感兴趣的,可以继续阅读《深入理解Linux内核》的-第五章。

根据前文的实验结果,进程上下文切换开销是3us-5us。没看过这个文章的同学可以关注我,然后从历史文章里找。
相关Linux命令
top: si列展示软中断造成CPU开销
vmstat 1:in列每秒展示软中断次数
cat /proc/softirqs:展示所有软中断发生的总数,包括TIMER、NET_TX、NET_RX等

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值