記一次 .NET 某娛樂聊天流平臺 CPU 爆高分析

一:背景

1.講故事

前段時間有位朋友加微信,說他的程序直接 CPU=100%,每次只能手工介入重啟,讓我幫忙看下到底怎么回事,哈哈,這種CPU打滿的事故,程序員壓力會非常大, 我讓朋友在 CPU 高的時候抓 2 個 dump 下來,然后發給我分析。

二:WinDbg 分析

1. CPU 真的被打滿了嗎?

為了防止南轅北轍,一定要用 !tp 命令去驗證下是不是真的 CPU 爆高。

0:000>?!tp
CPU?utilization:?100%
Worker?Thread:?Total:?21?Running:?7?Idle:?0?MaxLimit:?32767?MinLimit:?4
Work?Request?in?Queue:?3AsyncTimerCallbackCompletion?TimerInfo@00000000042d2430AsyncTimerCallbackCompletion?TimerInfo@00000000042d2f90AsyncTimerCallbackCompletion?TimerInfo@000000000420c150
--------------------------------------
Number?of?Timers:?0
--------------------------------------
Completion?Port?Thread:Total:?18?Free:?9?MaxFree:?8?CurrentLimit:?18?MaxLimit:?1000?MinLimit:?4

從卦中看確實 100%,太牛了,而且 WorkRequest 還有任務堆積現象,確認無疑后,接下來看下是誰引發的?

2. 誰導致的 CPU 爆高

根據慣例首先懷疑是不是 GC 觸發所致,可以用 !t 查看下線程列表,觀察下有沒有 GC 字樣。

:000>?!t
ThreadCount:??????53
UnstartedThread:??0
BackgroundThread:?53
PendingThread:????0
DeadThread:???????0
Hosted?Runtime:???noLock??ID?OSID?ThreadOBJ???????????State?GC?Mode?????GC?Alloc?Context??????????????????Domain???????????Count?Apt?Exception4????1?1240?00000000021cdf30????2a220?Preemptive??0000000000000000:0000000000000000?00000000021d94c0?0?????MTA?23????2?4db4?00000000041cdaa0????2b220?Preemptive??0000000000000000:0000000000000000?00000000021d94c0?0?????MTA?(Finalizer)?...65??156?22f4?000000000b1a3f60??8029220?Preemptive??00000004527751F0:0000000452775EE8?00000000021d94c0?0?????MTA?(Threadpool?Completion?Port)?66??205?2ef8?000000000b1a1080??8029220?Preemptive??0000000157641DE0:00000001576435B0?00000000021d94c0?0?????MTA?(Threadpool?Completion?Port)?...

從卦中看沒有 GC 字樣,也表明這個程序并不是由 GC 觸發所致,接下來該怎么排查呢?一般來說 CPU 的爆高是由線程抬起來的,所以接下來就是看下 CPU 的檔次和各個線程棧,看有沒有什么新線索, 可以使用 ~*e !clrstack

