国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

ASP.NET Core整合Zipkin鏈路跟蹤的實(shí)現方法

發(fā)布時(shí)間:2021-08-17 12:10 來(lái)源: 閱讀:0 作者:yi念之間 欄目: ASP 歡迎投稿:712375056

前言

    在日常使用ASP.NET Core的開(kāi)發(fā)或學(xué)習中,如果有需要使用鏈路跟蹤系統,大多數情況下會(huì )優(yōu)先選擇SkyAPM。我們之前也說(shuō)過(guò)SkyAPM設計確實(shí)比較優(yōu)秀,巧妙的利用DiagnosticSource診斷跟蹤日志,可以做到對項目無(wú)入侵方式的集成。其實(shí)還有一款比較優(yōu)秀的鏈路跟蹤系統,也可以支持ASP.NET Core,叫Zipkin。它相對于SkyWalking來(lái)說(shuō)相對輕量級,使用相對來(lái)說(shuō)比較偏原生的方式,而且支持Http的形式查詢(xún)和提交鏈路數據。因為我們總是希望能擁有多一種的解決方案方便對比和參考,所以接下來(lái)我們就來(lái)學(xué)習一下關(guān)于Zipkin的使用方式。

Zipkin簡(jiǎn)介

    Zipkin是由Twitter開(kāi)源的一款基于Java語(yǔ)言開(kāi)發(fā)的分布式實(shí)時(shí)數據追蹤系統(Distributed Tracking System),其主要功能是采集來(lái)自各個(gè)系統的實(shí)時(shí)監控數據。該系統讓開(kāi)發(fā)者可通過(guò)一個(gè) Web 前端輕松的收集和分析數據,例如用戶(hù)每次請求服務(wù)的處理時(shí)間等,可方便的監測系統中存在的瓶頸。它大致可以分為三個(gè)核心概念

  • 首先是上報端,它主要通過(guò)代碼的形式集成到程序中,用于上報Trace數據到Collector端。
  • Collector負責接收客戶(hù)端發(fā)送過(guò)來(lái)的數據,保存到內存或外部存儲系統中,供UI展示。
  • 存儲端可以是基于zipkin內存完全不依賴(lài)外部存儲的In-Memory形式或依賴(lài)外部存儲系統的形式,一般采用外部存儲系統存儲鏈路數據,畢竟內存有限。它可支持的存儲數據庫有MySQL、Cassandra、Elasticsearch。
  • UI負責展示采集的鏈路數據,及系統之間的依賴(lài)關(guān)系。

相對來(lái)說(shuō)還是比較清晰的,如果用一張圖表示整體架構的話(huà),大致如下圖所示(圖片來(lái)源于網(wǎng)絡(luò ))

在學(xué)習鏈路跟蹤的過(guò)程中會(huì )設計到相關(guān)概念,我們接下來(lái)介紹鏈路跟蹤幾個(gè)相關(guān)的概念

  • TranceId,一般一次全局的請求會(huì )有一個(gè)唯一的TraceId,用于代表一次唯一的請求。比如我請求了訂單管理系統,而訂單管理系統內部還調用了商品管理系統,而商品管理系統還調用了緩存系統或數據庫系統。但是對全局或外部來(lái)說(shuō)這是一次請求,所以會(huì )有唯一的一個(gè)TraceId。
  • SpanId,雖然全局的來(lái)說(shuō)是一次大的請求,但是在這個(gè)鏈路中內部間還會(huì )發(fā)起別的請求,這種內部間的每次請求會(huì )生成一個(gè)SpanId。
  • 如果將整條鏈路串聯(lián)起來(lái)的話(huà),我們需要記錄全局的TraceId,代表當前節點(diǎn)的SpanId和發(fā)起對當前節點(diǎn)調用的的父級ParentId。
  • 然后基于鏈路跟蹤的核心概念,然后介紹一下Zipkin衍生出來(lái)了幾個(gè)相關(guān)概念
  • cs:Clent Sent 客戶(hù)端發(fā)起請求的時(shí)間,比如 dubbo 調用端開(kāi)始執行遠程調用之前。
  • cr:Client Receive 客戶(hù)端收到處理完請求的時(shí)間。
  • ss:Server Receive 服務(wù)端處理完邏輯的時(shí)間。

