前言

本文紧接上篇.Net架构篇:思考如何设计一款实用的分布式监控系统?,上篇仅仅是个思考篇,跟本文没有太大的关系。但有思考,结合现有的开源组件,实践起来更易理解起来,所以看本文之前,应该先看下上篇博文。

Zipkin简介

Zipkin是一种分布式跟踪系统。它有助于收集解决微服务架构中的延迟问题所需的时序数据。它管理这些数据的收集和查找。Zipkin的设计基于Google Dapper 论文。

应用程序用于向Zipkin报告时序数据。Zipkin UI还提供了一个依赖关系图,显示了每个应用程序通过的跟踪请求数。如果要解决延迟问题或错误,可以根据应用程序,跟踪长度,注释或时间戳对所有跟踪进行筛选或排序。选择跟踪后,您可以看到每个跨度所需的总跟踪时间百分比,从而可以识别有问题的应用程序。

快速开始

Docker

docker run -d -p 9411:9411 openzipkin/zipkin

Java

curl -sSL https://zipkin.io/quickstart.sh | bash -s

java -jar zipkin.jar

源码启动

# get the latest source
git clone https://github.com/openzipkin/zipkin
cd zipkin
# Build the server and also make its dependencies
./mvnw -DskipTests --also-make -pl zipkin-server clean install
# Run the server
java -jar ./zipkin-server/target/zipkin-server-*exec.jar

无论您以何种方式启动zikpin,请访问 http://your_host:9411以查询跟踪。

启动效果

架构

架构简述

应用程序中的监控器记录有关发生的操作的时间和元数据,并且对用户是透明的。如一个web监听服务记录了请求什么时候进来,什么时候离开。这个监控的数据叫做Span。

将数据发送到Zipkin的检测应用程序中的组件称为Reporter。

如图所示 

示例流程

这是一个示例序列的http跟踪,其中用户代码调用资源/ foo。这个结果是单个Span,在用户代码收到http响应后异步发送到Zipkin。

┌─────────────┐ ┌───────────────────────┐ ┌─────────────┐ ┌──────────────────┐
│ User Code │ │ Trace Instrumentation │ │ Http Client │ │ Zipkin Collector │
└─────────────┘ └───────────────────────┘ └─────────────┘ └──────────────────┘
│ │ │ │
┌─────────┐
│ ──┤GET /foo ├─▶ │ ────┐ │ │
└─────────┘ │ record tags
│ │ ◀───┘ │ │
────┐
│ │ │ add trace headers │ │
◀───┘
│ │ ────┐ │ │
│ record timestamp
│ │ ◀───┘ │ │
┌─────────────────┐
│ │ ──┤GET /foo ├─▶ │ │
│X-B3-TraceId: aa │ ────┐
│ │ │X-B3-SpanId: 6b │ │ │ │
└─────────────────┘ │ invoke
│ │ │ │ request │

│ │ │ │ │
┌────────┐ ◀───┘
│ │ ◀─────┤200 OK ├─────── │ │
────┐ └────────┘
│ │ │ record duration │ │
┌────────┐ ◀───┘
│ ◀──┤200 OK ├── │ │ │
└────────┘ ┌────────────────────────────────┐
│ │ ──┤ asynchronously report span ├────▶ │
│ │
│{ │
│ "traceId": "aa", │
│ "id": "6b", │
│ "name": "get", │
│ "timestamp": 1483945573944000,│
│ "duration": 386000, │
│ "annotations": [ │
│--snip-- │
└────────────────────────────────┘

跟踪检测报告以异步方式跨越,以防止与跟踪系统相关的延迟或故障延迟或中断用户代码。

Transport。

由仪器库发送的span必须从跟踪到Zipkin收集器的服务传输。 主要支持三种传输: HTTP, Kafka 和 Scribe.

组件

Zipkin有4个组件:

  • 收集器(collector)
  • 存储(storage)
  • 搜索(search)
  • web UI

Web UI

我们创建了一个GUI,它为查看跟踪提供了一个很好的界面。Web UI提供了一种基于服务,时间和注释查看跟踪的方法。注意:UI中没有内置身份验证!

.NetCore使用zipkin

第一款ZipkinTracer

按照官方文档说明。


using ZipkinTracer.DependencyInjection;
using ZipkinTracer.Owin;
public class Startup
{
public void Configuration(IApplicationBuilder app)
{
app.UseZipkinTracer();
}
public void ConfigureServices(IServiceCollection services)
{
var config = new ZipkinConfig(new Uri("http://XXX:9411"), request => new Uri("https://yourservice.com"))
{
Bypass = request => request.GetUri().AbsolutePath.StartsWith("/allowed"),
SpanProcessorBatchSize = 10,
SampleRate = 0.5
}
services.AddZipkinTracer(config);
}
}
//GetUri()方法报错。

改成如下方法:

 public void Configuration(IApplicationBuilder app)
{
app.UseZipkinTracer();
}
public void ConfigureServices(IServiceCollection services)
{
var config = new ZipkinConfig(new Uri("http://weixinhe.cn:9411"));
services.AddZipkinTracer(config);
services.AddZipkinTracer(config);
}

客户端调用

using ZipkinTracer.Http;
public class HomeController : Controller
{
private readonly IZipkinTracer _tracer;
public HomeController(IZipkinTracer tracer)
{
_tracer = tracer;
}
public async Task<ActionResult> Index()
{
using (var httpClient = new HttpClient(new ZipkinMessageHandler(_tracer))))
{
var response = await httpClient.GetAsync("http://www.google.com");
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
}
}
return View();
}
}

