阿裡簡訊回執.net sdk的bug導致生產服務cpu 100%排查

来源:https://www.cnblogs.com/huangxincheng/archive/2020/05/26/12966717.html
-Advertisement-
Play Games

一:背景 1. 講故事 去年阿裡聚石塔上的所有isv簡訊通道全部對接阿裡通信,我們就做了對接改造,使用阿裡提供的.net sdk。 網址:https://help.aliyun.com/document_detail/114480.html 同事當時使用的是ons-.net v1.1.3版本,程式上 ...


一:背景

1. 講故事

去年阿裡聚石塔上的所有isv簡訊通道全部對接阿裡通信,我們就做了對接改造,使用阿裡提供的.net sdk

網址:https://help.aliyun.com/document_detail/114480.html

同事當時使用的是ons-.net v1.1.3版本,程式上線後若幹天就會有一次程式崩潰現象,當時也沒特別在意,以為是自己代碼或者環境出了什麼問題,索性就加了一個檢測程式,如果檢測到sdk程式退出就自動重啟,就這樣先糊弄著,直到有一天伺服器告警,那個程式CPU居然飆到100%,伺服器可是16核128G的哦。。。

二:分析問題

1. 抓dump文件

情況比較緊急,馬上給程式發送Ctrl+C命令讓程式退出,結果又退出不了,奇葩。。。為了分析問題抓了一個dump下來,然後強制kill掉程式。

2. 查看線程池以及各個線程正在做什麼?


0:000> !tp
CPU utilization: 100%
Worker Thread: Total: 0 Running: 0 Idle: 0 MaxLimit: 32767 MinLimit: 16
Work Request in Queue: 0
--------------------------------------
Number of Timers: 1
--------------------------------------
Completion Port Thread:Total: 1 Free: 1 MaxFree: 32 CurrentLimit: 1 MaxLimit: 1000 MinLimit: 16

CPU utilization: 100% 上看,果然cpu100%了,發現 Worker Thread 沒有Running 線程,可能是因為執行了Ctrl+C都銷毀了,接下來用 ~*e !clrstack 把所有的托管線程棧打出來。


0:000> ~*e !clrstack
OS Thread Id: 0x1818 (0)
Unable to walk the managed stack. The current thread is likely not a 
managed thread. You can run !threads to get a list of managed threads in
the process
Failed to start stack walk: 80070057

從輸出結果看,沒有任何托管線程,唯一的那個線程0還不是還托管線程,然後改成 ~*e !dumpstack把非托管線程棧找出來。


0:000> ~*e !dumpstack
OS Thread Id: 0x1818 (0)
Current frame: ntdll!ZwRemoveIoCompletion+0x14
Child-SP         RetAddr          Caller, Callee
000000637323ef40 00007ff8327bac2f KERNELBASE!GetQueuedCompletionStatus+0x3f, calling ntdll!ZwRemoveIoCompletion
000000637323efa0 00007ff81b9c8a00 ONSClient4CPP!metaq_juce::URL::launchInDefaultBrowser+0x273d0, calling kernel32!GetQueuedCompletionStatus
000000637323f090 00007ff81ba3eb0a ONSClient4CPP!ons::Message::getMsgBody+0x5a8a, calling ONSClient4CPP!metaq_juce::URL::launchInDefaultBrowser+0x1f100
000000637323f140 00007ff81ba3f084 ONSClient4CPP!ons::Message::getMsgBody+0x6004, calling ONSClient4CPP!ons::Message::getMsgBody+0x5800
000000637323f280 00007ff81ba233b4 ONSClient4CPP!ons::ONSFactoryProperty::setSendMsgTimeout+0xa6b4, calling ONSClient4CPP!ons::ONSFactoryProperty::setSendMsgTimeout+0xa5d0
000000637323f2b0 00007ff81ba11b43 ONSClient4CPP!ons::ONSFactoryAPI::~ONSFactoryAPI+0x153
000000637323f310 00007ff81ba12d64 ONSClient4CPP!ons::SendResultONS::operator=+0xc44, calling ONSClient4CPP!ons::ONSFactoryAPI::~ONSFactoryAPI+0x10
000000637323f460 00007ff81ba83eb4 ONSClient4CPP!ons::Message::getStoreTimestamp+0xf484, calling ONSClient4CPP!ons::Message::getStoreTimestamp+0xf1c4
000000637323f630 00007ff8356f7d94 ntdll!RtlExitUserProcess+0xb4, calling ntdll!LdrShutdownProcess
000000637323f690 00007ff832777c23 KERNELBASE!CtrlRoutine+0xa3
000000637323f780 00007ff834df8364 kernel32!BaseThreadInitThunk+0x14, calling kernel32!WriteConsoleOutputW+0x530