sr - cs = 請求在網(wǎng)絡(luò )上的耗時(shí)
ss - sr = 服務(wù)端處理請求的耗時(shí)
cr - ss = 回應在網(wǎng)絡(luò )上的耗時(shí)
cr - cs = 一次調用的整體耗時(shí)

關(guān)于zipkin概念相關(guān)的就介紹這么多,接下來(lái)我們介紹如何部署Zipkin。

部署ZipKin

    關(guān)于Zipkin常用的部署方式大概有兩種,一種是通過(guò)下載安裝JDK,然后運行zipkin.jar的方式,另一種是基于Docker的方式。為了方便我采用的是基于Docker的方式部署,因為采用原生的方式去部署還需要安裝JDK,而且操作相對比較麻煩。咱們上面說(shuō)過(guò),雖然Zipkin可以將鏈路數據存放到內存中,但是這種操作方式并不實(shí)用,實(shí)際使用過(guò)程中多采用ElasticSearch存儲鏈路數據。所以部署的時(shí)候需要依賴(lài)Zipkin和ElasticSearch,對于這種部署形式采用docker-compose的方式就再合適不過(guò)了,大家可以在Zipkin官方Github中找到docker的部署方式,地址是,官方使用的方式相對比較復雜,下載下來(lái)docker-compose相關(guān)文件之后我簡(jiǎn)化了它的使用方式,最終修改如下

version: "3.6"
services:
 elasticsearch:
 # 我使用的是7.5.0版本
 image: elasticsearch:7.5.0
 container_name: elasticsearch
 restart: always
 #暴露es端口
 ports:
 - 9200:9200
 environment:
 - discovery.type=single-node
 - bootstrap.memory_lock=true
 #es有內存要求
 - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
 ulimits:
 memlock:
 soft: -1
 hard: -1
 networks:
 default:
 aliases:
 - elasticsearch

 zipkin:
 image: openzipkin/zipkin
 container_name: zipkin
 restart: always
 networks:
 default:
 aliases:
 - zipkin
 environment:
 #存儲類(lèi)型為es
 - STORAGE_TYPE=elasticsearch
 #es地址
 - ES_HOSTS=elasticsearch:9200
 ports:
 - 9411:9411
 #依賴(lài)es所以在es啟動(dòng)完成后在啟動(dòng)zipkin
 depends_on:
 - elasticsearch

通過(guò)docker-compose運行編輯后的yaml文件,一條指令就可以運行起來(lái)

<PackageReference Include="zipkin4net" Version="1.5.0" />
<PackageReference Include="zipkin4net.middleware.aspnetcore" Version="1.5.0" />

其中-f是指定文件名稱(chēng),如果是docker-compose.yml則可以直接忽略文件名稱(chēng),當shell中出現如下界面

并且在瀏覽器中輸入出現如圖所示,則說(shuō)明Zikpin啟動(dòng)成功

整合ASP.NET Core

ZipKin啟動(dòng)成功之后,我們就可以將程序中的數據采集到Zipkin中去了,我新建了兩個(gè)ASP.NET Core的程序,一個(gè)是OrderApi,另一個(gè)是ProductApi方便能體現出調用鏈路,其中OrderApi調用ProductApi接口,在兩個(gè)項目中分別引入Zipkin依賴(lài)包

<PackageReference Include="zipkin4net" Version="1.5.0" />
<PackageReference Include="zipkin4net.middleware.aspnetcore" Version="1.5.0" />

其中zipkin4net為核心包,zipkin4net.middleware.aspnetcore是集成ASP.NET Core的程序包。然后我們在Startup文件中添加如下方法

