Net和Java基于zipkin的全鏈路追蹤

????在各大廠分布式鏈路跟蹤系統(tǒng)架構(gòu)對比中已經(jīng)介紹了幾大框架的對比,如果想用免費的可以用zipkin和pinpoint還有一個忘了介紹:SkyWalking伏嗜,具體介紹可參考:https://github.com/apache/incubator-skywalking/blob/master/README_ZH.md

  由于追蹤的要求是Net平臺和Java平臺都要支持坛悉,對于java平臺各組件都是天生的支持的,但對于net的支持找了些開源組件承绸,發(fā)現(xiàn)Pinpoint和SkyWalking給出的Demo都是基于NetCore(SkyWalking可以在github上搜skywalking-netcore裸影,Pinpoint沒有好的推薦),版本要求比較高军熏,但不可能更改現(xiàn)有平臺的FW框架轩猩,Zipkin有開源項目 Medidata.zipkinTracerModule 、zipkin.net、zipkin-csharp界轩,網(wǎng)上依次推薦是從前到后画饥,經(jīng)過測試發(fā)現(xiàn)Medidata.zipkinTracerModule、zipkin.net也是用于Net Core的浊猾,在NuGet上安裝報錯抖甘。最后測試zipkin-csharp(https://github.com/openzipkin-attic/zipkin-csharp)可以成功,在NuGet中搜索Zipkin.Core葫慎,現(xiàn)在版本也只有一個衔彻,如下:

然后查看給出的demo中代碼:zipkin-csharp/examples/ZipkinExample/Program.cs

using System;using System.Net;using System.Threading;using Zipkin;using Zipkin.Tracer.Kafka;namespace ZipkinExample

{

? ? class Program

? ? {

? ? ? ? staticvoidMain(string[] args)

? ? ? ? {

? ? ? ? ? ? varrandom =new Random();

? ? ? ? ? ? // make sure Zipkin with Scribe client is working

? ? ? ? ? ? //var collector = new HttpCollector(new Uri("http://localhost:9411/"));varcollector =new KafkaCollector(KafkaSettings.Default);

? ? ? ? ? ? vartraceId =newTraceHeader(traceId: (ulong)random.Next(), spanId: (ulong)random.Next());

? ? ? ? ? ? varspan =newSpan(traceId,newIPEndPoint(IPAddress.Loopback,9000),"test-service");

? ? ? ? ? ? span.Record(Annotations.ClientSend(DateTime.UtcNow));

? ? ? ? ? ? Thread.Sleep(100);

? ? ? ? ? ? span.Record(Annotations.ServerReceive(DateTime.UtcNow));

? ? ? ? ? ? Thread.Sleep(100);

? ? ? ? ? ? span.Record(Annotations.ServerSend(DateTime.UtcNow));

? ? ? ? ? ? Thread.Sleep(100);

? ? ? ? ? ? span.Record(Annotations.ClientReceive(DateTime.UtcNow));

? ? ? ? ? ? collector.CollectAsync(span).Wait();

? ? ? ? }

? ? }

}

可以看出這里的traceId和spanId都是隨機生成的,在這里推薦自己生成ID偷办,注意是ulong型艰额,這里毫秒數(shù)只格式化兩位(數(shù)據(jù)庫的位數(shù)20位,會超)椒涯,也可以用更保險的其它方法柄沮。

////// 獲得隨機數(shù)

? ? ? ? //////privatestaticulong getRandom()

? ? ? ? {

? ? ? ? ? ? varrandom =new Random();

? ? ? ? ? ? returnulong.Parse(DateTime.Now.ToString("yyyyMMddHHmmssff") + random.Next(100,999));

? ? ? ? }

? ? }

  collector這里使用Http來接收,注釋kafka的废岂,放開http的祖搓。去掉?collector.CollectAsync(span).Wait(); 中的Wait。

Zipkin的幾個基本概念

Span:基本工作單元湖苞,一次鏈路調(diào)用(可以是RPC拯欧,DB等沒有特定的限制)創(chuàng)建一個span,通過一個64位ID標識它财骨, span通過還有其他的數(shù)據(jù)镐作,例如描述信息,時間戳隆箩,key-value對的(Annotation)tag信息该贾,parent-id等,其中parent-id 可以表示span調(diào)用鏈路來源捌臊,通俗的理解span就是一次請求信息

