前言
讀本篇文章之前,可以先讀前兩篇文章。為了照顧沒(méi)看過(guò)的朋友,我也會(huì)稍作復(fù)習(xí)。
思考大綱: .Net架構(gòu)篇:思考如何設(shè)計(jì)一款實(shí)用的分布式監(jiān)控系統(tǒng)?
實(shí)踐篇一:.NetCore實(shí)踐篇:分布式監(jiān)控客戶(hù)端ZipkinTracer從入門(mén)到放棄之路
實(shí)踐篇二:.NetCore實(shí)踐篇:分布式監(jiān)控系統(tǒng)zipkin踩坑之路(二)
上一章節(jié),我們遺留了兩個(gè)問(wèn)題,
聚合調(diào)用span傳送到zipkin時(shí),沒(méi)有產(chǎn)生聚合的span。
菜單dependencies沒(méi)有聚合數(shù)據(jù),zipkin-dependencies啟動(dòng)失敗問(wèn)題。
很慶幸,這兩個(gè)問(wèn)題都在本篇文章得到完美解決。沒(méi)有什么比一步一步解決問(wèn)題更開(kāi)心了,我又收集了一堆寶貴的鏈接。非常感謝社區(qū),所以我也將自己的實(shí)踐之路分享出來(lái),為.net社區(qū)繁榮增一點(diǎn)力氣。
zipkin復(fù)習(xí)
zipkin為分布式鏈路調(diào)用監(jiān)控系統(tǒng),聚合各業(yè)務(wù)系統(tǒng)調(diào)用延遲數(shù)據(jù),達(dá)到鏈路調(diào)用監(jiān)控跟蹤;
zipkin通過(guò)采集跟蹤數(shù)據(jù)可以幫助開(kāi)發(fā)者深入了解在分布式系統(tǒng)中某一個(gè)特定的請(qǐng)求時(shí)如何執(zhí)行的;
詳情如下
zipkin參考
zipkin官網(wǎng)
zipkin4net復(fù)習(xí)
zipkin4net是.NET客戶(hù)端庫(kù)。
它為您提供:
- Zipkin 原語(yǔ)(跨度,注釋?zhuān)M(jìn)制注釋?zhuān)?.....)【Zipkin primitives (spans, annotations, binary annotations, ...)】
- 異步跟蹤發(fā)送
- 跟蹤傳輸抽象
詳情如下:
zipkin4net
zipkin-dependencies復(fù)習(xí)
這是一個(gè)Spark作業(yè),它將從您的數(shù)據(jù)存儲(chǔ)區(qū)收集跨度,分析服務(wù)之間的鏈接,并存儲(chǔ)它們以供以后在Web UI中呈現(xiàn)(例如http://localhost:8080/dependency)。
什么是Spark?
Apache Spark 是專(zhuān)為大規(guī)模數(shù)據(jù)處理而設(shè)計(jì)的快速通用的計(jì)算引擎。
此作業(yè)以UTC時(shí)間分析當(dāng)天的所有跟蹤。這意味著您應(yīng)該將其安排在UTC午夜之前運(yùn)行。
支持所有Zipkin 存儲(chǔ)組件,包括Cassandra,MySQL和Elasticsearch。
詳情如下:
zipkin-dependencies
今日重點(diǎn)--成功啟動(dòng)zipkin-dependencies
上次被zipkin-dependencies的啟動(dòng)問(wèn)題卡了很晚,就結(jié)束了那篇文章,今天繼續(xù)解決問(wèn)題。我從網(wǎng)上搜到一篇類(lèi)似的博文 部署生產(chǎn)環(huán)境時(shí)踩到的一些坑,里面提到直接在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啟動(dòng)成功。
[root@izwz9fwifc2eniq3lbdzmgz 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.
后來(lái)又搜到這條鏈接how to increase heap size?
原來(lái)直接在執(zhí)行java命令時(shí),追加-Xmx就行了,腦袋太死板,想不到這個(gè)點(diǎn)。
[root@izwz9fwifc2eniq3lbdzmgz 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)
提示內(nèi)存不足,分配失敗。
[root@izwz9fwifc2eniq3lbdzmgz 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
解決步驟:
執(zhí)行剛才的vi catalina.sh,清理掉設(shè)置的JAVA_OPTs信息,關(guān)掉mysql,重啟tomcat等步驟。利用free或top查看內(nèi)存消耗。
[root@izwz9fwifc2eniq3lbdzmgz cusD]# free -h
total used free shared buff/cache available
Mem: 1.8G 228M 1.2G 388K 396M 1.4G
Swap: 0B 0B 0B
[root@izwz9fwifc2eniq3lbdzmgz 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,不過(guò)日志級(jí)別為Warn,可以忽略。
啟動(dòng)成功后,dependency依然沒(méi)有數(shù)據(jù), 需要繼續(xù)查詢(xún)問(wèn)題。
今日重點(diǎn)--深思流程解決span聚合問(wèn)題
上次是由于啟動(dòng)問(wèn)題,今天解決了啟動(dòng)問(wèn)題,再看不到數(shù)據(jù),就需要深思整個(gè)流程了。
再讓我們回憶下下面這張圖,parentid為空,是不是意味著跨站點(diǎn)需要強(qiáng)指定parentid或站點(diǎn)名稱(chēng)?

繼續(xù)翻看zipkin4Net示例代碼,發(fā)現(xiàn)使用了IHttpClientFactory的CreateClient方法,又在ConfigureServices里指定了applicationName,也許這才是能顯示出聚合站點(diǎn)的關(guān)鍵!
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);
}
}
});
}
}
}
繼續(xù)按照示例代碼,修改我們的邏輯,封裝一個(gè)可供其他站點(diǎn)調(diào)用的HTTPHelper幫助類(lèi),提供能追蹤站點(diǎn)的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;
}
}
}
}
}
兩個(gè)站點(diǎn)的Add方法做出修正,然后查看監(jiān)控?cái)?shù)據(jù)。
[HttpPost]
public IActionResult Add([FromBody]User user)
{
_userService.AddUser(user);
//模擬調(diào)用其他站點(diǎn)請(qǐng)求。
var url = $"{ConfigEx.WebSite}/user/get?id={user.Id}";
var content = HTTPHelper.GetAsync(url, null);
return Content(content.Result);
}
監(jiān)控spans有兩級(jí)了,達(dá)到了我們要的效果



經(jīng)測(cè)試,重啟linux后,不開(kāi)啟zipkin-dependencies的情況下,內(nèi)存模式下依然能實(shí)時(shí)聚合,上篇文章的結(jié)論是本人不熟悉所導(dǎo)致。
參考資料
how to increase heap size?
部署生產(chǎn)環(huán)境時(shí)踩到的一些坑
Linux下如何同時(shí)注釋多行/同時(shí)取消多行注釋
利用Zipkin追蹤Mysql數(shù)據(jù)庫(kù)調(diào)用鏈
微服務(wù)調(diào)用鏈追蹤中心搭建
微服務(wù)監(jiān)控zipkin+asp.net core
Zipkin實(shí)踐:Python項(xiàng)目中跟蹤系統(tǒng)導(dǎo)入Zipkin
源碼
源碼已上傳范存威的github
總結(jié)
基于內(nèi)存模型的存儲(chǔ),執(zhí)行效果演示到此結(jié)束。在這個(gè)過(guò)程中,提升了我java一些知識(shí),.NetCore依賴(lài)注入,加深了zipkin整體流程的理解。
下篇文章大體方向是zipkin數(shù)據(jù)持久化和集群,以及zipkin如何跟蹤mongodb和Redis。
本篇到此結(jié)束,感謝觀看!