public void RegisterZipkinTrace(IApplicationBuilder app, ILoggerFactory loggerFactory, IHostApplicationLifetime lifetime)
{
 lifetime.ApplicationStarted.Register(() =>
 {
 //記錄數據密度,1.0代表全部記錄
 TraceManager.SamplingRate = 1.0f;
 //鏈路日志
 var logger = new TracingLogger(loggerFactory, "zipkin4net");
 //zipkin服務(wù)地址和內容類(lèi)型
 var httpSender = new HttpZipkinSender("http://localhost:9411/", "application/json");
 var tracer = new ZipkinTracer(httpSender, new JSONSpanSerializer(), new Statistics());
 var consoleTracer = new zipkin4net.Tracers.ConsoleTracer();

 TraceManager.RegisterTracer(tracer);
 TraceManager.RegisterTracer(consoleTracer);
 TraceManager.Start(logger);

 });
 //程序停止時(shí)停止鏈路跟蹤
 lifetime.ApplicationStopped.Register(() => TraceManager.Stop());
 //引入zipkin中間件,用于跟蹤服務(wù)請求,這邊的名字可自定義代表當前服務(wù)名稱(chēng)
 app.UseTracing(Configuration["nacos:ServiceName"]);
}

然后我們在Configure方法中調用RegisterZipkinTrace方法即可。由于我們要在OrderApi項目中采用HttpClient的方式調用ProductAPI,默認zipkin4net是支持采集HttpClient發(fā)出請求的鏈路數據(由于在ProductApi中我們并不發(fā)送Http請求,所以可以不用集成一下操作),具體集成形式如下,如果使用的是HttpClientFactory的方式,在ConfigureServices中配置如下

public void ConfigureServices(IServiceCollection services)
{
 //由于我使用了Nacos作為服務(wù)注冊中心
 services.AddNacosAspNetCore(Configuration);
 services.AddScoped<NacosDiscoveryDelegatingHandler>();
 services.AddHttpClient(ServiceName.ProductService,client=> {
 client.BaseAddress = new Uri($"http://{ServiceName.ProductService}");
 })
 .AddHttpMessageHandler<NacosDiscoveryDelegatingHandler>()
 //引入zipkin trace跟蹤httpclient請求,名稱(chēng)配置當前服務(wù)名稱(chēng)即可
 .AddHttpMessageHandler(provider =>TracingHandler.WithoutInnerHandler(Configuration["nacos:ServiceName"]));
 services.AddControllers();
}

如果是直接是使用HttpClient的形式調用則可以采用以下方式

using (HttpClient client = new HttpClient(new TracingHandler("OrderApi")))
{
}

然后我們在OrderApi中寫(xiě)一段調用ProductApi的代碼

[Route("orderapi/[controller]")]
public class OrderController : ControllerBase
{
 private List<OrderDto> orderDtos = new List<OrderDto>();
 private readonly IHttpClientFactory _clientFactory;

 public OrderController(IHttpClientFactory clientFactory)
 {
 orderDtos.Add(new OrderDto { Id = 1, TotalMoney=222,Address="北京市",Addressee="me",From="淘寶",SendAddress="武漢" });
 _clientFactory = clientFactory;
 }

 /// <summary>
 /// 獲取訂單詳情接口
 /// </summary>
 /// <param name="id">訂單id</param>
 /// <returns></returns>
 [HttpGet("getdetails/{id}")]
 public async Task<OrderDto> GetOrderDetailsAsync(long id)
 {
 OrderDto orderDto = orderDtos.FirstOrDefault(i => i.Id == id);
 if (orderDto != null)
 {
 OrderDetailDto orderDetailDto = new OrderDetailDto
 {
 Id = orderDto.Id,
 TotalMoney = orderDto.TotalMoney,
 Address = orderDto.Address,
 Addressee = orderDto.Addressee,
 From = orderDto.From,
 SendAddress = orderDto.SendAddress
 };
 //調用ProductApi服務(wù)接口
 var client = _clientFactory.CreateClient(ServiceName.ProductService);
 var response = await client.GetAsync($"/productapi/product/getall");
 var result = await response.Content.ReadAsStringAsync();

 orderDetailDto.Products = JsonConvert.DeserializeObject<List<OrderProductDto>>(result);
 return orderDetailDto;
 }
 return orderDto;
 }
}

在ProductApi中我們只需要編寫(xiě)調用RegisterZipkinTrace方法即可,和OrderApi一樣,我們就不重復粘貼了。因為ProductApi不需要調用別的服務(wù),所以可以不必使用集成HttpClient,只需要提供簡(jiǎn)單的接口即可

