其中-f是指定文件名称,如果是docker-compose.yml则可以直接忽略文件名称,当shell中出现如下界面
并且在浏览器中输入:9411/zipkin/出现如图所示,则说明Zikpin启动成功
整合ASP.NET Core
ZipKin启动成功之后,我们就可以将程序中的数据采集到Zipkin中去了,我新建了两个ASP.NET Core的程序,一个是OrderApi,另一个是ProductApi方便能体现出调用链路,其中OrderApi调用ProductApi接口,在两个项目中分别引入Zipkin依赖包
<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服务地址和内容类型 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); }); //程序停止时停止链路跟踪 lifetime.ApplicationStopped.Register(() => TraceManager.Stop()); //引入zipkin中间件,用于跟踪服务请求,这边的名字可自定义代表当前服务名称 app.UseTracing(Configuration["nacos:ServiceName"]); }
然后我们在Configure方法中调用RegisterZipkinTrace方法即可。由于我们要在OrderApi项目中采用HttpClient的方式调用ProductAPI,默认zipkin4net是支持采集HttpClient发出请求的链路数据(由于在ProductApi中我们并不发送Http请求,所以可以不用集成一下操作),具体集成形式如下,如果使用的是HttpClientFactory的方式,在ConfigureServices中配置如下
public void ConfigureServices(IServiceCollection services) { //由于我使用了Nacos作为服务注册中心 services.AddNacosAspNetCore(Configuration); services.AddScoped<NacosDiscoveryDelegatingHandler>(); services.AddHttpClient(ServiceName.ProductService,client=> { client.BaseAddress = new Uri($"http://{ServiceName.ProductService}"); }) .AddHttpMessageHandler<NacosDiscoveryDelegatingHandler>() //引入zipkin trace跟踪httpclient请求,名称配置当前服务名称即可 .AddHttpMessageHandler(provider =>TracingHandler.WithoutInnerHandler(Configuration["nacos:ServiceName"])); services.AddControllers(); }
如果是直接是使用HttpClient的形式调用则可以采用以下方式
using (HttpClient client = new HttpClient(new TracingHandler("OrderApi"))) { }
然后我们在OrderApi中写一段调用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>订单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服务接口 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; } }