成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

重大事故!IO問題引發(fā)線上20臺機器同時崩潰

系統(tǒng)
幾年前的一個下午,公司里碼農(nóng)們正在安靜地敲著代碼,突然很多人的手機同時“嗶嗶”地響了起來。本來以為發(fā)工資了,都挺高興!打開一看,原來是告警短信。

幾年前的一個下午,公司里碼農(nóng)們正在安靜地敲著代碼,突然很多人的手機同時“嗶嗶”地響了起來。本來以為發(fā)工資了,都挺高興!打開一看,原來是告警短信。

[[322939]]

圖片來自 Pexels

故障回顧

告警提示“線程數(shù)過多,超出閾值”,“CPU 空閑率太低”。打開監(jiān)控系統(tǒng)一看,訂單服務所有 20 個服務節(jié)點都不行了,服務沒響應。

查看監(jiān)控(一個全鏈路性能監(jiān)控工具),每個 Spring Boot 節(jié)點線程數(shù)全都達到了最大值。但是 JVM 堆內(nèi)存和 GC 沒有明顯異常。

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

下面是執(zhí)行 top 命令查看 CPU 狀況的截圖:

從上圖,我們可以看到:

  • CPU 空閑率是 0%(上圖中紅框 id)。
  • CPU 使用率是 22%(上圖中紅框 us 13% 加上 sy 9%,us 可以理解成用戶進程占用的 CPU,sy 可以理解成系統(tǒng)進程占用的 CPU)。
  • CPU 在等待磁盤 IO 操作上花費的時間占比是 76.6% (上圖中紅框 wa)。

到現(xiàn)在可以確定,問題肯定發(fā)生在 IO 等待上。利用監(jiān)控系統(tǒng)和 jstack 命令,最終定位問題發(fā)生在文件寫入上。

大量的磁盤讀寫導致了系統(tǒng)線程資源耗盡,最終導致訂單服務無法響應上游服務的請求。

IO,你不知道的那些事兒

既然 IO 對系統(tǒng)性能和穩(wěn)定性影響這么大,我們就來深入探究一下。

所謂的 I/O(Input/Output)操作實際上就是輸入輸出的數(shù)據(jù)傳輸行為。程序員最關注的主要是磁盤 IO 和網(wǎng)絡 IO,因為這兩個 IO 操作和應用程序的關系最直接最緊密。

磁盤 IO:磁盤的輸入輸出,比如磁盤和內(nèi)存之間的數(shù)據(jù)傳輸;網(wǎng)絡 IO:不同系統(tǒng)間跨網(wǎng)絡的數(shù)據(jù)傳輸,比如兩個系統(tǒng)間的遠程接口調(diào)用。

下面這張圖展示了應用程序中發(fā)生 IO 的具體場景:

通過上圖,我們可以了解到 IO 操作發(fā)生的具體場景。一個請求過程可能會發(fā)生很多次的 IO 操作:

  • 頁面請求到服務器會發(fā)生網(wǎng)絡 IO。
  • 服務之間遠程調(diào)用會發(fā)生網(wǎng)絡 IO。
  • 應用程序訪問數(shù)據(jù)庫會發(fā)生網(wǎng)絡 IO。
  • 數(shù)據(jù)庫查詢或者寫入數(shù)據(jù)會發(fā)生磁盤 IO。

IO 和 CPU 的關系

不少攻城獅會這樣理解,如果 CPU 空閑率是 0%,就代表 CPU 已經(jīng)在滿負荷工作,沒精力再處理其他任務了。真是這樣的嗎?

我們先看一下計算機是怎么管理磁盤 IO 操作的。計算機發(fā)展早期,磁盤和內(nèi)存的數(shù)據(jù)傳輸是由 CPU 控制的,也就是說從磁盤讀取數(shù)據(jù)到內(nèi)存中,是需要 CPU 存儲和轉(zhuǎn)發(fā)的,期間 CPU 一直會被占用。

我們知道磁盤的讀寫速度遠遠比不上 CPU 的運轉(zhuǎn)速度。這樣在傳輸數(shù)據(jù)時就會占用大量 CPU 資源,造成 CPU 資源嚴重浪費。

后來有人設計了一個 IO 控制器,專門控制磁盤 IO。當發(fā)生磁盤和內(nèi)存間的數(shù)據(jù)傳輸前,CPU 會給 IO 控制器發(fā)送指令,讓 IO 控制器負責數(shù)據(jù)傳輸操作,數(shù)據(jù)傳輸完 IO 控制器再通知 CPU。

因此,從磁盤讀取數(shù)據(jù)到內(nèi)存的過程就不再需要 CPU 參與了,CPU 可以空出來處理其他事情,大大提高了 CPU 利用率。

