博客園 .NET 5 之路,我們可以學(xué)到什么?
移動(dòng)開(kāi)發(fā)和人工智能編者:?博客園團(tuán)隊(duì)發(fā)布的原文:Memcached 的惹禍,.NET 5.0 的背鍋,?博客園覺(jué)得上次升級(jí).NET 5在沒(méi)有確認(rèn)具體的原因的情況下把鍋甩錯(cuò)了,因此有了這篇文章。
下面是博客園的博客原文:
抱歉,拖到現(xiàn)在才寫(xiě)這篇為 .NET 5.0 洗白的博文(之前的博文),不好意思,又錯(cuò)了,不是洗白,是還 .NET 5.0 的清白。
抱歉,就在今天上午寫(xiě)這篇博客的過(guò)程中,由于一個(gè)bug被迫在訪問(wèn)高峰發(fā)布,在10:30~11:10再次引發(fā)上次遇到的同樣故障,由此給您帶來(lái)麻煩,請(qǐng)您諒解。
2020年10月14日晚上我們發(fā)布了升級(jí)至 .NET 5.0 RC 2 的博客系統(tǒng),在正式版發(fā)布之前進(jìn)行升級(jí)不是我們想追求前衛(wèi),而是因?yàn)椋?/p>
微軟官博已經(jīng)說(shuō)明可以用于生產(chǎn)環(huán)境
RC2 is a “go live” release; you are supported using it in production.
正則表達(dá)式性能大幅提升(Regular expression performance improvements)
On many of the expressions we’ve tried, these improvements routinely result in throughput improvements of 3-6x, and in some cases, much more.
Json 序列化性能提升
JsonSerializer performance is significantly improved in .NET 5.0.
想使用 EF Core 5.0 的新特性(What's New in EF Core 5.0)
最吸引我們的是第2點(diǎn),博客系統(tǒng)的代碼中用了很多正則表達(dá)式,是耗CPU大戶。
而且升級(jí)很簡(jiǎn)單:
TargetFramework 由?
netcoreapp3.1?改為?net5.0更新 nuget 包
容器鏡像?
mcr.microsoft.com/dotnet/core/sdk:3.1?改為?mcr.microsoft.com/dotnet/sdk:5.0,mcr.microsoft.com/dotnet/core/aspnet:3.1?改為?mcr.microsoft.com/dotnet/aspnet:5.0
發(fā)布后從第2天上午訪問(wèn)高峰的監(jiān)控?cái)?shù)據(jù)看,CPU消耗降了10%,效果不錯(cuò)。
輕松升級(jí),提前享受 .NET 5.0 的性能提升,印象中這是我們?cè)?.NET Core 大版本升級(jí)歷史中最?lèi)芤獾囊淮巍?/p>
下午我們帶著升級(jí)后的喜悅心情歡迎新人的加入,現(xiàn)在能夠遇到有興趣學(xué)習(xí) .NET 的新人也是不容易的,好了,現(xiàn)在可以直接學(xué) .NET 5.0 了。就在新人歡迎會(huì)期間,網(wǎng)站出現(xiàn)了故障,昨晚升級(jí)到 .NET 5.0,今天下午就出故障,最大的嫌疑對(duì)象顯然是 .NET 5.0,當(dāng)機(jī)立斷地進(jìn)行回退操作,如果回退到升級(jí)之前的版本能恢復(fù)正常,那 .NET 5.0 就罪責(zé)難逃。
用下面的腳本在k8s集群上將部署回退到升級(jí)之前的容器鏡像
./deploy-blog.sh 2.3.73
回退完成之后,很快恢復(fù)正常,鐵證如山,隨后我們立即發(fā)博宣判——博客系統(tǒng)升級(jí)到 .NET 5.0 引發(fā)的故障,讓還未正式出茅廬的 .NET 5.0 就背上一口沉重的鍋。
幸好有開(kāi)發(fā)同事沒(méi)有這么片面地看待問(wèn)題,對(duì)故障進(jìn)行了進(jìn)一步分析,發(fā)現(xiàn)故障與 memcached 服務(wù)器的 tcp 連接數(shù)異常高有關(guān),大量的數(shù)據(jù)庫(kù)連接超時(shí)是因?yàn)檫B不上 memcached (達(dá)到了1萬(wàn)的最大連接數(shù)限制)造成大量請(qǐng)求直接訪問(wèn)數(shù)據(jù)庫(kù)引起的。更進(jìn)一步地,還找到了重現(xiàn)問(wèn)題的方法,多次點(diǎn)擊某些博客,就能讓 memcached tcp 連接數(shù)飆升,排查后發(fā)現(xiàn)這些博客需要被緩存的數(shù)據(jù)超過(guò)了1M,超出了 memcached 單個(gè)緩存項(xiàng)的大小限制(默認(rèn)就是1M),造成數(shù)據(jù)永遠(yuǎn)無(wú)法被緩存,但每次都要徒勞地讀寫(xiě) memcached 服務(wù)器。我們針對(duì)這個(gè)問(wèn)題進(jìn)行了修復(fù),修復(fù)后重新發(fā)布了 .NET 5.0 版,觀察幾天后沒(méi)有再次出現(xiàn)故障。
我們錯(cuò)怪了 .NET 5.0,我們的一時(shí)武斷讓 .NET 5.0 在即將出道之前先背鍋,我們向 .NET 5.0 說(shuō)抱歉,向被誤導(dǎo)的 .NET 開(kāi)發(fā)者說(shuō)抱歉,我們會(huì)吸取教訓(xùn),在故障發(fā)生后不要急于發(fā)博文,先全面分析問(wèn)題,不能因?yàn)槲覀兊囊粫r(shí)誤判產(chǎn)生誤導(dǎo)。
雖然修復(fù)了問(wèn)題,用上了 .NET 5.0,但問(wèn)題背后的真正原因至今沒(méi)有弄明白——僅僅幾次鼠標(biāo)點(diǎn)擊,緩存數(shù)據(jù)超過(guò)1M,就能讓 memcached 服務(wù)器的 tcp 連接數(shù)飆升?可能與我們使用的 memcached 客戶端 EnyimMemcachedCore,待以后再找時(shí)間研究。
今天在寫(xiě)這篇博文的期間,再次遇到這個(gè)故障,看來(lái)有緣分,想躲也躲不過(guò)去了。今天發(fā)生故障與訪問(wèn)高峰發(fā)布有關(guān),但之前我們?cè)u(píng)估過(guò)訪問(wèn)高峰發(fā)布的影響,也就5-10分鐘左右訪問(wèn)速度變慢,不會(huì)產(chǎn)生如此大的重創(chuàng)。這次故障與上次是同樣的表現(xiàn),memcached tcp 連接數(shù)異常高,頻頻達(dá)到1萬(wàn)的最大連接數(shù)限制,打開(kāi)網(wǎng)頁(yè)速度慢就是因?yàn)樵诘却c memcached 服務(wù)器建立 tcp 連接,重啟 memcaced 服務(wù)器也于事無(wú)補(bǔ),很快就會(huì)再次飆升至1萬(wàn),平時(shí)訪問(wèn)高峰也就5000左右的連接。
從 memcached 服務(wù)器的其他指標(biāo)看,雖然上萬(wàn)的 tcp 連接,但并沒(méi)有不堪重負(fù),難道僅僅是車(chē)多路窄造成的堵車(chē)引起大家都通行緩慢?那把路拓寬不就行了,于是將 memcached 服務(wù)器的 tcp 最大連接數(shù)限制由1萬(wàn)拓寬到2萬(wàn),本擔(dān)心連接數(shù)會(huì)飆升到2萬(wàn),但沒(méi)想到竟然恢復(fù)正常了??赡苁悄撤N特殊情況造成需要稍過(guò)萬(wàn)的 tcp 連接,但最大連接數(shù)限制把大家都堵住了,看來(lái)代碼世界也最怕堵車(chē)。

今天集中3個(gè)多小時(shí)的時(shí)間才完成這篇粗糙的博文,在故障后分享一篇博文也不是一件容易的事。