运行程序,报错! 

让我们去官网看看问题,issue 里面有人提出了这个问题,

Registering zipkin tracer throws an error #10

下面有人回复:意思是需要重写中间件。

I have the same issue. According to the documentation, the dependencies in the middlewares should be moved into the Invoke method. In this case, the ZipkinMiddleware has to be changed in my opinion.

年久失修,作者未回复。但是源码都放在那里了,难道任由其报错而无能为力么?这我不能忍受。所以,下载源码,引用源码项目。开启调试之路。

解决问题

右键查看属性,竟然看不到目标框架。应该是版本太低了。 

查看依赖版本是framework4.6和.netstandard 1.3

那好办,我们新建一个.netcore2.1版本的项目,然后将tracer的代码都复制过去。 一些复制好并引用后,还是刚才那个错。调试也没有看到哪里报错,只是最终页面报错了。所以我们继续搜索。

Cannot consume scoped service 'XXXX' from singleton 'XXX'.

依赖注入的知识普及

.net核心依赖注入生命周期解释

无法从Singleton消耗Scoped服务 - ASP.net核心DI范围的一课

ASP.net核心中的第三方依赖注入

此网站已收集在.NetCore外国一些高质量博客分享,长期保持更新。

上面三篇文章普及了一些依赖注入的知识。sorry,这块我研究的很浅。。。这次顺带了解了不少,以后要抽空专门研究一下。

Single:单例是一个将持续应用程序整个生命周期的实例。在Web术语中,这意味着在服务的初始请求之后,每个后续请求将使用相同的实例。这也意味着它跨越Web请求(因此,如果两个不同的用户访问您的网站,代码仍然使用相同的实例)。考虑单例的最简单方法是,如果类中有静态变量,则它是跨多个实例的单个值。

Scoped:范围内的生命周期对象通常会简化为“每个Web请求一个实例”,但实际上它比实际上更加微妙。无可否认,在大多数情况下,您可以将每个Web请求视为范围对象。您可能会看到的常见问题是每个Web请求创建一次DBContext,或者创建一次NHibernate上下文,以便您可以将整个请求包含在事务中。作用域生存期对象的另一个非常常见的用途是当您要创建每个请求缓存时。 Scoped生命周期实际上意味着在创建的“范围”对象中将是同一个实例。它恰好发生在.net核心中,它在“范围”内包装请求,但您实际上可以手动创建范围

Transient:每次请求服务时,都会创建一个新实例。

关于上述的类似错误无法从单件服务 #2569中使用作用域服务'AutoMapper.IMapper',有用户评论:

这是一个基本的设计约束。你不能让单身人士(Single)依赖于瞬态(Scoped)或范围内(Transient)的物品。这不是容器的错,这些生命周期是不相容的。如果您需要兼容的生命周期,请选择不同的生命周期。

Singleton < - Singleton 良好

Singleton < - Scoped 糟糕

Singleton < - Transient 糟糕

Scoped < - Singleton 良好

Scoped < - Scoped 良好

Scoped < - Transient 良好

TRANSIENT < - Singleton 良好

Transient < - Scoped 良好在范围内,糟糕在范围外 TRANSIENT< - TRANSIENT 良好

所以真的只有两种情况“总是糟糕”,一种情况“有时候很糟糕”。 ASP.NET Core DI使这个非常明确,甚至将工厂方法传递给上下文对象,例如过滤器。过滤器是Singleton,因此您不能拥有构造函数依赖项。相反,您使用传递给过滤器方法的各种XyzContext对象来解析依赖项。