Trace:類似于樹結(jié)構(gòu)的Span集合杨蛋,表示一條調(diào)用鏈路,存在唯一標識娃属,即TraceId

Annotation:注解,用來記錄請求特定事件相關(guān)信息(例如時間)护姆,通常包含四個注解信息

cs - Client Start矾端,表示客戶端發(fā)起請求

sr - Server Receive,表示服務(wù)端收到請求

ss - Server Send卵皂,表示服務(wù)端完成處理秩铆,并將結(jié)果發(fā)送給客戶端

cr - Client Received,表示客戶端獲取到服務(wù)端返回信息

BinaryAnnotation:提供一些額外信息,一般以key-value對出現(xiàn)


啟動服務(wù)端測試

下載 https://github.com/openzipkin/zipkin/releases 最近的穩(wěn)定版 release-2.7.1的jar包殴玛,這里采用mysql的型式保存記錄捅膘,因此需要創(chuàng)建數(shù)據(jù)庫zipkin,創(chuàng)建表:

SETFOREIGN_KEY_CHECKS=0;-- ------------------------------ Table structure for `zipkin_annotations`-- ----------------------------DROPTABLEIFEXISTS `zipkin_annotations`;CREATETABLE `zipkin_annotations` (

? `trace_id_high` bigint(20)NOTNULLDEFAULT'0'COMMENT'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',

? `trace_id` bigint(20)NOTNULLCOMMENT'coincides with zipkin_spans.trace_id',

? `span_id` bigint(20)NOTNULLCOMMENT'coincides with zipkin_spans.id',

? `a_key` varchar(255)NOTNULLCOMMENT'BinaryAnnotation.key or Annotation.value if type == -1',

? `a_value` blob COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB',

? `a_type` int(11)NOTNULLCOMMENT'BinaryAnnotation.type() or -1 if Annotation',

? `a_timestamp` bigint(20)DEFAULTNULLCOMMENT'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp',

? `endpoint_ipv4` int(11)DEFAULTNULLCOMMENT'Null when Binary/Annotation.endpoint is null',

? `endpoint_ipv6` binary(16)DEFAULTNULLCOMMENT'Null when Binary/Annotation.endpoint is null, or no IPv6 address',

? `endpoint_port` smallint(6)DEFAULTNULLCOMMENT'Null when Binary/Annotation.endpoint is null',

? `endpoint_service_name` varchar(255)DEFAULTNULLCOMMENT'Null when Binary/Annotation.endpoint is null',

? UNIQUEKEY`trace_id_high` (`trace_id_high`,`trace_id`,`span_id`,`a_key`,`a_timestamp`) COMMENT'Ignore insert on duplicate',

? UNIQUEKEY`trace_id_high_4` (`trace_id_high`,`trace_id`,`span_id`,`a_key`,`a_timestamp`) COMMENT'Ignore insert on duplicate',

? KEY`trace_id_high_2` (`trace_id_high`,`trace_id`,`span_id`) COMMENT'for joining with zipkin_spans',

? KEY`trace_id_high_3` (`trace_id_high`,`trace_id`) COMMENT'for getTraces/ByIds',

? KEY`endpoint_service_name` (`endpoint_service_name`) COMMENT'for getTraces and getServiceNames',

? KEY`a_type` (`a_type`) COMMENT'for getTraces',

? KEY`a_key` (`a_key`) COMMENT'for getTraces',

? KEY`trace_id` (`trace_id`,`span_id`,`a_key`) COMMENT'for dependencies job',

? KEY`trace_id_high_5` (`trace_id_high`,`trace_id`,`span_id`) COMMENT'for joining with zipkin_spans',

? KEY`trace_id_high_6` (`trace_id_high`,`trace_id`) COMMENT'for getTraces/ByIds',

? KEY`endpoint_service_name_2` (`endpoint_service_name`) COMMENT'for getTraces and getServiceNames',

? KEY`a_type_2` (`a_type`) COMMENT'for getTraces',

? KEY`a_key_2` (`a_key`) COMMENT'for getTraces',

? KEY`trace_id_2` (`trace_id`,`span_id`,`a_key`) COMMENT'for dependencies job') ENGINE=InnoDBDEFAULTCHARSET=utf8 ROW_FORMAT=COMPRESSED;-- ------------------------------ Records of zipkin_annotations-- ------------------------------ ------------------------------ Table structure for `zipkin_dependencies`-- ----------------------------DROPTABLEIFEXISTS `zipkin_dependencies`;CREATETABLE `zipkin_dependencies` (

? `day` dateNOTNULL,

? `parent` varchar(255)NOTNULL,

? `child` varchar(255)NOTNULL,

? `call_count` bigint(20)DEFAULTNULL,

? `error_count` bigint(20)DEFAULTNULL,

? UNIQUEKEY`day` (`day`,`parent`,`child`),

? UNIQUEKEY`day_2` (`day`,`parent`,`child`)

) ENGINE=InnoDBDEFAULTCHARSET=utf8 ROW_FORMAT=COMPRESSED;-- ------------------------------ Records of zipkin_dependencies-- ------------------------------ ------------------------------ Table structure for `zipkin_spans`-- ----------------------------DROPTABLEIFEXISTS `zipkin_spans`;CREATETABLE `zipkin_spans` (

? `trace_id_high` bigint(20)NOTNULLDEFAULT'0'COMMENT'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',

? `trace_id` bigint(20)NOTNULL,

? `id` bigint(20)NOTNULL,

? `name` varchar(255)NOTNULL,

? `parent_id` bigint(20)DEFAULTNULL,

? `debug` bit(1)DEFAULTNULL,

? `start_ts` bigint(20)DEFAULTNULLCOMMENT'Span.timestamp(): epoch micros used for endTs query and to implement TTL',

? `duration` bigint(20)DEFAULTNULLCOMMENT'Span.duration(): micros used for minDuration and maxDuration query',

? UNIQUEKEY`trace_id_high` (`trace_id_high`,`trace_id`,`id`) COMMENT'ignore insert on duplicate',

? UNIQUEKEY`trace_id_high_4` (`trace_id_high`,`trace_id`,`id`) COMMENT'ignore insert on duplicate',

? KEY`trace_id_high_2` (`trace_id_high`,`trace_id`,`id`) COMMENT'for joining with zipkin_annotations',

? KEY`trace_id_high_3` (`trace_id_high`,`trace_id`) COMMENT'for getTracesByIds',

? KEY`name` (`name`) COMMENT'for getTraces and getSpanNames',

? KEY`start_ts` (`start_ts`) COMMENT'for getTraces ordering and range',

? KEY`trace_id_high_5` (`trace_id_high`,`trace_id`,`id`) COMMENT'for joining with zipkin_annotations',

? KEY`trace_id_high_6` (`trace_id_high`,`trace_id`) COMMENT'for getTracesByIds',

? KEY`name_2` (`name`) COMMENT'for getTraces and getSpanNames',

? KEY`start_ts_2` (`start_ts`) COMMENT'for getTraces ordering and range') ENGINE=InnoDBDEFAULTCHARSET=utf8 ROW_FORMAT=COMPRESSED;-- ------------------------------ Records of zipkin_spans-- ----------------------------