[Route("productapi/[controller]")]
public class ProductController : ControllerBase
{
 private List<ProductDto> productDtos = new List<ProductDto>();
 public ProductController()
 {
 productDtos.Add(new ProductDto { Id = 1,Name="酒精",Price=22.5m });
 productDtos.Add(new ProductDto { Id = 2, Name = "84消毒液", Price = 19.9m });
 }

 /// <summary>
 /// 獲取所有商品信息
 /// </summary>
 /// <returns></returns>
 [HttpGet("getall")]
 public IEnumerable<ProductDto> GetAll()
 {
 return productDtos;
 }
}

啟動(dòng)這兩個(gè)項目,調用OrderApi的getdetails接口,完成后打開(kāi)zipkin界面點(diǎn)擊進(jìn)去可查看鏈路詳情
總結起來(lái)核心操作其實(shí)就兩個(gè),一個(gè)是在發(fā)送請求的地方,使用TracingHandler記錄發(fā)起端的鏈路情況,然后在接收請求的服務(wù)端使用UseTracing記錄來(lái)自于客戶(hù)端請求的鏈路情況。

改進(jìn)集成方式

    其實(shí)在上面的演示中,我們可以明顯的看到明顯的不足,就是很多時(shí)候其實(shí)我們沒(méi)辦法去設置HttpClient相關(guān)的參數的,很多框架雖然也是使用的HttpClient或HttpClientFactory相關(guān),但是在外部我們沒(méi)辦法通過(guò)自定義的方式去設置他們的相關(guān)操作,比如Ocelot其實(shí)也是使用HttpClient相關(guān)發(fā)起的轉發(fā)請求,但是對外我們沒(méi)辦法通過(guò)我們的程序去設置HttpClient的參數。還有就是在.Net Core中WebRequest其實(shí)也是對HttpClient的封裝,但是我們同樣沒(méi)辦法在我們的程序中給他們傳遞類(lèi)似TracingHandler的操作?,F在我們從TracingHandler源碼開(kāi)始解讀看看它的內部到底是如何工作的,zipkin官方提供的.net core插件zipkin4net的源碼位于
,我們找到TracingHandler類(lèi)所在的位置[],由于TracingHandler本身就是DelegatingHandler的子類(lèi),所以我們主要看SendAsync方法,大致抽離出來(lái)如下

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
 Func<HttpRequestMessage, string> _getClientTraceRpc = _getClientTraceRpc = getClientTraceRpc ?? (request => request.Method.ToString());
 IInjector<HttpHeaders> _injector = Propagations.B3String.Injector<HttpHeaders>((carrier, key, value) => carrier.Add(key, value));
 //記錄發(fā)起請求客戶(hù)端鏈路信息的類(lèi)是ClientTrace
 using (var clientTrace = new ClientTrace(_serviceName, _getClientTraceRpc(request)))
 {
 if (clientTrace.Trace != null)
 {
 _injector.Inject(clientTrace.Trace.CurrentSpan, request.Headers);
 }

 var result = await clientTrace.TracedActionAsync(base.SendAsync(request, cancellationToken));
 //AddAnnotation是記錄標簽信息,我們可以在zipkin鏈路詳情中看到這些標簽
 if (clientTrace.Trace != null)
 {
 //記錄請求路徑
 clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_PATH, result.RequestMessage.RequestUri.LocalPath));
 //記錄請求的http方法
 clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_METHOD, result.RequestMessage.Method.Method));
 if (_logHttpHost)
 {
 //記錄主機
 clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_HOST, result.RequestMessage.RequestUri.Host));
 }
 if (!result.IsSuccessStatusCode)
 {
 clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_STATUS_CODE, ((int)result.StatusCode).ToString()));
 }
 }
 return result;
 }
}

實(shí)現方式比較簡(jiǎn)單,就是借助ClientTrace記錄一些標簽,其他的相關(guān)操作都是由zipkin4net提供的。我們在之前的文章中層說(shuō)道HttpClient底層會(huì )有發(fā)出診斷日志,我們可以借助這個(gè)思路,來(lái)對HttpClient進(jìn)行鏈路跟蹤埋點(diǎn)。
我們結合Microsoft.Extensions.DiagnosticAdapter擴展包定義如下類(lèi)