這個 IO 控制器就是“DMA”,即直接內(nèi)存訪問,Direct Memory Access?,F(xiàn)在的計算機基本都采用這種 DMA 模式進行數(shù)據(jù)傳輸。

通過上面內(nèi)容我們了解到,IO 數(shù)據(jù)傳輸時,是不占用 CPU 的。

當應用進程或線程發(fā)生 IO 等待時,CPU 會及時釋放相應的時間片資源并把時間片分配給其他進程或線程使用,從而使 CPU 資源得到充分利用。

所以,假如 CPU 大部分消耗在 IO 等待(wa)上時,即便 CPU 空閑率(id)是 0%,也并不意味著 CPU 資源完全耗盡了,如果有新的任務來了,CPU 仍然有精力執(zhí)行任務。

如下圖:

在 DMA 模式下執(zhí)行 IO 操作是不占用 CPU 的,所以 CPU IO 等待(上圖的wa)實際上屬于 CPU 空閑率的一部分。

所以我們執(zhí)行 top 命令時,除了要關注 CPU 空閑率,CPU 使用率(us,sy),還要關注 IO Wait(wa)。注意,wa 只代表磁盤 IO Wait,不包括網(wǎng)絡 IO Wait。

Java 中線程狀態(tài)和 IO 的關系

當我們用 jstack 查看 Java 線程狀態(tài)時,會看到各種線程狀態(tài)。當發(fā)生 IO 等待時(比如遠程調(diào)用時),線程是什么狀態(tài)呢,Blocked 還是 Waiting?

答案是 Runnable 狀態(tài),是不是有些出乎意料!實際上,在操作系統(tǒng)層面 Java 的 Runnable 狀態(tài)除了包括 Running 狀態(tài),還包括 Ready(就緒狀態(tài),等待 CPU 調(diào)度)和 IO Wait 等狀態(tài)。

如上圖,Runnable 狀態(tài)的注解明確說明了,在 JVM 層面執(zhí)行的線程,在操作系統(tǒng)層面可能在等待其他資源。

如果等待的資源是 CPU,在操作系統(tǒng)層面線程就是等待被 CPU 調(diào)度的 Ready 狀態(tài);如果等待的資源是磁盤網(wǎng)卡等 IO 資源,在操作系統(tǒng)層面線程就是等待 IO 操作完成的 IO Wait 狀態(tài)。

有人可能會問,為什么 Java 線程沒有專門的 Running 狀態(tài)呢?

目前絕大部分主流操作系統(tǒng)都是以時間分片的方式對任務進行輪詢調(diào)度,時間片通常很短,大概幾十毫秒。

也就是說一個線程每次在 CPU 上只能執(zhí)行幾十毫秒,然后就會被 CPU 調(diào)度出來變成 Ready 狀態(tài),等待再一次被 CPU 執(zhí)行,線程在 Ready 和 Running 兩個狀態(tài)間快速切換。

通常情況,JVM 線程狀態(tài)主要為了監(jiān)控使用,是給人看的。當你看到線程狀態(tài)是 Running 的一瞬間,線程狀態(tài)早已經(jīng)切換 N 次了。所以,再給線程專門加一個 Running 狀態(tài)也就沒什么意義了。

深入理解網(wǎng)絡 IO 模型

5 種 Linux 網(wǎng)絡 IO 模型包括:

  • 同步阻塞 IO
  • 同步非阻塞 IO
  • 多路復用 IO
  • 信號驅(qū)動 IO
  • 異步 IO

為了更好地理解網(wǎng)絡 IO 模型,我們先了解幾個基本概念:

①Socket(套接字):Socket 可以理解成,在兩個應用程序進行網(wǎng)絡通信時,分別在兩個應用程序中的通信端點。

通信時,一個應用程序?qū)?shù)據(jù)寫入 Socket,然后通過網(wǎng)卡把數(shù)據(jù)發(fā)送到另外一個應用程序的 Socket 中。

我們平常所說的 HTTP 和 TCP 協(xié)議的遠程通信,底層都是基于 Socket 實現(xiàn)的。5 種網(wǎng)絡 IO 模型也都要基于 Socket 實現(xiàn)網(wǎng)絡通信。

②阻塞與非阻塞:所謂阻塞,就是發(fā)出一個請求不能立刻返回響應,要等所有的邏輯全處理完才能返回響應。

非阻塞反之,發(fā)出一個請求立刻返回應答,不用等處理完所有邏輯。

③內(nèi)核空間與用戶空間:在 Linux 中,應用程序穩(wěn)定性遠遠比不上操作系統(tǒng)程序,為了保證操作系統(tǒng)的穩(wěn)定性,Linux 區(qū)分了內(nèi)核空間和用戶空間。

可以這樣理解,內(nèi)核空間運行操作系統(tǒng)程序和驅(qū)動程序,用戶空間運行應用程序。

