只有累積,沒有奇蹟

2022年12月28日 星期三

[APM] 提升應用程式效能的利器 Elastic APM : APM 解決什麼問題

前言
資深的開發者都知道程式開發完成後上線後是個重大的挑戰,隨著功能的迭代系統功能會變得更複雜,如何確保當程式錯誤時可以更快速的 debug 與找到異常的問題或出問題的服務 (Service)是個重要的議題,因此自己在可觀測性如何落地過程中 suvery 很多不同工具發現 Elastic APM 是符合需求的,另外也支援近期火紅的 OpenTelemetry 蒐集遙測數據的開源框架,接著會預計整理成相關系列文章。這邊是研究 Elastic APM 的系列文第一篇,這系列主要會分為三篇分別是
  • APM 解決什麼問題
  • .NET x Elastic APM
  • OpenTelemetry x Elastic APM 整合
若對於上述內容有問題或是不清楚的地方,歡迎提出來一起討論


真實世界的問題
如果自己公司產品或是系統在 PRODUCTION 環境壞掉會怎麼辦呢 ? 公司產品可能是電商系統,亦或者是演唱會在搶票或是 HR 產業上下班打卡的情境,這時候身為開發者或是資深工程師的你們,要如何找到可能的問題呢 ?
這時候我們可以問一下最近最夯的 chartGPT,身為一個不專業的工程師,請問線上網站壞掉了怎麼辦呢 ? chartGPT 的回答如下
這回答的重點是確認 Server 狀況、看 Log、尋找網站的維運人員來協助解決,但反過來說身為開發者的我們,當遇到緊急問題的時候要如何快速找到問題呢 ?
可能相對較完整的問題處理流程可能是如下圖所示
  • 透過監控與系統預警機制,設定水位與警報告知提醒有潛在的問題發生 (Metrics + Logging)
  • 當收到異常通知時,開啟監控 Dashboard 來釐清問題,使用常用的查詢與統計找到可能發生異常的模組 (Metrics)
  • 針對模組與相關程式碼 Log 查詢與分析其問題,找到異常的 Log 資訊 (Logging)
  • 定位可能的服務後,查詢其請求的鏈路追蹤定位問題代瑪 (Tracing)
可以發現在問題處理的流程中主要會透過 Metrics、Logging、Tracing 找到可能系統的異常問題,這也就是可觀測性一直以來提到的三個支柱觀念。在 2017 年時 Peter Bourgon 在 2017 Distributed Tracing Summit 後撰寫文章 Metrics, tracing, and logging,作者認為 Metrics 特徵是可以聚合的,Log 是處理離散的事件,Tracing 特徵是處理請求範圍的信息。三者在各自都有其功用與目的,如果缺少其中一項可能在對問題處理與時效上都會有些影響,並透過一張圖歸納三者的關聯與重疊部分,
如果對其有興趣想了解更多可以參考 連結,這裡不多加說明。


企業永續
上述處理問題的流程背後的目的想要解決的是企業永續經營(Business Continuity),企業永續經營是個目標聽起來很遙遠那要怎麼達到呢 ? 可以透過企業永續經營企劃(Business continuity planning)來達到其目的,針對 BCP WIKI 說明如下
Any event that could negatively impact operations should be included in the plan, such as supply chain interruption, loss of or damage to critical infrastructure (major machinery or computing/network resource). As such, BCP is a subset of risk management.
A Business Continuity Plan outlines a range of disaster scenarios and the steps the business will take in any particular scenario to return to regular trade. 
BCP's are written ahead of time and can also include precautions to be put in place.
這聽起來有點高大尚離我們很遙遠,就我自己的理解就是制定其計畫,計畫內容是當意外發生的時候企業可以針對關鍵的流程快速恢復服務,降低意外發生時後對企業營運的影響。可以分為四個流程
  • 識別企業關鍵流程與資源
  • 確認關鍵流程的影響
  • 定義解決方案
  • 方案進行演練
實作上可以思考 Backup、Disaster Recovery、High Availability 三個方向(包含但不限),以下就自己的理解做簡單的說明
  • Backup : 不管傳統的機房或是雲端,企業重要資料都是需要備份 不然遭遇到天災時 應用程式重新佈署可以使用 但資料無法復原會是很尷尬的問題
  • 災難備援 :要思考的是當災難發生時,要如何在最短的時間將網站快速恢復,網站佈署即恢復的流程怎麼進行、團隊分工分別是什麼、定期演練的規劃,當異常發生時接受噴掉多少資料及多久能恢復都是關鍵的問題與需要事前準備的。
  • High Availability : 為了要達到系統的高可用性,要如何做好監控機制、告警機制如何通知、處理人員及異常事件處理流程與 SOP 分別是甚麼,最後產品的 SLA、SLO與 SLI 要怎麼定義,這些都是重要的考量與因素。
