分類:未分類

C# 工作平行程式庫的例外處理機制

C# 工作平行程式庫的例外處理機制

最近2個月又重回C#懷抱了,昨晚追查一個底層ThreadPool Exception,然後會造成w3wp的Exception, 會造成集區重啟的異常

後來發現有一個非同步呼叫射後不理的部分,並沒有合理的包裝例外,然後又會造成.net framework底層無法Handle的例外

Legacy Code的用法是改一半的非同步呼叫方法

function method1()
{
       method2();
}

async Task<ResultObj> function method2()
{
       //略
}

後來查詢多方說法後(StackOverFlow網友建議),建議這種射後不理的整合寫法,可以採用TPL(工作型非同步執行庫)

正規TPL的非同步方法在Handle的時候如下:

其例外處理範例,因為Task的例外會拋出來的是AggregateException方法。因此可以例用以下方法來走訪所有的Exception

   public static void Main()
   {
      var task1 = Task.Run( () => { throw new CustomException("This exception is expected!"); } );

      try
      {
          task1.Wait();
      }
      catch (AggregateException ae)
      {
          foreach (var e in ae.InnerExceptions) {
              // Handle the custom exception.
              if (e is CustomException) {
                  Console.WriteLine(e.Message);
              }
              // Rethrow any other exception.
              else {
                  throw;
              }
          }
      }
   }

 

後續改寫一版後,能明確抓到射後不理的Exception,也不會造成集區崩潰就變成以下的版本了

Task listenerTask = Task.Run(() => proxy.callService<ResultObject>(inputObj)).ContinueWith( 
	t => { logException(t, proxy.ServiceName); }, TaskContinuationOptions.OnlyOnFaulted);

private static void logException(Task<BaseAddOutput> t, string serviceName)
{
	var message = string.Empty;
    if (t.Exception != null)
       message = t.Exception.Message;
    if (t.Exception.InnerException != null)
       message = t.Exception.InnerException.Message;
    Debug.Log(ConfigUtil.GetBoolean("Debug"), "system call " + serviceName + " error, msg:" + message);
}

 

當然,若不是要射後不理的話,建議還是要讓function async / wait化,來確保執行流程順序中的工作都有被完成

 

MS Docs參考

https://docs.microsoft.com/zh-tw/dotnet/standard/parallel-programming/task-based-asynchronous-programming

關於實作秒殺壓力測試的架構驗證

關於實作秒殺壓力測試的架構驗證

之前為了一個案子,實作了一個POC秒殺的情境,透過python、nginx、lucust、docker來模擬,但那時候必竟是架構新手,對於POC驗證的環節

只想的到以下的方式,以下提供參考…若有盲點或不足之處,歡迎指導…

 

一  測試內容

二  測試方法

三  測試方法

四  測試目標

五  測試環境

5-1 壓力測試部署圖

5-2 壓測用戶端與服務端主機規格

六  系統部署

6-1 系統部署架構圖

6-2相關系統容器配置表

七  性能測試結果與分析

7-1 測試步驟與結果摘要

7-2 劇情1 線上用戶30,000,開放10,000個號碼牌

7-3 劇情2線上用戶30,000,開放30,000個號碼牌

7-4 結果與發現

 

 

一  測試內容

本次測試是針對搶票系統進行壓力測試,在秒殺產品的場景中,需求遠遠大於供給,因此考慮巨大流量的情況下,我們在設計交易的接口中,加入了號碼牌機制,從入場、選位到結帳三關卡皆透過號碼牌的控制來監控與管理入場選擇產品的人流。並逐步縮小對於後端API的請求,達到集中運算資源與降低關鍵接口負載壓力的目的。這次我們主要驗證的功能包含了領取號碼牌選位結帳的功能。

 

二  測試方法

本次採用了python開源的分散式壓力測試工具Locust.io,這個工具的特性是可以快速佈署壓測用戶端的集群,並透過統一的Master發動壓力測試,並具備Dashboard,提供效能統計表與分析圖型,近期Amazon Web Service廠商已經善用其可分散式佈署的特性,透過259台用戶端,將壓力測試提升到每秒超過10萬次的後端請求的等級,請參考相關AWS官方連結

 

這次測試採用容器技術動態建立Locust測試集群,並透過Http協議發出GET請求,伺服器端主要透過Nginx+Tornado建立Load Balance與非阻塞式的Web Server,並結合容器技術動態擴充WebServer群,包含主要關鍵流程API,包含取得號碼牌請求、模擬選位請求、模擬結帳請求。關鍵流程之間,透過Redis快取技術協調並模擬用戶狀態(包含入場前、入場選位前、選位後、結帳前),最終透過MongoDB儲存持久化交易結果。

 