上述是十分有价值的评价,先收藏,以后细细品味。

有了这些基础知识和良好建议,我们再来回顾下代码。看到前面都是AddSingleton,后面是AddScoped,在上面的建议中是属于糟糕的。虽然不清楚作者的意图,但我们可以先把程序跑起来,以后用熟悉了再来仔细修复。

 public static class ServiceCollectionExtensions
{
public static void AddZipkinTracer(this IServiceCollection services, ZipkinConfig config)
{
if (config == null) throw new ArgumentNullException(nameof(config));
var maxSize = config.MaxQueueSize <= 0 ? 100 : config.MaxQueueSize;
services.AddSingleton(config);
services.AddSingleton(new BlockingCollection<Span>(maxSize));
services.AddSingleton<IServiceEndpoint, ServiceEndpoint>();
services.AddSingleton<ISpanProcessorTask, SpanProcessorTask>();
services.AddSingleton<ISpanProcessor, SpanProcessor>();
services.AddSingleton<ITraceInfoAccessor, TraceInfoAccessor>();
services.AddScoped<ISpanCollector, SpanCollector>();
services.AddScoped<IZipkinTracer, ZipkinClient>();
services.AddScoped<ISpanTracer, SpanTracer>();
}
}

好吧,临时将三个AddScoped 改为 AddSingleton(); 运行项目。又开始报错了。。。。说IZipkinTracer需要一个无参的构造函数。

InvalidOperationException: Could not create an instance of type 'ZipkinTracer.IZipkinTracer'. Model bound complex types must not be abstract or value types and must have a parameterless constructor. Alternatively, give the 'tracer' parameter a non-null default value.

继续搜索新的这个错误。

模型绑定的知识普及

精彩评论:

您正在混淆依赖注入模型绑定。有一个很大的不同。请考虑执行以下操作。 注册IModelFactory为服务:

public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IModelFactory>(ModelFactory.Current);
// Add framework services.
services.AddMvc();
}

现在在您的控制器中,用于FromServices获取实例,并使用以下内容获取创建模型所需的值FromForm:

[HttpPost]
public IActionResult CreateTemplate([FromForm] string name,
[FromServices] IModelFactory factory)
{
var item = factory.CreateTechnicalTaskTemplate(name);
repo.Templates.Add(item);
return View(nameof(TemplatesList));
}

您的工厂应该被视为一项服务。模型绑定需要POCO,而不是接口。

从入门到放弃

对不起,模型绑定这个错,我没看太懂,只能先放弃了。如果对着源码都找不到解决办法,我只能理解自己的知识太浅。。。时间也很晚了,程序员也是需要有业余生活的。关于zipkintracer的试用到此为止。下期使用官方推荐客户端zipkin4net

看官们,你们也真的深入了解依赖注入和模型绑定么?

总结

本篇旅程虽然失败,但也了解了zipkin的相关介绍,原理,也在解决问题的过程中加深了依赖注入的理解。模型绑定的概念还不是太清楚,抽空我再看看。真可谓:无心栽花花不成,无心插柳柳成荫。来一句鸡汤:努力向前走,总会有意想不到的收获。

可参考资料

部署Zipkin分布式性能追踪日志系统的操作记录

微服务监控zipkin+asp.net core

各大厂分布式链路跟踪系统架构对比 Net和Java基于zipkin的全链路追踪

本篇到此结束,感谢观看。