其中 SLA、SLO、SLI 的部分是很重要的一個環節,SLA 是產品與客戶的協議合約,SLO 要達到 SLA 是我產品所制定的目標,SLI 要達到目標所定義的指標,要先有辦法衡量才可以進行其管理與改善,才有機會知道我們做完了某些決策之後,是不是有變好進行下一步的調整方向。SLA 內容可以參考 .NET MVP 安德魯大師之前在 .NET Conf 2020 的分享,裡面有清楚定義三者關係,影片連結 Andrew Wu - 非同步系統的服務水準保證;淺談非同步系統的 SLO 設計


APM
接著進入這篇的重點 APM,什麼是 APM 呢 ? 一般來說有兩種定義分別是 Application Performance Monitoring 與 Application Performance Management,前者是後者的集合。APM 的目的可以幫助開發團隊在應用程式遭遇到錯誤或是異常問題時,快速的將問題定問與修復,縮短其平均修復時間(MTTR),達到前面所提到的企業永續經營裡高可用性(HA)的目的。當然上述只是其中一個目的還可以幫助很多不同的面相,在 What is APM? Application performance monitoring guide 就有提到還可以解決以下問題
  • 整合 APM 到整個網絡監控和管理工具中
  • 確保應用程式 response 時間和用戶體驗
  • 增加應用程式的正常運行時間/減少中斷時間
  • 實施服務保障方法和服務水平均協議(SLA)
  • 蒐集應用程式效能與元件/底層資訊
重點是希望透過 APM 來提高開發人員對於系統的了解 (Observability) 與縮短 MTTR (Mean Time to revocer)。
在 CNCF Landscape 有針對可觀測性 Observability 列出滿滿的專案,大致上分為 Monitor、Logging、Tracing、Chaos Engineer 與 Continuous Optimization 等各式各樣的專案與工具,其中要推薦的 Elastic APM 就是在其中之一,關於其介紹會在下一篇在說明 :)


參考
Metrics, tracing, and logging
Andrew Wu - 非同步系統的服務水準保證;淺談非同步系統的 SLO 設計

2022年12月18日 星期日

[conference] .NET Conf 2022 - 再不使用 APM 就芭比Q 了

分享心得
今天很開心可以到 .NET Conf 2022 分享 APM 的主題,雖然主題是介紹 Elastic APM 但其實沒有太多工具的介紹,反而希望多跟大家分享像是工具背後是想要解決什麼問題(Business Continuity or High Availability ),為了達到 HA 有哪些重要指標 (Golden Signals、USE、RED) 可以參考及觀念,最後用《為什麼比怎麼做還重要》結束。 如果對於今天分享主題有想要了解更多或是不清楚的地方,歡迎一起討論與交流自己的想法, happy Coding


議程介紹
主題 : 再不使用 APM 就芭比Q 了
隨著科技與技術不斷的進步與創新,軟體架構從單體式(Monolithic)到 SOA(Service Oriented Architecture) 再到微服務(Micro Service),在應用程式服務顆粒度切分得更細的情況下,當系統發生問題時也隨著架構複雜度變高更難定位問題,有沒有更好的方案可以解決呢 ?
這個議程將會用淺顯易懂的方式,帶你一起探究下列議題
1. .NET 如何與 Elastic APM 整合
2. Elastic APM 內建的監控數據可以為團隊帶來哪些幫助
3. 如何與現代化遙測標準 OpenTelemetry 整合
透過 Elastic APM 快速了解問題的脈絡(Tracing),找到可能的系統效能瓶頸,讓發生線上問題時團隊可以更快速定位問題並止血,分享在這過程學習到的經驗以及小小心得。

主辦單位 : study4
議程表 : 連結
投影片 : 連結



2022年11月28日 星期一

[Benchmark] String 比較字串效能分析

前言
在 .NET 開發時很常會用到字串的比對,C# 中提供多種字串比對的方式,這篇文章就列出在 C# 提供的字串比方法,針對這幾種常用的方法使用  BenchmarkDotNet  做效能的測試及比對並會在 .NET Framework 與 .NET Core 分別測試結果,若有問題或是錯誤的地方歡迎各位給予指導及討論