三  測試場景

測試場景包含了1取得號碼牌API,其主要目的是第一關控制流量,但也因為要面對第一線最多的請求流量,因此需要的資源最多。其2為模擬選位API,因應用戶取得號碼牌後的狀態變動,我們透過快取保存用戶狀態,以模擬用戶端行為。用戶在具備號碼牌的狀態下,呼叫模擬選位API,會有自動配位的邏輯處理,亂數決定客戶購買1~4張的張數,並動態查詢仍有空位的連續座位區域並隨機決定。此時會透過鎖定機制,保存在快取內,並非同步創建訂單到NoSQL的儲存體中,其狀態為未付款(Pay Status=1),並將此用戶加入到待付款的佇列中。最終為模擬結帳API,此API將會隨機取得佇列中的排隊付款用戶,並同步更新NoSQL的付款狀態(Pay Status=2),此時會標記其用戶已付款完成。

本次測試樣本將模擬銷售單一場次、6區域,依2回合進行測試,分別開放token限制為1萬、3萬,分別模擬請求流量的變化。

四  測試目標

測試獲取單一物理主機的伺服器在反應時間3秒內,其單位承載量RPS為多少,模擬併發用戶為多少。

 

採用號碼牌分流搶票流程下,在上述系統效能需求下,最終全數票券銷售完成到結帳狀態(模擬完成金流後,寫回訂單資料押付款完成的狀態)需要多久的時間。

 

五 測試環境

  5-1 壓力測試部署圖

  5-2 壓測用戶端與服務端主機規格

環境 機器型號 作業系統 硬體cpu 硬體mem
用戶端 Linux虛擬機 CentOS 7 4核 8G
服務端 Linux虛擬機 CentOS 7 4核 8G

 

六  系統部署

6-1 系統部署架構圖

6-2相關系統容器配置表

容器環境 佈署應用程式 數量# 備註
用戶端主機 Locust Master 1 統一發動測試端與測試結果Dashboard
Locust Slave 10 接受發動測試指令,執行測試腳本
服務端主機 Nginx 3 用於3個關鍵流程的Reverse Proxy分流關卡
Tornado(Token API) 5 主要面對最大流量領取號碼牌請求
Tornado(Reserve API) 3 面對已過濾擁有號碼牌的用戶進行選位模擬
Tornado(Admin API) 1 初始化資料預熱

Dashboard監控資訊

開放TokenLimit接口

MongoDb(NoSQL) 1 主要儲存最終訂單持久化與結帳後模擬金流回填狀態。
Redis Cache Server 1 主要處理關鍵流程間狀態控管

 

 

七  性能測試結果與分析

7-1 測試步驟與結果摘要

步驟一.Dashboard 初始化

步驟二.Locust配置與啟動

步驟三.抽樣觀測Server狀態與銷售狀態

步驟四 銷售完畢後,並待所有結帳佇列消耗完成後,搜集Client端數據

 

7-2 劇情1  模擬線上30,000用戶,開放10,000個號碼牌,銷售總票數為10,000張

7-2-1 Locust壓測用戶端統計資訊

開放10,000個號碼牌,銷售總票數為10,000張
模擬線上用戶數 30,000
用戶平均爬升數/秒 2,000
銷售總花費時數 1分40秒
有效訂單數(已付款,已進入數據庫) 3,971
總請求數(擷至全售完) 117,678
總平均RPS(Request per Second) 1,176.8
取號碼牌成功請求總數(HttpStatus=200) 32,268
模擬選位成功請求總數(HttpStatus=200) 10,903
模擬結帳成功請求總數(HttpStatus=200) 7,610
服務器狀態 全數存活

 

 

 

7-2-2 Locust壓測期間趨勢圖

7-2-3容器正常服務

 

7-3 劇情2  模擬線上30,000用戶,開放20,000個號碼牌,銷售總票數為10,000張

7-3-1 Locust壓測用戶端統計資訊

開放20,000個號碼牌,銷售總票數為10,000張
模擬用戶數 30,000
用戶平均爬升數/秒 2,000
銷售總花費時數 2分17秒
有效訂單數(已付款,已進入數據庫) 3,962
總請求數(擷至全售完) 156,029
總平均RPS(Request per Second) 1,138.9
取號碼牌成功請求總數(HttpStatus=200) 36,606
模擬選位成功請求總數(HttpStatus=200) 14,776
模擬結帳成功請求總數(HttpStatus=200) 6,984
服務器狀態 全數存活

 

 