public class HttpDiagnosticListener: ITraceDiagnosticListener
{
 public string DiagnosticName => "HttpHandlerDiagnosticListener";

 private ClientTrace clientTrace;
 private readonly IInjector<HttpHeaders> _injector = Propagations.B3String.Injector<HttpHeaders>((carrier, key, value) => carrier.Add(key, value));

 [DiagnosticName("System.Net.Http.Request")]
 public void HttpRequest(HttpRequestMessage request)
 {
 clientTrace = new ClientTrace("apigateway", request.Method.Method);
 if (clientTrace.Trace != null)
 {
 _injector.Inject(clientTrace.Trace.CurrentSpan, request.Headers);
 }
 }

 [DiagnosticName("System.Net.Http.Response")]
 public void HttpResponse(HttpResponseMessage response)
 {
 if (clientTrace.Trace != null)
 {
 clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_PATH, response.RequestMessage.RequestUri.LocalPath));
 clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_METHOD, response.RequestMessage.Method.Method));
 clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_HOST, response.RequestMessage.RequestUri.Host));
 if (!response.IsSuccessStatusCode)
 {
 clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_STATUS_CODE, ((int)response.StatusCode).ToString()));
 }
 }
 }

 [DiagnosticName("System.Net.Http.Exception")]
 public void HttpException(HttpRequestMessage request,Exception exception)
 {
 }
}

ITraceDiagnosticListener是我們方便操作DiagnosticListener定義的接口,接口僅包含DiagnosticName用來(lái)表示DiagnosticListener監聽(tīng)的名稱(chēng),有了這個(gè)接口接下來(lái)的操作我們會(huì )方便許多,接下來(lái)我們來(lái)看訂閱操作的實(shí)現。

public class TraceObserver :IObserver<DiagnosticListener>
{
 private IEnumerable<ITraceDiagnosticListener> _traceDiagnostics;
 public TraceObserver(IEnumerable<ITraceDiagnosticListener> traceDiagnostics)
 {
 _traceDiagnostics = traceDiagnostics;
 }

 public void OnCompleted()
 {
 }

 public void OnError(Exception error)
 {
 }

 public void OnNext(DiagnosticListener listener)
 {
 //這樣的話(huà)我們可以更輕松的擴展其他DiagnosticListener的操作
 var traceDiagnostic = _traceDiagnostics.FirstOrDefault(i=>i.DiagnosticName==listener.Name);
 if (traceDiagnostic!=null)
 {
 //適配訂閱
 listener.SubscribeWithAdapter(traceDiagnostic);
 }
 }
}

通過(guò)這種操作我們就無(wú)需關(guān)心如何將自定義的DiagnosticListener訂閱類(lèi)適配到DiagnosticAdapter中去,方便我們自定義其他DiagnosticListener的訂閱類(lèi),這樣的話(huà)我們只需注冊自定義的訂閱類(lèi)即可。

services.AddSingleton<TraceObserver>();
services.AddSingleton<ITraceDiagnosticListener, HttpDiagnosticListener>();

通過(guò)這種改進(jìn)方式,我們可以解決類(lèi)似HttpClient封裝到框架中,并且我們我們無(wú)法通過(guò)外部程序去修改設置的時(shí)候。比如我們在架構中引入了Ocelot網(wǎng)關(guān),我們就可以采用類(lèi)似這種方式,在網(wǎng)關(guān)層集成zipkin4net。

自定義埋點(diǎn)

    通過(guò)上面我們查看TracingHandler的源碼我們得知埋點(diǎn)主要是通過(guò)ClientTrace進(jìn)行的,它是在發(fā)起請求的客戶(hù)端進(jìn)行埋點(diǎn)。在服務(wù)端埋點(diǎn)的方式我們可以通過(guò)TracingMiddleware中間件中的源碼查看到[]叫ServerTrace。有了ClientTrace和ServerTrace我們可以非常輕松的實(shí)現一次完整的客戶(hù)端和服務(wù)端埋點(diǎn),只需要通過(guò)它們打上一些標簽即可。其實(shí)它們都是對Trace類(lèi)的封裝,我們找到它們的源碼進(jìn)行查看

