1. 程式人生 > >.NetCore實踐篇:成功解決分散式監控ZipKin聚合依賴問題(三)

.NetCore實踐篇:成功解決分散式監控ZipKin聚合依賴問題(三)

前言

聚合呼叫span傳送到zipkin時,沒有產生聚合的span。

選單dependencies沒有聚合資料,zipkin-dependencies啟動失敗問題。

很慶幸,這兩個問題都在本篇文章得到完美解決。沒有什麼比一步一步解決問題更開心了,我又收集了一堆寶貴的連結。非常感謝社群,所以我也將自己的實踐之路分享出來,為.net社群繁榮增一點力氣。

zipkin複習

zipkin為分散式鏈路呼叫監控系統,聚合各業務系統呼叫延遲資料,達到鏈路呼叫監控跟蹤;zipkin通過採集跟蹤資料可以幫助開發者深入瞭解在分散式系統中某一個特定的請求時如何執行的;

zipkin4net複習

zipkin4net是.NET客戶端庫。

它為您提供:

  • Zipkin 原語(跨度,註釋,二進位制註釋,......)【Zipkin primitives (spans, annotations, binary annotations, ...)】
  • 非同步跟蹤傳送
  • 跟蹤傳輸抽象

zipkin-dependencies複習

這是一個Spark作業,它將從您的資料儲存區收集跨度,分析服務之間的連結,並存儲它們以供以後在Web UI中呈現(例如http://localhost:8080/dependency)。什麼是Spark?Apache Spark 是專為大規模資料處理而設計的快速通用的計算引擎。此作業以UTC時間分析當天的所有跟蹤。這意味著您應該將其安排在UTC午夜之前執行。支援所有Zipkin 

儲存元件,包括Cassandra,MySQL和Elasticsearch。

今日重點--成功啟動zipkin-dependencies

上次被zipkin-dependencies的啟動問題卡了很晚,就結束了那篇文章,今天繼續解決問題。我從網上搜到一篇類似的博文 部署生產環境時踩到的一些坑,裡面提到直接在tomcat的catalina.sh的JAVA_OPTS註釋處,加一行JAVA_OPTS="-server -Xms1024m -Xmx1624m -XX:PermSize=128M -XX:MaxPermSize=256m",即可解決。

#   JAVA_OPTS       (Optional) Java runtime options used when any command
# is executed. # Include here and not in CATALINA_OPTS all options, that # should be used by Tomcat and also by the stop process, # the version command etc. # Most options should go into CATALINA_OPTS. JAVA_OPTS="-server -Xms1024m -Xmx1624m -XX:PermSize=128M -XX:MaxPermSize=256m"

tomcat啟動成功。

[[email protected] bin]# ./startup.sh 
Using CATALINA_BASE:   /usr/local/tomcat/apache-tomcat-8.5.32
Using CATALINA_HOME:   /usr/local/tomcat/apache-tomcat-8.5.32
Using CATALINA_TMPDIR: /usr/local/tomcat/apache-tomcat-8.5.32/temp
Using JRE_HOME:        /usr/lib/jdk1.8.0_181
Using CLASSPATH:       /usr/local/tomcat/apache-tomcat-8.5.32/bin/bootstrap.jar:/usr/local/tomcat/apache-tomcat-8.5.32/bin/tomcat-juli.jar
Tomcat started.

後來又搜到這條連結how to increase heap size?原來直接在執行java命令時,追加-Xmx就行了,腦袋太死板,想不到這個點。

[[email protected] cusD]# java -Xmx1024m -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)

提示記憶體不足,分配失敗。

[[email protected] cusD]# STORAGE_TYPE=cassandra3  java -Xmx1024m -Xms1024m -jar zipkin-dependencies.jar `date -u -d '1 day ago' +%F`
Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000d5550000, 715849728, 0) failed; error='Cannot allocate memory' (errno=12)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 715849728 bytes for committing reserved memory.
# An error report file with more information is saved as:
# /cusD/hs_err_pid6871.log

解決步驟:

執行剛才的vi catalina.sh,清理掉設定的JAVA_OPTs資訊,關掉mysql,重啟tomcat等步驟。利用freetop檢視記憶體消耗。

[[email protected] cusD]# free -h
              total        used        free      shared  buff/cache   available