Linux 以這種方式隔離了操作系統(tǒng)程序和應用程序,避免了應用程序影響到操作系統(tǒng)自身的穩(wěn)定性。

這也是 Linux 系統(tǒng)超級穩(wěn)定的主要原因。所有的系統(tǒng)資源操作都在內(nèi)核空間進行,比如讀寫磁盤文件,內(nèi)存分配和回收,網(wǎng)絡接口調(diào)用等。

所以在一次網(wǎng)絡 IO 讀取過程中,數(shù)據(jù)并不是直接從網(wǎng)卡讀取到用戶空間中的應用程序緩沖區(qū),而是先從網(wǎng)卡拷貝到內(nèi)核空間緩沖區(qū),然后再從內(nèi)核拷貝到用戶空間中的應用程序緩沖區(qū)。

對于網(wǎng)絡 IO 寫入過程,過程則相反,先將數(shù)據(jù)從用戶空間中的應用程序緩沖區(qū)拷貝到內(nèi)核緩沖區(qū),再從內(nèi)核緩沖區(qū)把數(shù)據(jù)通過網(wǎng)卡發(fā)送出去。

同步阻塞 IO

我們先看一下傳統(tǒng)阻塞 IO。在 Linux 中,默認情況下所有 Socket 都是阻塞模式的。

當用戶線程調(diào)用系統(tǒng)函數(shù) read(),內(nèi)核開始準備數(shù)據(jù)(從網(wǎng)絡接收數(shù)據(jù)),內(nèi)核準備數(shù)據(jù)完成后,數(shù)據(jù)從內(nèi)核拷貝到用戶空間的應用程序緩沖區(qū),數(shù)據(jù)拷貝完成后,請求才返回。

從發(fā)起 Read 請求到最終完成內(nèi)核到應用程序的拷貝,整個過程都是阻塞的。為了提高性能,可以為每個連接都分配一個線程。

因此,在大量連接的場景下就需要大量的線程,會造成巨大的性能損耗,這也是傳統(tǒng)阻塞 IO 的最大缺陷。

同步非阻塞 IO

用戶線程在發(fā)起 Read 請求后立即返回,不用等待內(nèi)核準備數(shù)據(jù)的過程。如果 Read 請求沒讀取到數(shù)據(jù),用戶線程會不斷輪詢發(fā)起 Read 請求,直到數(shù)據(jù)到達(內(nèi)核準備好數(shù)據(jù))后才停止輪詢。

非阻塞 IO 模型雖然避免了由于線程阻塞問題帶來的大量線程消耗,但是頻繁的重復輪詢大大增加了請求次數(shù),對 CPU 消耗也比較明顯。這種模型在實際應用中很少使用。

多路復用 IO 模型

多路復用 IO 模型,建立在多路事件分離函數(shù) Select,Poll,Epoll 之上。

在發(fā)起 Read 請求前,先更新 Select 的 Socket 監(jiān)控列表,然后等待 Select 函數(shù)返回(此過程是阻塞的,所以說多路復用 IO 也是阻塞 IO 模型)。

當某個 Socket 有數(shù)據(jù)到達時,Select 函數(shù)返回。此時用戶線程才正式發(fā)起 Read 請求,讀取并處理數(shù)據(jù)。

這種模式用一個專門的監(jiān)視線程去檢查多個 Socket,如果某個 Socket 有數(shù)據(jù)到達就交給工作線程處理。

由于等待 Socket 數(shù)據(jù)到達過程非常耗時,所以這種方式解決了阻塞 IO 模型一個 Socket 連接就需要一個線程的問題,也不存在非阻塞 IO 模型忙輪詢帶來的 CPU 性能損耗的問題。

多路復用 IO 模型的實際應用場景很多,比如大家耳熟能詳?shù)?Java NIO,Redis 以及 Dubbo 采用的通信框架 Netty 都采用了這種模型。

下圖是基于 Select 函數(shù) Socket 編程的詳細流程:

信號驅(qū)動 IO 模型

信號驅(qū)動 IO 模型,應用進程使用 Sigaction 函數(shù),內(nèi)核會立即返回,也就是說內(nèi)核準備數(shù)據(jù)的階段應用進程是非阻塞的。

內(nèi)核準備好數(shù)據(jù)后向應用進程發(fā)送 SIGIO 信號,接到信號后數(shù)據(jù)被復制到應用程序進程。

采用這種方式,CPU 的利用率很高。不過這種模式下,在大量 IO 操作的情況下可能造成信號隊列溢出導致信號丟失,造成災難性后果。

異步 IO 模型

異步 IO 模型的基本機制是,應用進程告訴內(nèi)核啟動某個操作,內(nèi)核操作完成后再通知應用進程。

