日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

记一次 .NET 某云采购平台API 挂死分析

發布時間:2023/12/4 asp.net 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 记一次 .NET 某云采购平台API 挂死分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一:背景

1. 講故事

大概有兩個月沒寫博客了,關注我的朋友應該知道我最近都把精力花在了星球,這兩個月時間也陸陸續續的有朋友求助如何分析dump,有些朋友太客氣了,給了大大的紅包,哈哈????,手里面也攢了10多個不同問題類型的dump,后續也會逐一將分析思路貢獻出來。

這個dump是一位朋友大概一個月前提供給我的,由于wx里面求助的朋友比較多,一時也沒找到相關截圖,不得已破壞一下老規矩。????????????

既然朋友說api接口無響應,呈現了hangon現象,從一些過往經驗看,大概也只有三種情況。

  • 大量鎖等待

  • 線程不夠用

  • 死鎖

有了這種先入為主的思想,那就上windbg說事唄。

二:windbg 分析

1. 有大量鎖等待嗎?

要想看是否鎖等待,老規矩,看一下 同步塊表。

0:000>?!syncblk Index?SyncBlock?MonitorHeld?Recursion?Owning?Thread?Info??SyncBlock?Owner ----------------------------- Total???????????1673 CCW?????????????3 RCW?????????????4 ComClassFactory?0 Free????????????397

撲了個空,啥也沒有,那就暴力看看所有的線程棧吧。

不看還好,一看嚇一跳,有339個線程卡在了 System.Threading.Monitor.ObjWait(Boolean, Int32, System.Object) 處,不過轉念一想,就算有339個線程卡在這里,真的會導致程序hangon嗎?也不一定,畢竟我看過有1000+的線程也不會卡死,只不過cpu爆高而已,接下來繼續研判一下是不是線程不夠用導致,可以從 線程池任務隊列 上面入手。

2. 探究線程池隊列

可以用 !tp 命令查看。

0:000>?!tp CPU?utilization:?10% Worker?Thread:?Total:?328?Running:?328?Idle:?0?MaxLimit:?32767?MinLimit:?4 Work?Request?in?Queue:?74Unknown?Function:?00007ffe91cc17d0??Context:?000001938b5d8d98Unknown?Function:?00007ffe91cc17d0??Context:?000001938b540238Unknown?Function:?00007ffe91cc17d0??Context:?000001938b5eec08...Unknown?Function:?00007ffe91cc17d0??Context:?0000019390552948Unknown?Function:?00007ffe91cc17d0??Context:?0000019390562398Unknown?Function:?00007ffe91cc17d0??Context:?0000019390555b30 -------------------------------------- Number?of?Timers:?0 -------------------------------------- Completion?Port?Thread:Total:?5?Free:?4?MaxFree:?8?CurrentLimit:?4?MaxLimit:?1000?MinLimit:?4

從輸出信息看,線程池中328個線程全部打滿,工作隊列中還有74位客人在等待,綜合這兩點信息就已經很清楚了,本次hangon是由于大量的客人到來超出了線程池的接待能力所致。

3. 接待能力真的不行嗎?

這個標題我覺得很好,真的不行嗎?到底行不行,可以從兩點入手:

  • 是不是代碼寫的爛?

  • qps是不是真的超出了接待能力?

要想找出答案,還得從那 339 個卡死的線程說起,仔細研究了下每一個線程的調用棧,大概卡死在這三個地方。

<1>. GetModel

