Memcached 的惹禍,.NET 5.0 的背鍋
阿新 • • 發佈:2020-10-28
抱歉,拖到現在才寫這篇為 .NET 5.0 洗白的博文([之前的博文](https://www.cnblogs.com/cmt/p/13820677.html)),不好意思,又錯了,不是洗白,是還 .NET 5.0 的清白。
抱歉,就在今天上午寫這篇部落格的過程中,由於一個bug被迫在訪問高峰釋出,在10:30~11:10再次引發上次遇到的同樣故障,由此給您帶來麻煩,請您諒解。
2020年10月14日晚上我們釋出了升級至 .NET 5.0 RC 2 的部落格系統,在正式版釋出之前進行升級不是我們想追求前衛,而是因為:
1. 微軟[官博](https://devblogs.microsoft.com/dotnet/announcing-net-5-0-rc-2/)已經說明可以用於生產環境
> RC2 is a “go live” release; you are supported using it in production.
2. 正則表示式效能大幅提升([Regular expression performance improvements](https://devblogs.microsoft.com/dotnet/announcing-net-5-0-preview-8/#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.
3. Json 序列化效能提升
> JsonSerializer performance is significantly improved in .NET 5.0.
4. 想使用 EF Core 5.0 的新特性([What's New in EF Core 5.0](https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/whatsnew))
最吸引我們的是第2點,部落格系統的程式碼中用了很多正則表示式,是耗CPU大戶。
而且升級很簡單:
* 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`
釋出後從第2天上午訪問高峰的監控資料看,CPU消耗降了10%,效果不錯。
輕鬆升級,提前享受 .NET 5.0 的效能提升,印象中這是我們在 .NET Core 大版本升級歷史中最愜意的一次。
下午我們帶著升級後的喜悅心情歡迎新人的加入,現在能夠遇到有興趣學習 .NET 的新人也是不容易的,好了,現在可以直接學 .NET 5.0 了。就在新人歡迎會期間,網站出現了故障,昨晚升級到 .NET 5.0,今天下午就出故障,最大的嫌疑物件顯然是 .NET 5.0,當機立斷地進行回退操作,如果回退到升級之前的版本能恢復正常,那 .NET 5.0 就罪責難逃。
用下面的指令碼在k8s叢集上將部署回退到升級之前的容器映象
```bash
./deploy-blog.sh 2.3.73
```
回退完成之後,很快恢復正常,鐵證如山,隨後我們立即發博宣判——[部落格系統升級到 .NET 5.0 引發的故障](https://www.cnblogs.com/cmt/p/13820677.html),讓還未正式出茅廬的 .NET 5.0 就背上一口沉重的鍋。
幸好有開發同事沒有這麼片面地看待問題,對故障進行了進一步分析,發現故障與 memcached 伺服器的 tcp 連線數異常高有關,大量的資料庫連線超時是因為連不上 memcached (達到了1萬的最大連線數限制)造成大量請求直接訪問資料庫引起的。更進一步地,還找到了重現問題的方法,多次點選某些部落格,就能讓 memcached tcp 連線數飆升,排查後發現這些部落格需要被快取的資料超過了1M,超出了 memcached 單個快取項的大小限制(預設就是1M),造成資料永遠無法被快取,但每次都要徒勞地讀寫 memcached 伺服器。我們針對這個問題進行了修復,修復後重新發布了 .NET 5.0 版,觀察幾天後沒有再次出現故障。
我們錯怪了 .NET 5.0,我們的一時武斷讓 .NET 5.0 在即將出道之前先背鍋,我們向 .NET 5.0 說抱歉,向被誤導的 .NET 開發者說抱歉,我們會吸取教訓,在故障發生後不要急於發博文,先全面分析問題,不能因為我們的一時誤判產生誤導。
雖然修復了問題,用上了 .NET 5.0,但問題背後的真正原因至今沒有弄明白——僅僅幾次滑鼠點選,快取資料超過1M,就能讓 memcached 伺服器的 tcp 連線數飆升?可能與我們使用的 memcached 客戶端 [EnyimMemcachedCore](https://github.com/cnblogs/EnyimMemcachedCore),待以後再找時間研究。
今天在寫這篇博文的期間,再次遇到這個故障,看來有緣分,想躲也躲不過去了。今天發生故障與訪問高峰釋出有關,但之前我們評估過訪問高峰釋出的影響,也就5-10分鐘左右訪問速度變慢,不會產生如此大的重創。這次故障與上次是同樣的表現,memcached tcp 連線數異常高,頻頻達到1萬的最大連線數限制,開啟網頁速度慢就是因為在等待與 memcached 伺服器建立 tcp 連線,重啟 memcaced 伺服器也於事無補,很快就會再次飆升至1萬,平時訪問高峰也就5000左右的連線。
從 memcached 伺服器的其他指標看,雖然上萬的 tcp 連線,但並沒有不堪重負,難道僅僅是車多路窄造成的堵車引起大家都通行緩慢?那把路拓寬不就行了,於是將 memcached 伺服器的 tcp 最大連線數限制由1萬拓寬到2萬,本擔心連線數會飆升到2萬,但沒想到竟然恢復正常了。可能是某種特殊情況造成需要稍過萬的 tcp 連線,但最大連線數限制把大家都堵住了,看來程式碼世界也最怕堵車。
![](https://img2020.cnblogs.com/blog/35695/202010/35695-20201028142647896-1065445960.png)
今天集中3個多小時的時間才完成這篇粗糙的博文,在故障後分享一篇博文也不是一件容易的事。