從非托管調用棧來看,其中KERNELBASE!CtrlRoutine 表明主線程接受到了Ctrl+C命令, 從棧頂發現貌似不能退出的原因是主線程被 ONSClient4CPP 接管,而且這個C++正在做遠程連接再等待網路IO返回,但這種會把16核cpu打滿應該不太可能,這個問題貌似到這裡就卡住了。

三: 重啟程式發現問題依舊

1. 抓dump文件

很開心的是程式重新啟動後,過了兩分鐘CPU又在飆升,這次學乖了,等CPU到了60,70%的時候抓dump文件。

2. 繼續排查


0:000> .time
Debug session time: Fri Apr 17 17:36:50.000 2020 (UTC + 8:00)
System Uptime: 355 days 5:33:48.092
Process Uptime: 0 days 0:02:11.000
  Kernel time: 0 days 0:03:31.000
  User time: 0 days 0:13:22.000


0:000> !tp
CPU utilization: 59%
Worker Thread: Total: 3 Running: 0 Idle: 3 MaxLimit: 32767 MinLimit: 16
Work Request in Queue: 0
--------------------------------------
Number of Timers: 1
--------------------------------------
Completion Port Thread:Total: 2 Free: 2 MaxFree: 32 CurrentLimit: 2 MaxLimit: 1000 MinLimit: 16

從上面代碼可以看到,進程啟動了2分11秒,這次cpu利用率是59%,抓的有點早,不過沒關係,先看一下Threads情況。


0:000> !threads
ThreadCount:      25
UnstartedThread:  0
BackgroundThread: 8
PendingThread:    0
DeadThread:       16
Hosted Runtime:   no
                                                                                                        Lock  
       ID OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
   0    1  cdc 0000022bb9f53220    2a020 Preemptive  0000022BBBFACCE8:0000022BBBFADFD0 0000022bb9f27dc0 1     MTA 
   2    2  3dc 0000022bb9f7f9f0    2b220 Preemptive  0000000000000000:0000000000000000 0000022bb9f27dc0 0     MTA (Finalizer) 
   3    4 296c 0000022bb9fe97b0  102a220 Preemptive  0000000000000000:0000000000000000 0000022bb9f27dc0 0     MTA (Threadpool Worker) 
XXXX    5    0 0000022bb9ffc5a0  1039820 Preemptive  0000000000000000:0000000000000000 0000022bb9f27dc0 0     Ukn (Threadpool Worker) 
XXXX    6    0 0000022bd43938c0  1039820 Preemptive  0000000000000000:0000000000000000 0000022bb9f27dc0 0     Ukn (Threadpool Worker) 
.............................................................................
 163   24 29e8 0000022bd4898650  1029220 Preemptive  0000022BBC102108:0000022BBC103FD0 0000022bb9f27dc0 0     MTA (Threadpool Worker) 
 164   25 2984 0000022bd489d470  1029220 Preemptive  0000022BBC0EA2D0:0000022BBC0EBFD0 0000022bb9f27dc0 0     MTA (Threadpool Worker) 

好家伙,才2分11秒,托管線程ThreadCount: 25就死了DeadThread: 16個,而且從threads列表中看,windbg給的最大編號是164,說明當前有 (164+1) - 25 =142 個非托管線程,應該就是阿裡的ONSClient4CPP開啟的,為什麼開啟這麼多線程,這就是一個很值得關註的問題了,接下來還是用 ~*e !dumpstack 把所有線程的托管和非托管線程棧打出來,由於信息太多,我就截幾張圖。