Mem:           1.8G        228M        1.2G        388K        396M        1.4G
Swap:            0B          0B          0B
[[email protected] cusD]# STORAGE_TYPE=cassandra3  java -Xmx512m -Xms128m -jar zipkin-dependencies.jar `date -u -d '1 day ago' +%F`
18/09/17 16:42:21 INFO CassandraDependenciesJob: Running Dependencies job for 2018-09-16: 1537056000000000 ≤ Span.timestamp 1537142399999999
18/09/17 16:42:21 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
18/09/17 16:42:22 WARN Java7Support: Unable to load JDK7 types (annotations, java.nio.file.Path): no Java7 support added
Exception in thread "main" java.io.IOException: Failed to open native connection to Cassandra at {127.0.0.1}:9042

未能載入JDK7 types,不過日誌級別為Warn,可以忽略。

啟動成功後,dependency依然沒有資料, 需要繼續查詢問題。

今日重點--深思流程解決span聚合問題

上次是由於啟動問題,今天解決了啟動問題,再看不到資料,就需要深思整個流程了。再讓我們回憶下下面這張圖,parentid為空,是不是意味著跨站點需要強指定parentid或站點名稱?

繼續翻看zipkin4Net示例程式碼,發現使用了IHttpClientFactoryCreateClient方法,又在ConfigureServices裡指定了applicationName,也許這才是能顯示出聚合站點的關鍵!
namespace frontend
{
    public class Startup : CommonStartup
    {
        public override void ConfigureServices(IServiceCollection services)
        {
            services.AddHttpClient("Tracer").AddHttpMessageHandler(provider =>
                TracingHandler.WithoutInnerHandler(provider.GetService<IConfiguration>()["applicationName"]));
        }

        protected override void Run(IApplicationBuilder app, IConfiguration config)
        {
            app.Run(async (context) =>
            {
                var callServiceUrl = config["callServiceUrl"];
                var clientFactory = app.ApplicationServices.GetService<IHttpClientFactory>();
                using (var httpClient = clientFactory.CreateClient("Tracer"))
                {
                    var response = await httpClient.GetAsync(callServiceUrl);
                    if (!response.IsSuccessStatusCode)
                    {
                        await context.Response.WriteAsync(response.ReasonPhrase);
                    }
                    else
                    {
                        var content = await response.Content.ReadAsStringAsync();
                        await context.Response.WriteAsync(content);
                    }
                }
            });
        }
    }
}

繼續按照示例程式碼,修改我們的邏輯,封裝一個可供其他站點呼叫的HTTPHelper幫助類,提供能追蹤站點的GetAsync方法,

namespace Demo.ZipkinCommon
{
    public class HTTPHelper : ControllerBase
    {
        /// <summary>
        /// 獲取
        /// </summary>
        /// <param name="url"></param>
        /// <param name="keyValues"></param>
        /// <param name="timeout"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static async Task<string> GetAsync(string url, Dictionary<string, string> keyValues, int timeout = 0, Encoding encoding = null)
        {
            if (encoding == null)
            {
                encoding = Encoding.UTF8;
            }
            var appName = ConfigureSettings.AppSettingConfig["applicationName"];

            using (var httpClient = new HttpClient(new TracingHandler(appName)))
            {
                var response = await httpClient.GetAsync(url);
                if (!response.IsSuccessStatusCode)
                {
                    return response.ReasonPhrase;
                }
                else
                {
                    var content = await response.Content.ReadAsStringAsync();
                    return content;
                }
            }
        }
    }
}

兩個站點的Add方法做出修正,然後檢視監控資料。

 [HttpPost]
        public IActionResult Add([FromBody]User user)
        {
            _userService.AddUser(user);

            //模擬呼叫其他站點請求。
            var url = $"{ConfigEx.WebSite}/user/get?id={user.Id}";
            var content = HTTPHelper.GetAsync(url, null);
            return Content(content.Result);
        }
監控spans有兩級了,達到了我們要的效果監控層級點開檢視效果站點聚合聚合效果圖

經測試,重啟linux後,不開啟zipkin-dependencies的情況下,記憶體模式下依然能實時聚合,上篇文章的結論是本人不熟悉所導致。

參考資料

原始碼

總結

基於記憶體模型的儲存,執行效果演示到此結束。在這個過程中,提升了我java一些知識,.NetCore依賴注入,加深了zipkin整體流程的理解。下篇檔案大體方向是zipkin資料持久化和叢集,以及zipkin如何跟蹤mongodb和Redis。

本篇到此結束,感謝觀看!