測試代碼 
測試使用  BenchmarkDotNet  進行測試的動作,如果沒聽過此套件可以參考介紹的文章 [.NETCore] 使用 BenchmarkDotNet 測試程式碼效能,這次測試的項目是字串的比對方式效能差異,另外在 stringBenchmark 類別加上  ClrJob,CoreJob  希望分別在 .NET Framework 與 .NET Core 測試效能差異,代碼如下 
namespace benchmarkLab
{
    class Program
    {
        static void Main(string[] args)
        {
            var summary = BenchmarkRunner.Run<stringCompareBenchmark>();
            Console.ReadKey();
        }
    }

    [MemoryDiagnoser]
    [ClrJob,CoreJob]
    public class stringCompareBenchmark
    {
        public string string1 = "i am iron man";
        public string string2 = "I AM IRON MAN";

        // 測試代碼
    }
}
使用 Benchmark 測試數據,需要在方法上加上 Benchmark,使用 string 的比對測試的代碼如下
[Benchmark]
public void EqualityString()
{
    if (string1 == string2) ;
}
使用 string.Equals 的測試代碼如下
[Benchmark]
public void EqualString()
{
    if (string1.Equals(string2)) ;
}
使用 string.Compare 比對 string 的方式如下
[Benchmark]
public void CompareString()
{
    if (string.Compare(string1, string2) == 0) ;
}
使用 string.CompareOrdinal,測試的代碼如下
[Benchmark]
public void CompareOrdinalString()
{
    if (string.CompareOrdinal(string1, string2) == 0) ;
}
使用 string.compareTo,測試的代碼如下
[Benchmark]
public void CompareToString()
{
    if (string1.CompareTo(string2) == 0) ;
}
使用 string.Concat,測試的代碼如下
[Benchmark]
public void Concat()
{
    string s = string.Empty;
    s = string.Concat(firstWord, secondWord);
}
也可以使用 indexOf 方法找,因此也一併列出看看測試效能測試的代碼如下
[Benchmark]
public void IndexOfString()
{
    if (string1.IndexOf(string2) == 0) ;
}
接著調整到 Release mode,按下 F5 進行測試
測試完成後,會產生測試報各路徑在  release\BenchmarkDotNet.Artifacts\results  目錄底下,如下圖所示
根據測試結果
  • .NET Framework : 表現最差的為 IndexOf,表現最好的是 string.CompareOrdinal
  • .NET Core : 同樣表現最差的為 IndexOf,表現最好的是 string.CompareOrdinal

  • 感想
    透過結果得知,在 .NET Framework 與 .NET Core 環境中在字串比較上,效能最好的是 string.CompareOrdinal,== 與 string.Equals 緊追在後,IndexOf 則是在 .NET Framework 與 .NET Core 都墊底,另外在微軟 MSDN 在 .NET 中比較字串 文章中也有介紹常見的字串比對,有特別強調 CompareOrdinal 主要是用於排序或字串排序時。 不應該使用 String.CompareOrdinal 方法來測試是否相等
    得到最後的結論 compareOrdinal 雖然快,但 若要判斷兩個字串是否相等,請使用 String.Equals ,另外文章列出的 String.StartsWith、String.EndsWith 在本次比較中並未列出,原因是個人覺得在情境上與其他出發點不同,若是想了解更多各位客官也可自行測試看看,以上就是比較字串的結果,Happy Coding :)

    2022年11月15日 星期二

    [NETCore] 動態 String 字串相加效能比較

    前言
    在前一篇 [.NETCore] String 字串相加效能比較 對於 C# string 的應用做了一些測試,得到在使用固定字串相加時使用 string 效能反而比 stringBuilder 來的好,在 string  有多種應用情境因此這篇就在針對另一種使用情境針對 string 動態文字相加做比較若有問題或是錯誤的地方歡迎各位給予指導及討論

    測試代碼 
    測試方式同樣以  BenchmarkDotNet  套件協助進行測試,對此套件有興趣可以參考介紹的文章 [.NETCore] 使用 BenchmarkDotNet 測試程式碼效能,上一篇介紹是使用固定字串相加做測試,這一篇則是在每一個測試方法中跑一個 for 迴圈將結果相加起來,同樣的測試 C# 中 string、stringBuilder、string.Format、Interpolation、string.Concat、string.Join 等字串相加的方法,BenchmarkDotnet 使用上相當容易,直接透過 BenchmarkRunner.Run<T> 靜態方法將要測試的類別帶入 T 即可,測試 Framework 希望得知動態字串在 .NET Framework 與 .NET Core 效能表現,因此在測試類別上加上  ClrJob,CoreJob  ,除了速度之外對於 Memory 以及 GC 的使用量也是使用上要考量的重點之一,可以加上  MemoryDiagnoser  觀察記憶體與 GC 的數據,代碼如下 
    namespace benchmarkLab
    {
        class Program
        {
            static void Main(string[] args)
            {
                var summary = BenchmarkRunner.Run<stringTestBenchmark>();
                Console.ReadKey();
            }
        }
    
        [MemoryDiagnoser]
        [ClrJob,CoreJob]
        public class stringTestBenchmark
        {       
            StringBuilder _sb = new StringBuilder();
            // 測試代碼
        }
    }
    使用 Benchmark 測試數據需要在方法上加上   Benchmark  attribute,使用 string 的相加測試的代碼如下
    [Benchmark]
    public void Normal()
    {
        string s = string.Empty;
        for (int i = 0; i < 10; i++)
        {
            s += i.ToString();
        }
    }
    使用 stringBuilder 的相加測試的代碼如下
    [Benchmark]
    public void StringBuilder()
    {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 10; i++)
        {
            sb.Append(i.ToString());
        }
        string s = sb.ToString();
    }
    另外一種使用 stringBuilder 的方式,將其宣告為區域變數使用前先 clear (很少看到有人這樣使用,但想測試看看在此應用情境速度是否會提升),測試的代碼如下
    [Benchmark]
    public void StringBuilderClear()
    {
        _sb.Clear();
        for (int i = 0; i < 10; i++)
        {
            _sb.Append(i.ToString());
        }
        string s = _sb.ToString();
    }
    使用 string.Format,測試的代碼如下
    [Benchmark]
    public void Format()
    {
        string s = string.Empty;
        for (int i = 0; i < 10; i++)
        {
            s = string.Format("{0}{1}", s, i.ToString());
        }
    }
    使用 C# 6.0 提供的新語法 Interpolation,測試的代碼如下
    [Benchmark]
    public void Interpolation()
    {
        string s = string.Empty;
        for (int i = 0; i < 10; i++)
        {
            s = $"{s}{i.ToString()}";
        }
    }
    使用 string.Concat,測試的代碼如下
    [Benchmark]
    public void Concat()
    {
        string s = string.Empty;
        for (int i = 0; i < 10; i++)
        {
            s = string.Concat(s, i.ToString());
        }
    }
    使用 string.Join,測試的代碼如下
    [Benchmark]
    public void Join()
    {
        string s = string.Empty;
        for (int i = 0; i < 10; i++)
        {
            s += string.Join(s, i.ToString());
        }
    }
    好的,完成了測試代碼接著將專案設定為 Release mode,按下 F5 進行測試,可以看到執行 Console 一開始會說明 BenchmarkDotnet 將會進行 14 項任務 (2 Framework * 7 種方法) 的測試,測試時間會根據你要測試的項目多寡而不同,以本次測試來說在小弟電腦大約12-15 分鐘左右
    測試完成後,會產生測試報各路徑在  release\BenchmarkDotNet.Artifacts\results  目錄底下
    測試報告最上方為測試主機的硬體資訊,小弟筆電為 Intel Core i7-8550、16 G,Windows 10 環境,也會列出測試的 Framework 相關資訊,像是測試時是在 .NET Framework 4.7 與 .NET Core 2.2 進行測試,下方為在 string 中測試動態字串相加 的測試結果


  • .NET Framework : 就像大家所知的,動態字串相加表現最好的為 stringBuilder,在執行時間與使用記憶體用量數據都是優於其他方法;string.Format 則是最後一名
  • .NET Core : 與 .NET Framework 相同表現最好的為 stringBuilder,相同代碼在 .NET Core 執行速度提升一倍 (除了 string.Format ),速度上最慢的依舊為 string.Format,恭喜 string.Format 在各項測試蟬聯墊底

  • 感想
    多年前曾經拜讀過黑暗大文章 StringBuilder串接字串的迷思,因此進行測試前心理大致有個答案,從以上測試結果來看,stringBuilder 在動態字串相加時效能比 string 好同樣可套用到 .NET Core 上面,另外 string.Format 不管是在動態或是靜態字串相加效能都是墊底,但在可讀性上是比較好的 (大家比較習慣?),日後在 Code Review 時並依據當下情境做適合的應用,Happy Coding :)

    Copyright © m@rcus 學習筆記 | Powered by Blogger

    Design by Anders Noren | Blogger Theme by NewBloggerThemes.com