public?static?T?GetModel<T,?K>(string?url,?K?content) {T?result?=?default(T);HttpClientHandler?httpClientHandler?=?new?HttpClientHandler();httpClientHandler.AutomaticDecompression?=?DecompressionMethods.GZip;HttpClientHandler?handler?=?httpClientHandler;using?(HttpClient?httpClient?=?new?HttpClient(handler)){string?content2?=?JsonConvert.SerializeObject((object)content);HttpContent?httpContent?=?new?StringContent(content2);httpContent.Headers.ContentType?=?new?MediaTypeHeaderValue("application/json");string?mD5ByCrypt?=?Md5.GetMD5ByCrypt(ConfigurationManager.AppSettings["SsoToken"]?+?DateTime.Now.ToString("yyyyMMdd"));httpClient.DefaultRequestHeaders.Add("token",?mD5ByCrypt);httpClient.DefaultRequestHeaders.Accept.Add(new?MediaTypeWithQualityHeaderValue("application/json"));HttpResponseMessage?result2?=?httpClient.PostAsync(url,?httpContent).Result;if?(result2.IsSuccessStatusCode){string?result3?=?result2.Content.ReadAsStringAsync().Result;return?JsonConvert.DeserializeObject<T>(result3);}return?result;} }

<2>. Get

public?static?T?Get<T>(string?url,?string?serviceModuleName) {try{T?val3?=?default(T);HttpClient?httpClient?=?TryGetClient(serviceModuleName,?true);using?(HttpResponseMessage?httpResponseMessage?=?httpClient.GetAsync(GetRelativeRquestUrl(url,?serviceModuleName,?true)).Result){if?(httpResponseMessage.IsSuccessStatusCode){string?result?=?httpResponseMessage.Content.ReadAsStringAsync().Result;if?(!string.IsNullOrEmpty(result)){val3?=?JsonConvert.DeserializeObject<T>(result);}}}T?val4?=?val3;val5?=?val4;return?val5;}catch?(Exception?exception){throw;} }

<3>. GetStreamByApi

public?static?Stream?GetStreamByApi<T>(string?url,?T?content) {Stream?result?=?null;HttpClientHandler?httpClientHandler?=?new?HttpClientHandler();httpClientHandler.AutomaticDecompression?=?DecompressionMethods.GZip;HttpClientHandler?handler?=?httpClientHandler;using?(HttpClient?httpClient?=?new?HttpClient(handler)){httpClient.DefaultRequestHeaders.Accept.Add(new?MediaTypeWithQualityHeaderValue("application/octet-stream"));string?content2?=?JsonConvert.SerializeObject((object)content);HttpContent?httpContent?=?new?StringContent(content2);httpContent.Headers.ContentType?=?new?MediaTypeHeaderValue("application/json");HttpResponseMessage?result2?=?httpClient.PostAsync(url,?httpContent).Result;if?(result2.IsSuccessStatusCode){result?=?result2.Content.ReadAsStreamAsync().Result;}httpContent.Dispose();return?result;} }

4. 尋找真相

上面我羅列的這三個方法的代碼,不知道大家可看出什么問題了?對,就是 異步方法同步化,這種寫法本身就很低效,主要表現在2個方面。

  • 開閉線程本身就是一個相對耗費資源和低效的操作。

  • 頻繁的線程調度給了cpu巨大的壓力

而且這種寫法在請求量比較小的情況下還看不出什么問題,一旦請求量稍大一些,馬上就會遇到該dump的這種情況。

三:總結

綜合來看這次hangon事故是由于開發人員 異步方法不會異步化 導致,改法很簡單,進行純異步化改造 (await,async),解放調用線程,充分利用驅動設備的能力。

這個dump也讓我想起了 CLR Via C# 書中(P646,647) 在講用 await,async 來改造 同步請求?的例子 。

我覺得這個dump就是該例子的最好佐證!????????????

END

工作中的你,是否已遇到 ...?

1. CPU爆高

2. 內存暴漲

3. 資源泄漏

4. 崩潰死鎖

5. 程序呆滯

等緊急事件,全公司都指望著你能解決...? 危難時刻才能展現你的技術價值,作為專注于.NET高級調試的技術博主,歡迎微信搜索: 一線碼農聊技術,免費協助你分析Dump文件,希望我能將你的踩坑經驗分享給更多的人。

總結

以上是生活随笔為你收集整理的记一次 .NET 某云采购平台API 挂死分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。