亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

.NET 某云采購(gòu)平臺(tái)API 掛死問(wèn)題解析

 更新時(shí)間:2024年11月26日 09:23:13   作者:一線碼農(nóng)  
這篇文章主要介紹了.NET 某云采購(gòu)平臺(tái)API 掛死問(wèn)題解析,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧

一:背景

1. 講故事

大概有兩個(gè)月沒(méi)寫(xiě)博客了,關(guān)注我的朋友應(yīng)該知道我最近都把精力花在了星球,這兩個(gè)月時(shí)間也陸陸續(xù)續(xù)的有朋友求助如何分析dump,有些朋友太客氣了,給了大大的紅包,哈哈??,手里面也攢了10多個(gè)不同問(wèn)題類(lèi)型的dump,后續(xù)也會(huì)逐一將分析思路貢獻(xiàn)出來(lái)。

這個(gè)dump是一位朋友大概一個(gè)月前提供給我的,由于wx里面求助的朋友比較多,一時(shí)也沒(méi)找到相關(guān)截圖,不得已破壞一下老規(guī)矩。??????

既然朋友說(shuō)api接口無(wú)響應(yīng),呈現(xiàn)了hangon現(xiàn)象,從一些過(guò)往經(jīng)驗(yàn)看,大概也只有三種情況。

  • 大量鎖等待

  • 線程不夠用

  • 死鎖

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

二: windbg 分析

1. 有大量鎖等待嗎?

要想看是否鎖等待,老規(guī)矩,看一下 同步塊表

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

撲了個(gè)空,啥也沒(méi)有,那就暴力看看所有的線程棧吧。

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

2. 探究線程池隊(duì)列

可以用 !tp 命令查看。

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

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

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

這個(gè)標(biāo)題我覺(jué)得很好,真的不行嗎? 到底行不行,可以從兩點(diǎn)入手:

  • 是不是代碼寫(xiě)的爛?

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

要想找出答案,還得從那 339 個(gè)卡死的線程說(shuō)起,仔細(xì)研究了下每一個(gè)線程的調(diào)用棧,大概卡死在這三個(gè)地方。

<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. 尋找真相

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

  • 開(kāi)閉線程本身就是一個(gè)相對(duì)耗費(fèi)資源和低效的操作。

  • 頻繁的線程調(diào)度給了cpu巨大的壓力

而且這種寫(xiě)法在請(qǐng)求量比較小的情況下還看不出什么問(wèn)題,一旦請(qǐng)求量稍大一些,馬上就會(huì)遇到該dump的這種情況。

三:總結(jié)

綜合來(lái)看這次hangon事故是由于開(kāi)發(fā)人員 異步方法不會(huì)異步化 導(dǎo)致,改法很簡(jiǎn)單,進(jìn)行純異步化改造 (await,async),解放調(diào)用線程,充分利用驅(qū)動(dòng)設(shè)備的能力。

這個(gè)dump也讓我想起了 CLR Via C# 書(shū)中(P646,647) 在講用 await,async 來(lái)改造 同步請(qǐng)求 的例子 。

到此這篇關(guān)于.NET 某云采購(gòu)平臺(tái)API 掛死問(wèn)題解析的文章就介紹到這了,更多相關(guān).NET 某云采購(gòu)平臺(tái)API內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論