7-2-2 Locust壓測期間趨勢圖

7-2-3容器正常服務

 

7-4 結果與發現

從相同的壓測用戶參數,並透過號碼牌來控制流程API的流量,我們發現號碼牌發放的控制,可以有效提升服務效率,銷售的時間更短。同時,這次銷售10,000張票在我們配置的架構下(Nginx與Tornado),單台主機可以支撐爆量請求而不會造成應用程式崩潰與異常銷售,仍然可以將其票券全數售完,並正常寫入資料庫。而本次透過容器建置所有的系統與API,說明未來管理上雲或是自建機房(IDC)可以在即短的時間內佈署。同時具備易用與易於擴充的特性。而切分微服務的概念,除了在系統佈署的配置上可以更彈性的運用,且未來更有機會隨時提升到Serverless的層次,透過雲端全託管的服務,可以有效降低維運成本。

 

看了[為你自己學Git]的常用Git指令筆記

看了[為你自己學Git]的常用Git指令筆記

看了為你自己學Git,五倍紅寶石,高見龍大師著作(這本真的釐清很多我對git一知半解的觀念,大推)

 

以下整理筆記,提供日後個人查詢使用~

常用指令

git add (陷阱觀念:p38),add完再edit file,新的變更不會進入暫存區,必須再執行一次add
註:若針對os指令做檔案操作,變更都要透過git add,加入暫存區,若是使用git mv、git rm的話,是git在背後幫我們做掉2段式動作
git status 
git commit -m "變更訊息"
git log (純粹訊息時間)
git log -p (多列出版本之間差異)
git log -g (reflog)
git log --oneline 
git log --oneline --since="" --until=""
git log --oneline --grep="查詢log message字眼"
git log -S "檔案內容指定字眼"

git rm <file> --cached(僅從git移除管控,但會保留檔案,變成untracked file)

git commit --amend -m "修改最後一次commit的訊息"
git commit --amend --no-edit    (不修改訊息,併入變更到最後一次修改-變更須先add到暫存區)

git blame -L 1,5 <file> (顯示第1到第5行的變更簽入者, 抓戰犯XD)

.gitignore可管理不要被git,忽略這個規則,強迫加入的話
git add -f <filename>

git clean -fX(一口氣刪除被忽略的檔案)


不小心本地刪掉檔案,可以用checkout救回,git checkout <file> or . (取回檔案)

git reset --hard(回到head變更狀態)

git reset <commit>^ 拆掉指定commit,回到前
1次,^^代表上2次,也可以使用~,~1代表上一次,~5代表前5次

git reset mode有 --mixed, --soft --hard
            工作目錄    暫存區
mixed     不變          丟掉
soft         不變          不變 (僅移動head)
hard        丟掉          丟掉

如果不小心使用hard模式 reset了某個commit,救的回來嗎?
git reset <之前的commit> --hard(--hard可以強迫放棄reset之後修改的檔案)
若忘了git 的commit,這時就使用git reflog或是git log -g可以查到之前的commit

待續
(FYI) MGIndexs的威力

(FYI) MGIndexs的威力

MGIndexs的威力

bitmap 索引是一種索引形式,它以行的形式存儲一系列位的值。例如,如果您有一百萬條記錄,並且正在名稱列中搜索’bob’,那麼名稱列的b +樹可能類似於下面的圖片,並且當您在葉節點中找到’bob’時,您將得到一個BitArray,表示在該列中按照記錄號索引的’bob’的存在。所以如果BitArray的第3位是1,那麼’bob’在第3行等等。很容易看出這是非常緊湊和高效的存儲和檢索機制。

xxxx
*上面的圖片顯示了b +樹/位圖索引結構,而不是使用字典的MGIndex,但原理相同。

下面的例子顯示了實際的功能,您想要查詢以下的“Name =’bob’和Code = between(1,3)”,查詢處理器將採用過濾器,解析該過濾器的值並生成執行計劃如下:xxxx
從上圖可以看出,執行計劃是一系列BitArrays,您需要做的就是根據分析的過濾器和{AND,OR,NOT} BitArrays一起跟踪位算術邏輯。這些操作通常在亞毫秒範圍內,即使對於數百萬或數據庫中的行也是如此。結果是一個位置索引行查找到您從磁盤讀取的行內容,並發送給調用者,其中1表示讀取行,0表示跳過行內容(即100001 … – >讀取記錄號:1, 6,…)

 

 

WP Facebook Auto Publish Powered By : XYZScripts.com