0:000>?!cpuid
CP??F/M/S??Manufacturer?????MHz0??6,79,1??<unavailable>???22991??6,79,1??<unavailable>???22992??6,79,1??<unavailable>???22993??6,79,1??<unavailable>???22990:000>?~*e?!clrstack?
OS?Thread?Id:?0x2cc4?(68)Child?SP???????????????IP?Call?Site
000000000c14e758?00007ffadeb86e4a?[GCFrame:?000000000c14e758]?
000000000c14e840?00007ffadeb86e4a?[GCFrame:?000000000c14e840]?
000000000c14e878?00007ffadeb86e4a?[HelperMethodFrame:?000000000c14e878]?System.Threading.Monitor.Enter(System.Object)
000000000c14e970?00007ffaceb40491?System.Net.ConnectionGroup.Disassociate(System.Net.Connection)?[f:\dd\NDP\fx\src\net\System\Net\_ConnectionGroup.cs?@?148]
000000000c14e9d0?00007ffaceb3fc93?System.Net.Connection.PrepareCloseConnectionSocket(System.Net.ConnectionReturnResult?ByRef)?[f:\dd\NDP\fx\src\net\System\Net\_Connection.cs?@?3048]
000000000c14eaa0?00007ffacf139bfb?System.Net.Connection.HandleError(Boolean,?Boolean,?System.Net.WebExceptionStatus,?System.Net.ConnectionReturnResult?ByRef)?[f:\dd\NDP\fx\src\net\System\Net\_Connection.cs?@?3119]
000000000c14eb00?00007ffacebc4118?System.Net.Connection.ReadComplete(Int32,?System.Net.WebExceptionStatus)?[f:\dd\NDP\fx\src\net\System\Net\_Connection.cs?@?3387]
000000000c14eb80?00007ffacebe3dc5?System.Net.LazyAsyncResult.Complete(IntPtr)?[f:\dd\NDP\fx\src\net\System\Net\_LazyAsyncResult.cs?@?415]
000000000c14ebe0?00007ffacebe3d07?System.Net.LazyAsyncResult.ProtectedInvokeCallback(System.Object,?IntPtr)?[f:\dd\NDP\fx\src\net\System\Net\_LazyAsyncResult.cs?@?368]
000000000c14ec20?00007ffacf3a476f?System.Net.Security._SslStream.StartFrameBody(Int32,?Byte[],?Int32,?Int32,?System.Net.AsyncProtocolRequest)
000000000c14ec80?00007ffacebb3ed8?System.Net.Security._SslStream.ReadHeaderCallback(System.Net.AsyncProtocolRequest)?[f:\dd\NDP\fx\src\net\System\Net\SecureProtocols\_SslStream.cs?@?1007]
000000000c14ece0?00007ffacebae5ee?System.Net.AsyncProtocolRequest.CompleteRequest(Int32)?[f:\dd\NDP\fx\src\net\System\Net\SecureProtocols\_HelperAsyncResults.cs?@?142]
000000000c14ed10?00007ffacf3a3567?System.Net.FixedSizeReader.CheckCompletionBeforeNextRead(Int32)
000000000c14ed40?00007ffacebae507?System.Net.FixedSizeReader.ReadCallback(System.IAsyncResult)?[f:\dd\NDP\fx\src\net\System\Net\SecureProtocols\_FixedSizeReader.cs?@?148]
000000000c14ed90?00007ffacebe3dc5?System.Net.LazyAsyncResult.Complete(IntPtr)?[f:\dd\NDP\fx\src\net\System\Net\_LazyAsyncResult.cs?@?415]
000000000c14edf0?00007ffadcbe3a63?System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext,?System.Threading.ContextCallback,?System.Object,?Boolean)?[f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs?@?954]
000000000c14eec0?00007ffadcbe38f4?System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,?System.Threading.ContextCallback,?System.Object,?Boolean)?[f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs?@?902]
000000000c14eef0?00007ffadcbe38c2?System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,?System.Threading.ContextCallback,?System.Object)?[f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs?@?891]
000000000c14ef40?00007ffaceba60cf?System.Net.ContextAwareResult.Complete(IntPtr)?[f:\dd\NDP\fx\src\net\System\Net\_ContextAwareResult.cs?@?463]
000000000c14ef90?00007ffacebe3d07?System.Net.LazyAsyncResult.ProtectedInvokeCallback(System.Object,?IntPtr)?[f:\dd\NDP\fx\src\net\System\Net\_LazyAsyncResult.cs?@?368]
000000000c14efd0?00007ffaceba5e2f?System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32,?UInt32,?System.Threading.NativeOverlapped*)?[f:\dd\NDP\fx\src\net\System\Net\Sockets\_BaseOverlappedAsyncResult.cs?@?399]
000000000c14f040?00007ffadcc2ffef?System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32,?UInt32,?System.Threading.NativeOverlapped*)?[f:\dd\ndp\clr\src\BCL\system\threading\overlapped.cs?@?135]
000000000c14f1f0?00007ffade9a6d93?[GCFrame:?000000000c14f1f0]?OS?Thread?Id:?0x5d6c?(70)Child?SP???????????????IP?Call?Site
000000000943e920?00007ffacf139bfb?System.Net.Connection.HandleError(Boolean,?Boolean,?System.Net.WebExceptionStatus,?System.Net.ConnectionReturnResult?ByRef)?OS?Thread?Id:?0x4ad4?(75)Child?SP???????????????IP?Call?Site
...
000000000c94e5a0?00007ffacf139bfb?System.Net.Connection.HandleError(Boolean,?Boolean,?System.Net.WebExceptionStatus,?System.Net.ConnectionReturnResult?ByRef)
...OS?Thread?Id:?0x1d70?(80)Child?SP???????????????IP?Call?Site
...
000000000d24e3a0?00007ffacf139bfb?System.Net.Connection.HandleError(Boolean,?Boolean,?System.Net.WebExceptionStatus,?System.Net.ConnectionReturnResult?ByRef)?[f:\dd\NDP\fx\src\net\System\Net\_Connection.cs?@?3119]
...