啟動

進入程序的當前目錄啟動滚粟,注意參數(shù)內(nèi)容寻仗,如果想要保存到elasticsearch,需要按官方文檔更改凡壤。

java -jar zipkin-server-2.7.1.jar --STORAGE_TYPE=mysql --MYSQL_DB=zipkin --MYSQL_USER=root --MYSQL_PASS=123456--MYSQL_HOST=localhost --MYSQL_TCP_PORT=3306

啟動后看到如下內(nèi)容表明成功署尤。

啟動成功后瀏覽器訪問?http://localhost:9411/

  至此服務(wù)端和展示頁面已經(jīng)啟動,不過功能還是很簡單的亚侠,具體的使用可另行查詢資料曹体。

?  這里用來測試的服務(wù)采用網(wǎng)友提供的 源碼:mircoservice分布式跟蹤系統(tǒng)(zipkin+springboot)?https://github.com/dreamerkr/mircoservice,文章可參考:微服務(wù)之分布式跟蹤系統(tǒng)(springboot+zipkin)https://blog.csdn.net/qq_21387171/article/details/53787019

用默認配置分別運行4個客戶端服務(wù)后運行效果:

(1)分別啟動每個服務(wù)硝烂,然后訪問服務(wù)1箕别,瀏覽器訪問(http://localhost:8081/service1/test

(2)輸入zipkin地址,每次trace的列表

?點擊其中的trace滞谢,可以看trace的樹形結(jié)構(gòu)串稀,包括每個服務(wù)所消耗的時間:

?點擊每個span可以獲取延遲信息:

?同時可以查看服務(wù)之間的依賴關(guān)系:

測試Net平臺程序

將demo代碼改為:

staticvoidMain(string[] args)

? ? ? ? {

? ? ? ? ? ? varrandom =new Random();

? ? ? ? ? ? // make sure Zipkin with Scribe client is workingvarcollector =newHttpCollector(newUri("http://localhost:9411/"));

? ? ? ? ? ? //var collector = new KafkaCollector(KafkaSettings.Default);vartraceId =newTraceHeader(traceId: (ulong)random.Next(), spanId: (ulong)random.Next());

? ? ? ? ? ? varspan =newSpan(traceId,newIPEndPoint(IPAddress.Loopback,9000),"zipkinweb");

? ? ? ? ? ? span.Record(Annotations.ClientSend(DateTime.UtcNow));

? ? ? ? ? ? Thread.Sleep(100);

? ? ? ? ? ? span.Record(Annotations.ServerReceive(DateTime.UtcNow));

? ? ? ? ? ? Thread.Sleep(100);

? ? ? ? ? ? span.Record(Annotations.ServerSend(DateTime.UtcNow));

? ? ? ? ? ? Thread.Sleep(100);

? ? ? ? ? ? span.Record(Annotations.ClientReceive(DateTime.UtcNow));

? ? ? ? ? ? collector.CollectAsync(span);

? ? ? ? }

然后運行一次再查看,會多出一條信息

點進去會看到請求的詳細信息和備注信息:

右上角查看json

  驗證了NET平臺下是可以成功調(diào)用的爹凹,而且可以看到zipkin服務(wù)前端展示是通過api請求的厨诸,前后臺分開的,因此我們可以以此來做二次開發(fā)禾酱,我們知道了數(shù)據(jù)結(jié)構(gòu)或者通過自己請求數(shù)據(jù)庫內(nèi)容做更復(fù)雜的業(yè)務(wù)前端微酬。

  這里強調(diào)一點的是net最好用framework4.5以上的版本,由net的demo來看其實封裝性不高颤陶,所以靈活性能很高颗管,需要自己進一步封裝才能達到代碼的侵入性更少,性能更高滓走。后面考慮到性能和數(shù)據(jù)量可改用kafka接收和ES保存數(shù)據(jù)垦江。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市搅方,隨后出現(xiàn)的幾起案子比吭,更是在濱河造成了極大的恐慌,老刑警劉巖姨涡,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衩藤,死亡現(xiàn)場離奇詭異,居然都是意外死亡涛漂,警方通過查閱死者的電腦和手機赏表,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門检诗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人瓢剿,你說我怎么就攤上這事逢慌。” “怎么了间狂?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵攻泼,是天一觀的道長。 經(jīng)常有香客問我前标,道長坠韩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任炼列,我火速辦了婚禮只搁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘俭尖。我一直安慰自己氢惋,他們只是感情好,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布稽犁。 她就那樣靜靜地躺著焰望,像睡著了一般。 火紅的嫁衣襯著肌膚如雪已亥。 梳的紋絲不亂的頭發(fā)上熊赖,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音虑椎,去河邊找鬼震鹉。 笑死,一個胖子當著我的面吹牛捆姜,可吹牛的內(nèi)容都是我干的传趾。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼泥技,長吁一口氣:“原來是場噩夢啊……” “哼浆兰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起珊豹,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤簸呈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后店茶,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜕便,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年忽妒,在試婚紗的時候發(fā)現(xiàn)自己被綠了玩裙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡段直,死狀恐怖吃溅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鸯檬,我是刑警寧澤决侈,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站喧务,受9級特大地震影響赖歌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜功茴,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一庐冯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧坎穿,春花似錦展父、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至孵延,卻和暖如春吕漂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背尘应。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工惶凝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人菩收。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓梨睁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親娜饵。 傳聞我的和親對象是個殘疾皇子坡贺,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容