個人猜測,純技術討論:


圖1:

從堆棧上看,有105個線程卡在 ntdll!ZwRemoveIoCompletion+0x14 這裡,而且從 ONSClient4CPP!metaq_juce::URL::launchInDefaultBrowser+0x23072 中看,貌似阿裡開了一個瀏覽器內核,用內核來發送數據,估計這裡併發閾值開的還挺大的,咨詢了下同事是前面有一家大客戶發了很多的簡訊,估計是大量的回持積壓,這個C# sdk進行了瘋狂讀取,這個跟CPU暴漲應該有脫不了的關係。

圖2:

從檢索上看有28個線程貌似正在臨界區等待鎖,CPU高的一個經典案例就是當很多線程在臨界區等待的時候,當某一個正在臨界區中的線程離開後,這28個線程的調度競搶也是CPU高的一個原因。

個人水平有限,進一步挖非托管堆目前還沒這個技術(┬_┬) 。。。

四: 解決方案

這種SDK的問題還能有什麼解決方案,能想到的就是去官網找下可有最新版:

可以看到最新版的 ons-.net v1.1.4 中提到的優化點:優化消息拉取流程,避免特殊情況下拉取異常造成的消息堆積

果然用了最新版的sdk就可以了,

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • akka 2.6.x正式發佈以來已經有好一段時間了。核心變化是typed-actor的正式啟用,當然persistence,cluster等模塊也有較大變化。一開始從名稱估摸就是把傳統any類型的消息改成強類型消息,所以想拖一段時間看看到底能對我們現有基於akka-classic的應用軟體有什麼深層 ...
  • 由於開發中發現以前的Activex控制項功能不夠用,沒辦法需要下載源碼重新增加功能。。。。 這個項目最開始也不我寫的,而我也是個小白,花了半天改好了代碼,然後打包用了一天半。-0- 各種百度,各種找。。。。準備用 InstallShield 2015打包,結果怎麼下打包好了就提示啥啥啥試用版。。。。最 ...
  • 格式轉換convert:轉換圖像的模式transpose:轉換圖像的格式convert之前已經使用過了,這裡就簡單演示一下transpose的作用,transpose主要傳入一些Image中的常量: from PIL import Image# 打開圖像im = Image.open('nnz.jp ...
  • 關於組件 現在前端幾大輪子全面組件化。組件讓我們可以對常用的功能進行封裝,以便復用。組件這東西對於搞.NET的同學其實並不陌生,以前ASP.NET WebForm的用戶控制項其實也是一種組件。它封裝html代碼,封裝業務邏輯,對外提供屬性事件等信息,它完完全全就是個組件,只是用戶控制項跑在服務端,而現在 ...
  • VS這麼強大的IDE,功能很多,有時候想知道某些功能藏在哪,是挺難找的。但是可以根據關鍵字搜索這些功能的駐扎點,在右上角的搜索框(Ctrl+Q)。 比如想知道下麵的計算解決方案的代碼度量的操作位置。 按enter鍵也可以,點擊那個搜索小圖標也可以,既能搜代碼,也能搜IDE功能。 假如想知道vs的顏色 ...
  • 在.NET中,我們可以通過Task.WhenAll用來等待多個任務。任務完成之後,我們可以使用await等待他們來獲取結果。 Task<int> task1 = Task.Run(() => 1); Task<string> task2 = Task.Run(() => "hello"); awai ...
  • 當用戶嚮應用程式發出請求時,伺服器將解析該請求,生成響應,然後將結果發送給客戶端。用戶可能會在伺服器處理請求的時候中止請求。就比如說用戶跳轉到另一個頁面中獲取說關閉頁面。在這種情況下,我們希望停止所有正在進行的工作,以浪費不必要的資源。例如我們可能要取消SQL請求、http調用請求、CPU密集型操作 ...
  • 一.相關介紹 Dockerfile:關於Dockerfile的使用說明,我在文章《讓.NetCore程式跑在任何有docker的地方》中有說到,這裡不在贅述,需要的可以先看下,本文主要介紹Jenkinsfile結合dockerfile配合使用,自動構建.NetCore應用程式。 Jenkinsfil ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...