從線程棧上看,這個 CPU 是 4個核,剛好對應著 4 個 HandleError 報錯,看樣子是什么網絡出問題了,接下來切到 80 號線程看一下有沒有什么異常類。

0:000>?~80s
clr!AwareLock::Contention+0x194:
00007ffa`deb86e40?4883e801????????sub?????rax,1
0:080>?!mdso
Thread?80:
Location??????????Object????????????Type
------------------------------------------------------------
000000000d24e098??000000015765e028??System.Net.WebException
000000000d24e0f8??0000000340b07110??System.Collections.ArrayList
000000000d24e110??000000015765e2b8??System.Net.HttpWebRequest[]
000000000d24e1c0??0000000340b070b8??System.Net.ConnectionGroup
000000000d24e258??0000000144a79678??System.Net.Connection0:080>?!mdt?000000015765e028
000000015765e028?(System.Net.WebException)_className:NULL?(System.String)_exceptionMethod:NULL?(System.Reflection.MethodBase)_exceptionMethodString:NULL?(System.String)_message:000000015765df70?(System.String)?Length=77,?String="The?underlying?connection?was?closed:?The?connection?was?closed?unexpectedly."...

果然看到了 System.Net.WebException, 從異常信息看貌似是 連接關閉了,到這里我就有了一個大膽的猜測,是不是高頻的異常輸出導致的 CPU 爆高呢?為了驗證,可以到托管堆上找下 WebException 的個數。

0:080>?!dumpheap?-stat
Statistics:MT????Count????TotalSize?Class?Name
...
00007ffacecc38b0????13315??????2343440?System.Net.WebException
00007ffadcdf6570????11369??????1909992?System.IO.IOException
00007ffadcdf5fb8????13380??????2247840?System.ObjectDisposedException
...

看到這么多異常還是挺嚇人的,剛好朋友抓了兩個dump可以做個比較。

0:048>?!dumpheap?-stat
Statistics:MT????Count????TotalSize?Class?Name
00007ffacecc38b0????26745??????4707120?System.Net.WebException
00007ffadcdf6570????26722??????4489296?System.IO.IOException
00007ffadcdf5fb8????28745??????4829160?System.ObjectDisposedException

可以看到,2 min 之內異常增加了合計 4w 左右,這就驗證了程序確實是瘋狂的拋異常,在 Windows 平臺上不管是硬件異常還是軟件異常都由 Windows SEH 異常處理框架統一處理,會出現用戶態和內核態的切換,這樣瘋狂的拋出,必然會導致 CPU 爆高,終于找到原因了,接下來就是尋找誘發因素。

3. 異常是誰誘發的

再回頭看 HandleError 函數的調用棧都是底層的庫函數,從線程棧的 PerformIOCompletionCallback 函數來看是 IO線程 誘發的,能被 IO 線程兜到是因為這是做了異步處理,既然是 異步,自然 OverlappedData 也會非常多。

0:080>?!gchandles?-stat
Statistics:MT????Count????TotalSize?Class?Name
00007ffadc6f7b98????14511??????1625232?System.Threading.OverlappedData
Total?17550?objectsHandles:Strong?Handles:???????426Pinned?Handles:???????23Async?Pinned?Handles:?14511Ref?Count?Handles:????24Weak?Long?Handles:????2430Weak?Short?Handles:???132SizedRef?Handles:?????4

說明此時有大概 1.5w 的異步請求待回頭,請求量還是蠻大的,但還是沒找到異常的用戶代碼,只能找下到底是誰發起了什么請求。

0:080>?!mdso
Thread?80:
Location??????????Object????????????Type
------------------------------------------------------------
...
000000000d24e488??0000000358c57918??System.Net.HttpWebRequest
000000000d24e2e8??00000001407b5b40??System.String??"net_io_readfailure"
...0:080>?!mdt?-r:2?0000000358c57918
0000000358c57918?(System.Net.HttpWebRequest)_Uri:0000000358c57210?(System.Uri)m_String:00000002407ee430?(System.String)?Length=98,?String="https://api.xxxx/peer_messages"....

可以看到請求的連接是 https://api.xxxx/peer_messages,是一個第三方的API接口, 由于底層的連接關閉,導致了最后 net_io_readfailure

把所有的信息整合一下就是:

當請求量大了之后,訪問 https://api.xxxx/peer_messages 會出問題,對方關閉了底層連接,導致客戶端這邊請求出現了大量 IO 回調異常:IOException: Unable to read data from the transport connection: The connection was closed.,2min之間多達合計 4w 的異常拋出,進而引發 CPU 爆高,將信息告訴了朋友,讓朋友重點關注下 https://api.xxxx/peer_messages 這個連接。

三:總結

這次生產事故主要是由于高峰期請求量過大,由于某種原因 Socket 連接關閉,導致了大量的異步回調異常。

解決方法在調用端做好限流,據朋友說減少了不必要的 https://api.xxxx/peer_messages 調用,目前沒有出現 CPU 爆高現象。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/281637.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/281637.shtml
英文地址,請注明出處:http://en.pswp.cn/news/281637.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

linux下mariadb大小寫敏感

2019獨角獸企業重金招聘Python工程師標準>>> Linux下安裝好mariadb后&#xff0c;在使用時會發現mariadb對大小寫敏感&#xff0c;這對開發帶來一定的不利&#xff0c;這時只要在配置文件中配置一下&#xff0c;取消大小寫敏感即可&#xff1a; sudo vi /etc/MySQL/…

評論列表顯示及排序,個人中心顯示

1.顯示所有評論{% for foo in ques.comments %} 2.所有評論排序uquestion db.relationship(Question, backrefdb.backref(comments, order_bycreat_time.desc)) 3.顯示評論條數{{ ques.comments|length }} 1題代碼如下&#xff1a; <h3>評論區:({{ ques.comments|length…

軟件工程現行國標匯集

GB/T 8566-2007 《信息技術 軟件生存周期過程》GB/T 8567-2006 《計算機軟件文檔編制規范》 GB/T 9385-2008《計算機軟件需求規格說明規范》GB/T 9386-2008 《計算機軟件測試文檔編制規范》 GB/T 11457-2006《信息技術 軟件工程術語》GB/T 14394-2008《計算機軟件可靠性和可維護…

oracle listagg方法,Oracle實現字符串拼接和分離功能的方法(LISTAGG函數),oraclelistagg...

Oracle實現字符串拼接和分離功能的方法(LISTAGG函數)&#xff0c;oraclelistagg字符串拼接(String Aggregation Techniques)是數據處理時經常需要用到一個技術&#xff0c;比如需要按時間順序拼裝一個快遞的運輸記錄&#xff0c;或者將流程中各個環節的處理人拼裝為一個字符串。…

他倆都曾是技術大牛,創業這些年來有怎樣的苦與樂?

這是頭哥侃碼的第263篇原創國慶假期回來&#xff0c;「頭哥嘮 B 嘮」的直播仍在繼續。這次我邀請了我工作上的老板和朋友&#xff0c;一起聊了聊關于 “技術創業路上的苦與樂”。熟悉他們兩位的都知道&#xff0c;可以說是技術出身&#xff0c;然后創業當老板的代表。大家都知道…

maven,gradle本地緩存位置

gradle: 配置系統環境變量GRADLE_USER_HOME即可&#xff0c;值為緩存位置。 maven: 修改settings文件&#xff1a;maven的home路徑下的conf文件夾下的settings.xml 對于有些IDEA&#xff0c;還需要配置。但是不要再打開項目后的FILE-->settings配置&#xff0c;而是需要在選…

git和php的區別,Git與Github的有什么區別

Git是一款免費&#xff0c;開源的分布是版本&#xff0c;用于敏捷高效的處理任何或小或大的項目。分布式相對于集中式的最大區別在于開發者可以提到本地&#xff0c;每個開發者通過克隆&#xff0c;在本地磁盤內拷貝一個完整的GIt倉庫。Git的功能特性&#xff1a;1.從服務器上克…

E20171214-sl

well-grounded  地基打的好 relevent adj. 有關的&#xff0c;中肯的; 相關聯的proposal n. 建議; 提議; 求婚; 〈美〉投標;轉載于:https://www.cnblogs.com/lancgg/p/8281675.html

客戶端嵌套 Web 頁面如何選擇

客戶端嵌套 Web 頁面如何選擇客戶端嵌套 Web 頁面如何選擇作者&#xff1a;驚鏵在使用客戶端嵌套WEB頁面有一下幾種方案&#xff1a;WebView2[1]Electron[2]NW.js[3]sciter[4]miniblink[5]現在國內眾多桌面程序都是用了以下五種&#xff0c;因為它跨平臺更為方便&#x1f447;。…

每天練習50個shell

1、統計日志每天IP訪問量前十 awk {print $1} 1.log | sort -n | uniq -c | sort -n 解釋&#xff1a;&#xff08;1&#xff09;awk 命令在分段方面比較有優勢&#xff0c;這里的{print $1}將第一段打印出來&#xff0c;awk可以用-F指定分隔符&#xff0c;如果不指定分隔符&am…

【Tomcat】Tomcat配置與優化(內存、并發、管理)【自己配置】

一、JVM內存配置優化 主要通過以下的幾個jvm參數來設置堆內存的&#xff1a; -Xmx512m 最大總堆內存&#xff0c;一般設置為物理內存的1/4 -Xms512m 初始總堆內存&#xff0c;一般將它設置的和最大堆內存一樣大&#xff0c;這樣就不需要根據當前堆使用情況而調整堆的大…

oracle 網關下載,oracle透明網關訪問sqlserver2000

oracle透明網關訪問sqlserver2000介紹oracle 10g透明網關訪問sqlserver2000一、環境如下:ORACLE 10g 安裝在:192.168.0.250 的window2003 server(版本&#xff1a;Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bit Production) SqlServer 2000安裝在:192.16…

C++和C#的指針小解

昨天和趙崇說了一下工作的事情&#xff0c;說起了性能問題就討論起了數據結果和指針對性能的影響。曾經一直沒有想到這方面的事情&#xff0c;這幾天專門抽時間回想一下這方面的知識&#xff0c;然后一點一點的總結一下&#xff0c;看看數據結構和指針在咱們代碼中是怎樣實現效…

使用RoleBasedAuthorization實現基于用戶角色的訪問權限控制

本文將介紹如何通過 Sang.AspNetCore.RoleBasedAuthorization[1] 庫實現 RBAC 權限管理。使用介紹Step 1添加庫 Sang.AspNetCore.RoleBasedAuthorizationInstall-Package Sang.AspNetCore.RoleBasedAuthorizationStep 2在 Program.cs 中添加builder.Services.AddSangRoleBasedA…

【2018-11-15】中證1000指數的估值詳情

中證1000指數選取中證500和滬深300指數樣本股以外的&#xff0c;流動性好的1000只股票組成&#xff0c;與滬深300 和中證500 等形成互補。 中證1000的個股大多數是由市場上流通市值排名在 800 到 1800 名之間的個股組成&#xff0c;是一個適用范圍較廣的小盤指數。 中證1000的…

[Leetcode Week15]Populating Next Right Pointers in Each Node

Populating Next Right Pointers in Each Node 題解 原創文章&#xff0c;拒絕轉載 題目來源&#xff1a;https://leetcode.com/problems/populating-next-right-pointers-in-each-node/description/ Description Given a binary tree struct TreeLinkNode {TreeLinkNode *left…

php 數組 1 開始,php數組使用1

1、array_values($arr) 將數組轉換成索引數組$arr1 [id>10,name>楊過,sex>male,salary>8900];echo .var_export(array_values($arr1),true).;2、array_column($arr,$col,$boll); 獲取多維數組的列表組成的數組。$arr2 [];$arr2 [[id>10,name>楊過,sex>…

印度光伏巨頭Adani與華為簽署500MW采購合同

日前&#xff0c;印度光伏巨頭Adani與華為簽訂了采購合同。Adani未來一年的項目全部采用華為FusionSolar3.0智能光伏解決方案&#xff0c;首期500MW采購合同已經簽署&#xff0c;將采購最新的智能光伏控制器&#xff08;組串逆變器&#xff09;SUN2000-43KTL、數據采集器SmartL…

宣布 .NET MAUI 支持 .NET 7 RC 2

點擊上方藍字關注我們&#xff08;本文閱讀時間&#xff1a;6分鐘)支持 .NET 7 Release Candidate 2 的 .NET 多平臺應用程序 UI (MAUI) 現在可在 Windows 和 Mac 上的 Visual Studio 17.4 Preview 4 中使用。RC2 的主要主題是質量和對帶有 iOS 16 的 Xcode 14 的 .NET 支持。此…

linux c文件操作,Linux C 文件的輸入/輸出操作

10.1 文件I/O操作概述在Linux系統中&#xff0c;文件I/O操作可以分為兩類&#xff0c;一類是基于文件描述符的I/O操作&#xff0c;另一類是基于數據流的I/O操作。10.1.1 文件描述符簡介在文件操作一章中&#xff0c;也經常提到文件描述符這個概念。所謂文件描述符&#xff0c;就…