在多路復用 IO 模型中,Socket 狀態(tài)事件到達,得到通知后,應用進程才開始自行讀取并處理數(shù)據(jù)。

在異步 IO 模型中,應用進程得到通知時,內(nèi)核已經(jīng)讀取完數(shù)據(jù)并把數(shù)據(jù)放到了應用進程的緩沖區(qū)中,此時應用進程直接使用數(shù)據(jù)即可。

很明顯,異步 IO 模型性能很高。不過到目前為止,異步 IO 和信號驅(qū)動 IO 模型應用并不多見,傳統(tǒng)阻塞 IO 和多路復用 IO 模型還是目前應用的主流。

Linux 2.6 版本后才引入異步 IO 模型,目前很多系統(tǒng)對異步 IO 模型支持尚不成熟。很多應用場景采用多路復用 IO 替代異步 IO 模型。

如何避免 IO 問題帶來的系統(tǒng)故障

對于磁盤文件訪問的操作,可以采用線程池方式,并設置線程上線,從而避免整個 JVM 線程池污染,進而導致線程和 CPU 資源耗盡。

對于網(wǎng)絡間遠程調(diào)用。為了避免服務間調(diào)用的全鏈路故障,要設置合理的 TImeout 值,高并發(fā)場景下可以采用熔斷機制。

在同一 JVM 內(nèi)部采用線程隔離機制,把線程分為若干組,不同的線程組分別服務于不同的類和方法,避免因為一個小功能點的故障,導致 JVM 內(nèi)部所有線程受到影響。

此外,完善的運維監(jiān)控(磁盤 IO,網(wǎng)絡 IO)和 APM(全鏈路性能監(jiān)控)也非常重要,能及時預警,防患于未然,在故障發(fā)生時也能幫助我們快速定位問題。

作者:二馬讀書

簡介:曾任職于阿里巴巴,每日優(yōu)鮮等互聯(lián)網(wǎng)公司,任技術總監(jiān),15 年電商互聯(lián)網(wǎng)經(jīng)歷。

編輯:陶家龍

出處:架構(gòu)師進階之路(ID:ermadushu)

 

責任編輯:武曉燕 來源: 架構(gòu)師進階之路
相關推薦

2020-08-20 07:37:21

數(shù)據(jù)庫開源框架

2015-12-01 15:19:02

2010-01-05 10:57:30

2019-12-10 09:42:57

OOM運維內(nèi)存

2023-09-07 08:05:32

三元表達式自動

2020-12-07 10:29:27

5G工業(yè)互聯(lián)網(wǎng)網(wǎng)絡安全

2020-05-07 11:00:24

Go亂碼框架

2023-02-16 08:55:13

2020-10-26 21:03:39

Kubernetes集kubectl終端日志文件

2020-04-02 07:31:53

RPC超時服務端

2017-11-23 11:12:57

數(shù)據(jù)中心運維基礎

2014-11-07 17:07:50

IT管理

2021-10-25 09:29:25

網(wǎng)絡安全云安全漏洞

2019-05-13 15:00:14

MySQLMyCat數(shù)據(jù)庫

2014-03-26 11:40:49

金山毒霸系統(tǒng)崩潰

2020-12-09 08:59:59

MongoDB復合索事故

2011-08-04 14:07:43

2021-10-08 08:55:23

FacebookBGP工具

2014-05-19 09:36:50

新聞回顧

2024-06-12 11:19:10

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日本高清中文字幕 | 亚洲精品在线视频 | 婷婷国产一区二区三区 | 久久亚洲欧美日韩精品专区 | 超碰地址| 久草免费视 | jlzzjlzz国产精品久久 | 亚洲一区精品在线 | 精品一区二区av | 精品久久一区二区三区 | 久久久久久美女 | 免费毛片网站在线观看 | 成人h视频在线 | 日本一二三区高清 | 国产午夜精品一区二区三区在线观看 | 欧美不卡在线 | 中文字字幕在线中文乱码范文 | 国产欧美日韩一区 | 亚洲一区二区电影在线观看 | 欧美久久一区 | 午夜电影福利 | 亚洲天堂精品久久 | 亚洲福利网站 | 在线中文字幕日韩 | 亚洲一区 | 午夜激情国产 | 国产视频中文字幕 | 99视频在线免费观看 | www国产成人免费观看视频,深夜成人网 | 美女天天干天天操 | 激情欧美日韩一区二区 | 国产成人一区二区 | 人人看人人草 | 中文字幕在线视频免费观看 | 国产精品久久久久久久久免费桃花 | 亚洲久久 | 欧美日韩视频在线 | 国产91精品久久久久久久网曝门 | 成人美女免费网站视频 | 欧洲毛片 | 日韩欧美手机在线 |