您当前的位置:首页 > 电脑百科 > 程序开发 > 架构

重大事故!IO问题引发线上20台机器同时崩溃

时间:2020-04-21 10:15:27  来源:51CTO  作者:

几年前的一个下午,公司里码农们正在安静地敲着代码,突然很多人的手机同时“哔哔”地响了起来。本来以为发工资了,都挺高兴!打开一看,原来是告警短信。

重大事故!IO问题引发线上20台机器同时崩溃

图片来自 Pexels

故障回顾

告警提示“线程数过多,超出阈值”,“CPU 空闲率太低”。打开监控系统一看,订单服务所有 20 个服务节点都不行了,服务没响应。

查看监控(一个全链路性能监控工具),每个 Spring Boot 节点线程数全都达到了最大值。但是 JVM 堆内存和 GC 没有明显异常。

CPU 空闲率基本都是 0%,但是 CPU 使用率并不高,反而 IO 等待却非常高。

下面是执行 top 命令查看 CPU 状况的截图:

重大事故!IO问题引发线上20台机器同时崩溃

 

从上图,我们可以看到:

  • CPU 空闲率是 0%(上图中红框 id)。
  • CPU 使用率是 22%(上图中红框 us 13% 加上 sy 9%,us 可以理解成用户进程占用的 CPU,sy 可以理解成系统进程占用的 CPU)。
  • CPU 在等待磁盘 IO 操作上花费的时间占比是 76.6% (上图中红框 wa)。

到现在可以确定,问题肯定发生在 IO 等待上。利用监控系统和 jstack 命令,最终定位问题发生在文件写入上。

大量的磁盘读写导致了系统线程资源耗尽,最终导致订单服务无法响应上游服务的请求。

IO,你不知道的那些事儿

既然 IO 对系统性能和稳定性影响这么大,我们就来深入探究一下。

所谓的 I/O(Input/Output)操作实际上就是输入输出的数据传输行为。程序员最关注的主要是磁盘 IO 和网络 IO,因为这两个 IO 操作和应用程序的关系最直接最紧密。

磁盘 IO:磁盘的输入输出,比如磁盘和内存之间的数据传输;网络 IO:不同系统间跨网络的数据传输,比如两个系统间的远程接口调用。

下面这张图展示了应用程序中发生 IO 的具体场景:

重大事故!IO问题引发线上20台机器同时崩溃

 

通过上图,我们可以了解到 IO 操作发生的具体场景。一个请求过程可能会发生很多次的 IO 操作:

  • 页面请求到服务器会发生网络 IO。
  • 服务之间远程调用会发生网络 IO。
  • 应用程序访问数据库会发生网络 IO。
  • 数据库查询或者写入数据会发生磁盘 IO。

IO 和 CPU 的关系

不少攻城狮会这样理解,如果 CPU 空闲率是 0%,就代表 CPU 已经在满负荷工作,没精力再处理其他任务了。真是这样的吗?

我们先看一下计算机是怎么管理磁盘 IO 操作的。计算机发展早期,磁盘和内存的数据传输是由 CPU 控制的,也就是说从磁盘读取数据到内存中,是需要 CPU 存储和转发的,期间 CPU 一直会被占用。

我们知道磁盘的读写速度远远比不上 CPU 的运转速度。这样在传输数据时就会占用大量 CPU 资源,造成 CPU 资源严重浪费。

后来有人设计了一个 IO 控制器,专门控制磁盘 IO。当发生磁盘和内存间的数据传输前,CPU 会给 IO 控制器发送指令,让 IO 控制器负责数据传输操作,数据传输完 IO 控制器再通知 CPU。

因此,从磁盘读取数据到内存的过程就不再需要 CPU 参与了,CPU 可以空出来处理其他事情,大大提高了 CPU 利用率。

这个 IO 控制器就是“DMA”,即直接内存访问,Direct Memory Access。现在的计算机基本都采用这种 DMA 模式进行数据传输。

重大事故!IO问题引发线上20台机器同时崩溃

 

通过上面内容我们了解到,IO 数据传输时,是不占用 CPU 的。