NetCore实践篇:分布式监控客户端ZipkinTracer从入门到放弃之路的更多相关文章

  1. .NetCore实践篇:分布式监控系统zipkin踩坑之路(二)

    前言 <牧神记>有一句话说的好,破心中神.当不再对分布式,微服务,CLR畏惧迷茫的时候,你就破了心中神. zipkin复习 第一篇: .Net架构篇:思考如何设计一款实用的分布式监控系统? ...

  2. .NetCore实践篇:成功解决分布式监控ZipKin聚合依赖问题(三)

    前言 读本篇文章之前,可以先读前两篇文章.为了照顾没看过的朋友,我也会稍作复习. 思考大纲: .Net架构篇:思考如何设计一款实用的分布式监控系统? 实践篇一:.NetCore实践篇:分布式监控客户端 ...

  3. .NetCore实践篇:分布式监控Zipkin持久化之殇

    前言 本系列已写了四篇文章,读本篇之前,可以先读前面几篇. 思考大纲:.Net架构篇:思考如何设计一款实用的分布式监控系统? 实践篇一:.NetCore实践篇:分布式监控客户端ZipkinTracer ...

  4. Scrapy入门到放弃03:理解settings配置,监控Scrapy引擎

    前言 代码未动,配置先行.本篇文章主要讲述一下Scrapy中的配置文件settings.py的参数含义,以及如何去获取一个爬虫程序的运行性能指标. 这篇文章无聊的一匹,没有代码,都是配置化的东西,但是 ...

  5. Scrapy入门到放弃01:开启爬虫2.0时代

    前言 Scrapy is coming!! 在写了七篇爬虫基础文章之后,终于写到心心念念的Scrapy了.Scrapy开启了爬虫2.0的时代,让爬虫以一种崭新的形式呈现在开发者面前. 在18年实习的时 ...

  6. 爬虫入门到放弃系列02:html网页如何解析

    前言 上一篇文章讲了爬虫的概念,本篇文章主要来讲述一下如何来解析爬虫请求的网页内容. 一个简单的爬虫程序主要分为两个部分,请求部分和解析部分.请求部分基本一行代码就可以搞定,所以主要来讲述一下解析部分 ...

  7. 爬虫入门到放弃系列05:从程序模块设计到代理IP池

    前言 上篇文章吧啦吧啦讲了一些有的没的,现在还是回到主题写点技术相关的.本篇文章作为基础爬虫知识的最后一篇,将以爬虫程序的模块设计来完结. 在我漫(liang)长(nian)的爬虫开发生涯中,我通常将 ...

  8. 爬虫入门到放弃系列07:js混淆、eval加密、字体加密三大反爬技术

    前言 如果再说IP请求次数检测.验证码这种最常见的反爬虫技术,可能大家听得耳朵都出茧子了.当然,也有的同学写了了几天的爬虫,觉得爬虫太简单.没有啥挑战性.所以特地找了三个有一定难度的网站,希望可以有兴 ...

  9. scrapy入门到放弃02:整一张架构图,开发一个程序

    前言 Scrapy开门篇写了一些纯理论知识,这第二篇就要直奔主题了.先来讲讲Scrapy的架构,并从零开始开发一个Scrapy爬虫程序. 本篇文章主要阐述Scrapy架构,理清开发流程,掌握基本操作. ...

随机推荐

  1. C# 使用System.Data.OleDb;避免oracle中文乱码问题

    首先,需要保证oracle客户端服务器的字符集是一样的,并且保证该字符集支持中文.你可以使用plsql查看是否乱码. 代码: using System; using System.Collection ...

  2. 【Linux高频命令专题(24)】grep

    简述 Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来.grep全称是Global Regular Expression Print,表示全局正则 ...

  3. linux富规则的案例

    使用firewall-cmd添加富规则: 1.拒绝来自public区域中ip地址为192.168.0.11的所有流量 firewall-cmd --permanent --zone=public -- ...

  4. SQL Server Alert发送告警邮件少了的原因

    最近突然发现我们部署在数据库上面的告警(Alert),当错误日志里面出现错误时,并不是每个错误日志都会发送邮件出来.如下所示,设置了告警"SQL Server Severity Event ...

  5. 内核线程的进程描述符task_struct中的mm和active_mm

    task_struct进程描述符中包含两个跟进程地址空间相关的字段mm, active_mm, struct task_struct { // ... struct mm_struct *mm; st ...

  6. c/c++ static关键字

    static关键字 1,static 成员变量 static 成员变量不随着对象的创建而开辟内存空间.也就是说,不管从哪个对象去看static成员变量,都是一样的. 2, static 成员方法 st ...

  7. python3使用selenium + Chrome基础操作代码

    selenium是Python的第三方库,使用前需要安装.但是如果你使用的是anaconda,就可以省略这个步骤,为啥?自带,任性. 安装命令: pip install selenium (一)使用s ...

  8. 自定义Chrome浏览器

    一.全局 自用备份,窗体透明化.要添加对应网站的窗体class到对应的位置 /*主页背景*/ /*https://images.cnblogs.com/cnblogs_com/AardWolf/135 ...

  9. python入门练习题

    1.使用while循环输入 1 2 3 4 5 6     8 9 10 num = 1 while num<=10: if num ==7: num += 1 continue print(n ...

  10. Maven中POM.XML详解

    转自https://blog.csdn.net/jariwsz/article/details/19554137 我们先看一个简单的例子: <project xmlns="http:/ ...