public class ClientTrace : BaseStandardTrace, IDisposable
{
 public ClientTrace(string serviceName, string rpc)
 {
 if (Trace.Current != null)
 {
 Trace = Trace.Current.Child();
 }

 Trace.Record(Annotations.ClientSend());
 Trace.Record(Annotations.ServiceName(serviceName));
 Trace.Record(Annotations.Rpc(rpc));
 }

 public void Dispose()
 {
 Trace.Record(Annotations.ClientRecv());
 }
}

public class ServerTrace : BaseStandardTrace, IDisposable
{
 public override Trace Trace
 {
 get
 {
 return Trace.Current;
 }
 }

 public ServerTrace(string serviceName, string rpc)
 {
 Trace.Record(Annotations.ServerRecv());
 Trace.Record(Annotations.ServiceName(serviceName));
 Trace.Record(Annotations.Rpc(rpc));
 }

 public void Dispose()
 {
 Trace.Record(Annotations.ServerSend());
 }
}

因此,如果你想通過(guò)更原始的方式去記錄跟蹤日志可以采用如下方式

var trace = Trace.Create();
trace.Record(Annotations.ServerRecv());
trace.Record(Annotations.ServiceName(serviceName));
trace.Record(Annotations.Rpc("GET"));
trace.Record(Annotations.ServerSend());
trace.Record(Annotations.Tag("http.url", "<url>"));

示例Demo

由于上面說(shuō)的比較多,而且有一部分關(guān)于源碼的解讀,為了防止由本人文筆有限,給大家帶來(lái)理解誤區,另一方面也為了更清晰的展示Zipkin的集成方式,我自己做了一套Demo,目錄結構如下
ApiGateway為網(wǎng)關(guān)項目可以轉發(fā)針對OrderApi的請求,OrderApi和ProductApi用于模擬業(yè)務(wù)系統,這三個(gè)項目都集成了zipkin4net鏈路跟蹤,他們之間是通過(guò)Nacos實(shí)現服務(wù)的注冊和發(fā)現。這個(gè)演示Demo我本地是可以直接運行成功的,如果有下載下來(lái)運行不成功的,可以評論區給我留言。由于博客園有文件上傳大小的限制,所以我將Demo上傳到了百度網(wǎng)盤(pán)中
下載鏈接:鏈接: https://pan.baidu.com/s/1LDyoRQehaE0FzedFTC4_Og 提取碼: i45x 

總結

    以上就是關(guān)于Zipkin以及ASP.NET Core整合Zipkin的全部?jì)热?,希望能給大家帶來(lái)一定的幫助。如果你有實(shí)際需要也可以繼續自行研究。Zipkin相對于我們常用的Skywalking而且,它的使用方式比較原生,許多操作都需要自行通過(guò)代碼操作,而SkyAPM可以做到對代碼無(wú)入侵的方式集成。Skywalking是一款APM(應用性能管理),鏈路跟蹤只是它功能的一部分。而Zipkin是一款專(zhuān)注于鏈路跟蹤的系統,個(gè)人感覺(jué)就鏈路跟蹤這一塊而言,Zipkin更輕量級(如果使用ES作為存儲數據庫的話(huà),Skywalking默認會(huì )生成一堆索引,而Zipkin默認是每天創(chuàng )建一個(gè)索引),而且鏈路信息檢索、詳情展示、鏈路數據上報形式等相對于Skywalking形式也更豐富一些。但是整體而言Skywalking更強大,比如應用監控、調用分析、集成方式等。技術(shù)并無(wú)好壞之分,適合自己的才是更好的,多一個(gè)解決方案,就多一個(gè)解決問(wèn)題的思路,我覺(jué)得這是對于我們程序開(kāi)發(fā)人員來(lái)說(shuō)都應該具備的認知。

到此這篇關(guān)于A(yíng)SP.NET Core整合Zipkin鏈路跟蹤的實(shí)現方法的文章就介紹到這了,更多相關(guān)ASP.NET Core整合Zipkin鏈路跟蹤內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。

日韩去日本高清在线| 波多野结衣AV手机在线观看| 中文无码伦AV中文字幕| 亚洲AV日韩综合一区尤物| 欧美XXXXX精品| 国产台湾无码AV片在线观看|