当应用进程或线程发生 IO 等待时,CPU 会及时释放相应的时间片资源并把时间片分配给其他进程或线程使用,从而使 CPU 资源得到充分利用。

所以,假如 CPU 大部分消耗在 IO 等待(wa)上时,即便 CPU 空闲率(id)是 0%,也并不意味着 CPU 资源完全耗尽了,如果有新的任务来了,CPU 仍然有精力执行任务。

如下图:

重大事故!IO问题引发线上20台机器同时崩溃

 

在 DMA 模式下执行 IO 操作是不占用 CPU 的,所以 CPU IO 等待(上图的wa)实际上属于 CPU 空闲率的一部分。

所以我们执行 top 命令时,除了要关注 CPU 空闲率,CPU 使用率(us,sy),还要关注 IO Wait(wa)。注意,wa 只代表磁盘 IO Wait,不包括网络 IO Wait。

JAVA 中线程状态和 IO 的关系

当我们用 jstack 查看 Java 线程状态时,会看到各种线程状态。当发生 IO 等待时(比如远程调用时),线程是什么状态呢,Blocked 还是 Waiting?

答案是 Runnable 状态,是不是有些出乎意料!实际上,在操作系统层面 Java 的 Runnable 状态除了包括 Running 状态,还包括 Ready(就绪状态,等待 CPU 调度)和 IO Wait 等状态。

重大事故!IO问题引发线上20台机器同时崩溃

 

 

如上图,Runnable 状态的注解明确说明了,在 JVM 层面执行的线程,在操作系统层面可能在等待其他资源。

如果等待的资源是 CPU,在操作系统层面线程就是等待被 CPU 调度的 Ready 状态;如果等待的资源是磁盘网卡等 IO 资源,在操作系统层面线程就是等待 IO 操作完成的 IO Wait 状态。

有人可能会问,为什么 Java 线程没有专门的 Running 状态呢?

目前绝大部分主流操作系统都是以时间分片的方式对任务进行轮询调度,时间片通常很短,大概几十毫秒。

也就是说一个线程每次在 CPU 上只能执行几十毫秒,然后就会被 CPU 调度出来变成 Ready 状态,等待再一次被 CPU 执行,线程在 Ready 和 Running 两个状态间快速切换。

通常情况,JVM 线程状态主要为了监控使用,是给人看的。当你看到线程状态是 Running 的一瞬间,线程状态早已经切换 N 次了。所以,再给线程专门加一个 Running 状态也就没什么意义了。

深入理解网络 IO 模型

5 种 linux 网络 IO 模型包括:

  • 同步阻塞 IO
  • 同步非阻塞 IO
  • 多路复用 IO
  • 信号驱动 IO
  • 异步 IO

为了更好地理解网络 IO 模型,我们先了解几个基本概念:

①Socket(套接字):Socket 可以理解成,在两个应用程序进行网络通信时,分别在两个应用程序中的通信端点。

通信时,一个应用程序将数据写入 Socket,然后通过网卡把数据发送到另外一个应用程序的 Socket 中。

我们平常所说的 HTTP 和 TCP 协议的远程通信,底层都是基于 Socket 实现的。5 种网络 IO 模型也都要基于 Socket 实现网络通信。

②阻塞与非阻塞:所谓阻塞,就是发出一个请求不能立刻返回响应,要等所有的逻辑全处理完才能返回响应。

非阻塞反之,发出一个请求立刻返回应答,不用等处理完所有逻辑。

③内核空间与用户空间:在 Linux 中,应用程序稳定性远远比不上操作系统程序,为了保证操作系统的稳定性,Linux 区分了内核空间和用户空间。

可以这样理解,内核空间运行操作系统程序和驱动程序,用户空间运行应用程序。

Linux 以这种方式隔离了操作系统程序和应用程序,避免了应用程序影响到操作系统自身的稳定性。

这也是 Linux 系统超级稳定的主要原因。所有的系统资源操作都在内核空间进行,比如读写磁盘文件,内存分配和回收,网络接口调用等。

所以在一次网络 IO 读取过程中,数据并不是直接从网卡读取到用户空间中的应用程序缓冲区,而是先从网卡拷贝到内核空间缓冲区,然后再从内核拷贝到用户空间中的应用程序缓冲区。

对于网络 IO 写入过程,过程则相反,先将数据从用户空间中的应用程序缓冲区拷贝到内核缓冲区,再从内核缓冲区把数据通过网卡发送出去。

同步阻塞 IO

我们先看一下传统阻塞 IO。在 Linux 中,默认情况下所有 Socket 都是阻塞模式的。

当用户线程调用系统函数 read(),内核开始准备数据(从网络接收数据),内核准备数据完成后,数据从内核拷贝到用户空间的应用程序缓冲区,数据拷贝完成后,请求才返回。

从发起 Read 请求到最终完成内核到应用程序的拷贝,整个过程都是阻塞的。为了提高性能,可以为每个连接都分配一个线程。

因此,在大量连接的场景下就需要大量的线程,会造成巨大的性能损耗,这也是传统阻塞 IO 的最大缺陷。

重大事故!IO问题引发线上20台机器同时崩溃

 

同步非阻塞 IO

用户线程在发起 Read 请求后立即返回,不用等待内核准备数据的过程。如果 Read 请求没读取到数据,用户线程会不断轮询发起 Read 请求,直到数据到达(内核准备好数据)后才停止轮询。

非阻塞 IO 模型虽然避免了由于线程阻塞问题带来的大量线程消耗,但是频繁的重复轮询大大增加了请求次数,对 CPU 消耗也比较明显。这种模型在实际应用中很少使用。

重大事故!IO问题引发线上20台机器同时崩溃

 

多路复用 IO 模型

多路复用 IO 模型,建立在多路事件分离函数 Select,Poll,Epoll 之上。

在发起 Read 请求前,先更新 Select 的 Socket 监控列表,然后等待 Select 函数返回(此过程是阻塞的,所以说多路复用 IO 也是阻塞 IO 模型)。

当某个 Socket 有数据到达时,Select 函数返回。此时用户线程才正式发起 Read 请求,读取并处理数据。

这种模式用一个专门的监视线程去检查多个 Socket,如果某个 Socket 有数据到达就交给工作线程处理。

由于等待 Socket 数据到达过程非常耗时,所以这种方式解决了阻塞 IO 模型一个 Socket 连接就需要一个线程的问题,也不存在非阻塞 IO 模型忙轮询带来的 CPU 性能损耗的问题。

多路复用 IO 模型的实际应用场景很多,比如大家耳熟能详的 Java NIO,redis 以及 Dubbo 采用的通信框架 Netty 都采用了这种模型。

重大事故!IO问题引发线上20台机器同时崩溃

 

下图是基于 Select 函数 Socket 编程的详细流程:

重大事故!IO问题引发线上20台机器同时崩溃

 

信号驱动 IO 模型

信号驱动 IO 模型,应用进程使用 Sigaction 函数,内核会立即返回,也就是说内核准备数据的阶段应用进程是非阻塞的。

内核准备好数据后向应用进程发送 SIGIO 信号,接到信号后数据被复制到应用程序进程。

采用这种方式,CPU 的利用率很高。不过这种模式下,在大量 IO 操作的情况下可能造成信号队列溢出导致信号丢失,造成灾难性后果。

异步 IO 模型

异步 IO 模型的基本机制是,应用进程告诉内核启动某个操作,内核操作完成后再通知应用进程。

在多路复用 IO 模型中,Socket 状态事件到达,得到通知后,应用进程才开始自行读取并处理数据。

在异步 IO 模型中,应用进程得到通知时,内核已经读取完数据并把数据放到了应用进程的缓冲区中,此时应用进程直接使用数据即可。

很明显,异步 IO 模型性能很高。不过到目前为止,异步 IO 和信号驱动 IO 模型应用并不多见,传统阻塞 IO 和多路复用 IO 模型还是目前应用的主流。

Linux 2.6 版本后才引入异步 IO 模型,目前很多系统对异步 IO 模型支持尚不成熟。很多应用场景采用多路复用 IO 替代异步 IO 模型。

如何避免 IO 问题带来的系统故障

对于磁盘文件访问的操作,可以采用线程池方式,并设置线程上线,从而避免整个 JVM 线程池污染,进而导致线程和 CPU 资源耗尽。

对于网络间远程调用。为了避免服务间调用的全链路故障,要设置合理的 TImeout 值,高并发场景下可以采用熔断机制。

在同一 JVM 内部采用线程隔离机制,把线程分为若干组,不同的线程组分别服务于不同的类和方法,避免因为一个小功能点的故障,导致 JVM 内部所有线程受到影响。

此外,完善的运维监控(磁盘 IO,网络 IO)和 APM(全链路性能监控)也非常重要,能及时预警,防患于未然,在故障发生时也能帮助我们快速定位问题。

作者:二马读书

简介:曾任职于阿里巴巴,每日优鲜等互联网公司,任技术总监,15 年电商互联网经历。

编辑:陶家龙

出处:架构师进阶之路(ID:ermadushu)



Tags:IO   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
应用锁一直是苹果用户的痛点,毕竟这功能隔壁安卓早就有了。 为什么苹果一直不给上应用锁的功能呢?之前记者也有提问过苹果的前设计师(首席声优)艾维,他说在苹果的逻辑里,手机密码...【详细内容】
2021-12-23  Tags: IO  点击:(27)  评论:(0)  加入收藏
众所周知,由于今年iOS 15系统的更新幅度不大,导致不少果粉的升级欲望大大降低,iOS 15系统的安装率也远低于去年的iOS 14系列,今年的iOS 15这么拉跨,那么明年的iOS 16呢? 目前关于i...【详细内容】
2021-12-22  Tags: IO  点击:(9)  评论:(0)  加入收藏
IT之家 12 月 20 日消息,百度网盘青春版 iOS 客户端今日晚间率先开启内测,安卓客户端将在稍后内测。使用苹果 iPhone 的IT之家小伙伴可以点此下载内测版,需要先下载 TestFlight...【详细内容】
2021-12-21  Tags: IO  点击:(10)  评论:(0)  加入收藏
相信很多小伙伴都遇到过这种情况,一台iPhone放太久了,当初设置的锁屏密码是什么都自己忘了。 这时候我们只能通过连接电脑进入恢复模式再进行刷机或者用另一台iPhone(登录的是...【详细内容】
2021-12-21  Tags: IO  点击:(16)  评论:(0)  加入收藏
近日苹果发布 iOS 15.2/iPadOS 15.2 正式版的更新,整合了此前测试版中所有新功能,因此更新内容不少,也有一些值得了解的实用功能。有没有必要更新 iOS 15.2 正式版?看完如下功能...【详细内容】
2021-12-17  Tags: IO  点击:(24)  评论:(0)  加入收藏
虽然手机圈每隔几天就会有新机登场,但依旧有小伙伴表示内心毫无波澜—— 「你发任你发,我的小米 6 还能再战两年。」 就算是电池损耗了,按键不灵了,屏幕摔碎了,修一修...【详细内容】
2021-12-16  Tags: IO  点击:(7)  评论:(0)  加入收藏
苹果昨日向 iPhone 和 iPad 用户推送了 iOS 15.2 / iPadOS 15.2 正式版更新,带来了多项新功能。据 9To5Mac 报道,iOS 15.2 / iPadOS 15.2 还有一项新功能,允许用户不借助 Mac...【详细内容】
2021-12-16  Tags: IO  点击:(30)  评论:(0)  加入收藏
今天发了几个关于iOS15.2正式版的微头条,没想到引发了大家不小的讨论,看来大家对于新版本还是有不少期待的,不少人今天早上睡醒之后就选择了升级,还有一些小伙伴一直在纠结要不...【详细内容】
2021-12-15  Tags: IO  点击:(21)  评论:(0)  加入收藏
在今天凌晨,苹果正式上线了 iOS 15.2 正式版 以及 watchOS 8.3 的新版本,这个正式版其实我是一直比较期待的,因为在此前的开发者测试版本中,就一直在内测APP 隐私报告,数字遗产以...【详细内容】
2021-12-15  Tags: IO  点击:(22)  评论:(0)  加入收藏
【手机中国新闻】随着互联网进一步深入到我们的生活,我们已经与数字化脱不开关系了,同时在网络上拥有很多对于我们而言有价值的事物。因此,有不少网友在思考,自己故去以后,网络上...【详细内容】
2021-12-14  Tags: IO  点击:(9)  评论:(0)  加入收藏
▌简易百科推荐
为了构建高并发、高可用的系统架构,压测、容量预估必不可少,在发现系统瓶颈后,需要有针对性地扩容、优化。结合楼主的经验和知识,本文做一个简单的总结,欢迎探讨。1、QPS保障目标...【详细内容】
2021-12-27  大数据架构师    Tags:架构   点击:(5)  评论:(0)  加入收藏
前言 单片机开发中,我们往往首先接触裸机系统,然后到RTOS,那么它们的软件架构是什么?这是我们开发人员必须认真考虑的问题。在实际项目中,首先选择软件架构是非常重要的,接下来我...【详细内容】
2021-12-23  正点原子原子哥    Tags:架构   点击:(7)  评论:(0)  加入收藏
现有数据架构难以支撑现代化应用的实现。 随着云计算产业的快速崛起,带动着各行各业开始自己的基于云的业务创新和信息架构现代化,云计算的可靠性、灵活性、按需计费的高性价...【详细内容】
2021-12-22    CSDN  Tags:数据架构   点击:(10)  评论:(0)  加入收藏
▶ 企业级项目结构封装释义 如果你刚毕业,作为Java新手程序员进入一家企业,拿到代码之后,你有什么感觉呢?如果你没有听过多模块、分布式这类的概念,那么多半会傻眼。为什么一个项...【详细内容】
2021-12-20  蜗牛学苑    Tags:微服务   点击:(9)  评论:(0)  加入收藏
我是一名程序员关注我们吧,我们会多多分享技术和资源。进来的朋友,可以多了解下青锋的产品,已开源多个产品的架构版本。Thymeleaf版(开源)1、采用技术: springboot、layui、Thymel...【详细内容】
2021-12-14  青锋爱编程    Tags:后台架构   点击:(21)  评论:(0)  加入收藏
在了解连接池之前,我们需要对长、短链接建立初步认识。我们都知道,网络通信大部分都是基于TCP/IP协议,数据传输之前,双方通过“三次握手”建立连接,当数据传输完成之后,又通过“四次挥手”释放连接,以下是“三次握手”与“四...【详细内容】
2021-12-14  架构即人生    Tags:连接池   点击:(17)  评论:(0)  加入收藏
随着移动互联网技术的快速发展,在新业务、新领域、新场景的驱动下,基于传统大型机的服务部署方式,不仅难以适应快速增长的业务需求,而且持续耗费高昂的成本,从而使得各大生产厂商...【详细内容】
2021-12-08  架构驿站    Tags:分布式系统   点击:(23)  评论:(0)  加入收藏
本系列为 Netty 学习笔记,本篇介绍总结Java NIO 网络编程。Netty 作为一个异步的、事件驱动的网络应用程序框架,也是基于NIO的客户、服务器端的编程框架。其对 Java NIO 底层...【详细内容】
2021-12-07  大数据架构师    Tags:Netty   点击:(17)  评论:(0)  加入收藏
前面谈过很多关于数字化转型,云原生,微服务方面的文章。虽然自己一直做大集团的SOA集成平台咨询规划和建设项目,但是当前传统企业数字化转型,国产化和自主可控,云原生,微服务是不...【详细内容】
2021-12-06  人月聊IT    Tags:架构   点击:(23)  评论:(0)  加入收藏
微服务看似是完美的解决方案。从理论上来说,微服务提高了开发速度,而且还可以单独扩展应用的某个部分。但实际上,微服务带有一定的隐形成本。我认为,没有亲自动手构建微服务的经历,就无法真正了解其复杂性。...【详细内容】
2021-11-26  GreekDataGuy  CSDN  Tags:单体应用   点击:(35)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条