服务追踪请联系小菜粮机公众号转载本文。那么本文我们继续我们的主题《吃透微服务》,继续了解分布式系统中链接跟踪的解决方案---Sleuth。当然可以作为噱头,也可以作为目的!我们不再争论微服务的质量。最近,我们看到了很多关于微服务特性的负面宣传。不知道大数据喂的准不准~ps:估计背景人物的画像已经被标记为反小分子了。这当然是个玩笑,玩完了,一起为微服务的学习贡献力量吧!微服务的关键是拆分服务,但关键不在微,而在大小合适。从我们走出分服的那一刻起,我们就要对我们的分服负责。这是一个程序员应有的责任!当服务出现问题时,您是否还在苦苦排查无法定位?.无法调试线上代码,发现问题时经常出现如下对话:除了无奈的苦笑,只能一味摸索,终于有一天程序员小菜不再妥协,努力解决问题。我们可不可以有一个类似监控的功能,当一个请求进来的时候,给它分配一个身份令牌,当它在微服务中游荡的时候,每个服务都会留下它的踪迹,当它出现问题的时候,同时我们只需要检查游戏走到哪个微服务,相当于画了一个行为轨迹,通过行为轨迹跟踪服务调用问题!我一边得意,一边嘀咕。这个说起来容易,实现起来好像有点难~退休鼓快敲响了,心想微服务怎么没人想到这个问题,于是在微服务组件间徘徊,想找一个问题的解决方案。最后,侦探出现了。Sleuth1.认识Sleuth之前做了很多准备工作,只是介绍一下Sleuth。说了一大堆口才,还是用一句话简述一下它的作用:在分布式系统中提供跟踪解决方案。它借鉴了很多GoogleDapper的设计。难道又是换壳的东西?先来了解一下Sleuth中的术语和相关概念,只是为了让我们更专业,更好地吹嘘架构。Trace由一组具有相同Id的TraceSpans串联组成一个树结构。为了实现请求跟踪,当一个请求到达分布式系统的入口点时,只需要服务跟踪框架为该请求创建一个唯一的标识符(即TraceId),同时,当en是系统内部不流动,框架一直传递这个唯一值,直到整个请求返回。那么我们就可以通过这个唯一标识,将所有的请求串联起来,形成一个完整的请求链接。Span表示一组基本的工作单元。为了统计每个处理单元的延迟,当请求到达每个服务组件时,还使用唯一标识符(SpanId)来标记其开始、具体过程和结束。通过SpanId的起止时间戳,可以统计Span的调用时间。此外,我们还可以获取事件名称、请求信息等元数据。注解用于记录一段时间内发生的事件。内部使用的重要说明如下:cs(ClientSend):客户端发出请求,开始请求事件sr(ServerReceived):服务器接收到请求,开始处理。sr-cs=networkdelay(服务调用时间)ss(ServerSend):服务器处理后准备发送给客户端。ss-sr=Requestprocessingtimeontheservercr(ClientReveived):客户端收到服务器的响应,请求结束。cr-sr=totaltimerequested理解了三个概念,我们就直接开始吧!2.MasterSleuth像往常一样拿出我们的微服务项目:几个简单的服务自我介绍一下dependency>org.springframework.cloudspring-cloud-starter-sleuth在父项目的dependency中直接引入,这样各个子服务就可以反复引入依赖然后启动我们的简单代码模式:store-orderserviceOrderController:ProductService:store-productserviceProductController:我们在订单服务中使用Feign远程调用商品服务中的接口,然后启动服务调用到查看控制台打印:注意我圈出的部分,你有没有发现什么不同,是的!此字符串包含InformationhasServiceName/TraceId/SpanId。有一个全局的TraceId用于顺序调用,连接调用链。通过分析微服务的日志,不难看出请求的具体过程。但是有一个缺点,就是服务数量增加,或者说日志数量增加。从日志文件中检索某个请求的调用过程并不容易。那么有没有可以全文搜索并可视化展示的插件帮我们解决呢?问题?既然提出了问题,小菜自然是找到了解决问题的办法!那就是ZipKin3。使用ZipKinZipKin是Twitter的一个开源项目。也是基于GoogleDapper实现的。它的主要作用就是解决我们上面提到的问题:采集服务的定时数据,解决微服务架构中的延迟问题,包括数据的采集、存储、搜索和展示。我们可以用它来收集各个服务器上请求链接的跟踪数据,并通过它提供的RESTAPI接口来协助我们查询跟踪数据来实现分布式系统的监控程序,从而及时发现问题系统延迟增加的原因,找出系统性能瓶颈的根本原因!除了面向开发的API接口,ZipKin还提供了一个方便的UI组件添加,帮助我们更直观的搜索和追踪信息,分析请求链接详情,例如:可以查询某个用户请求在某个时间内的处理时间一段时间等等,听到UI组件的时候有没有感觉耳目一新,说明我们可以通过控制台更好的管理链接跟踪?不仅如此,ZipKin还提供了可插拔的数据存储方式,例如:In-Memory、MySQL、Cassandra和Elasticsearch。应援方式不多,总有你喜欢的!我们来看一下ZipKin的基础架构图:可以看出ZipKin的结构并不复杂,由四个核心组件组成:Collector:收集器组件。主要用于处理外部系统发现的跟踪信息,然后将信息转换成ZipKin内部处理过的Span格式,以支持后续的存储、分析、展示等功能。存储:存储组件。主要用于处理采集器收到的跟踪信息。默认情况下,此信息将存储在内存中。我们可以修改存储策略,存储到我们其他的存储仓库中。RestFulAPI:API组件。提供外部访问的接口,如客户端的跟踪信息,或外部系统的访问信息WebUI:UI组件。基于API组件实现的上层应用,用户可以通过UI组件方便、直观地查询和分析跟踪信息。所以ZiPKin有点类似于我们上篇文章提到的Sentinel,分为server和client。客户端是指微服务中的应用程序。服务器的URL地址是在客户端配置的。一旦服务之间发生调用,就会被微服务中配置的Sleuth监听器监听,并生成相应的Trace和Span。信息被发送到服务器。1.ZipKinserver服务器是一个现成的SpringBoot服务。我们只需要下载jar包直接运行即可!下载地址然后我们可以通过命令行启动它:java-jarzipkin-server-2.12.9-exec.jar启动成功后,访问http://localhost:9411可以看到如下页面:所以至此,我们的服务器已经安装成功。然后回到我们的客户端集成2.对于ZipKin客户端,我们需要在每个服务中引入ZipKin依赖org.springframework.cloudspring-cloud-starter-zipkin然后在配置文件中配置:spring:zipkin:base-url:http://127.0.0.1:9411/#zipkin服务器地址discoveryClientEnabled:false#让nacos把它当作一个URL,而不是当作一个服务名sleuth:sampler:probability:1.0#Samplingpercentage然后我们回到项目中,启动项目通过访问我们上面定义好的接口来访问微服务,然后在ZipKinUI界面上观察。我们刚才访问微服务的请求链接出现了。点击其中一条记录,可以查看具体的访问路径。通过跟踪请求链接,可以判断服务的哪个模块耗时较多,进而进行优化或排查bug。3.ZipKinPersistence在ZipKin中,链接跟踪数据默认会保存在内存中,但这种方式显然不适合生产环境。所以ZipKin支持将trackinglink数据持久化到mysql数据库或者elasticsearch。mysql首先首先我们数据库信息信息信息信息信息信息信息,`start_ts`BIGINTCOMMENT'Span.timestamp():epochmicrosusedforendTsqueryandtoimplementTTL',`duration`BIGINTCOMMENT'Span.duration():microsusedforminDurationandmaxDurationquery')ENGINE=InnoDBROW_FORMAT=COMPRESSEDCHARACTERSET=utf8COLLATEutf8_general_ci;ALTERTABLE`zip`kin_spanshigh,id_spansKEY(ADTDUNIQUEKEY))COMMENT'ignoreinsertonduplicate';ALTERTABLEzipkin_spansADDINDEX(`trace_id_high`,`trace_id`,`id`)COMMENT'forjoiningwithzipkin_annotations';ALTERTABLEzipkin_spansADDINDEX(`trace_id_high`,`trace_id`)COMMENT'forgetTracesByIds';ALTERTABLEzipkin_spans'andgetSpans)'namesADDINDEX('name;ALTERTABLEzipkin_spansADDINDEX(`start_ts`)COMMENT'forgetTracesorderingandrange';CREATETABLEIFNOTEXISTSzipkin_annotations(`trace_id_high`BIGINTNOTNULLDEFAULT0COMMENT'Ifnonzero,thismeansthetraceuses128bittraceIdsinsteadof64bit',`trace_id`BIGINTNOTNULLCOMMENT'coincideswithzipkin_spans.trace_id',`span_id`BIGINTNOTNULLCOMMENT'coincideswithzipkin_spans.id',`a_key`VARCHAR(255)NOTNULLCOMMENT'BinaryAnnotation.keyorAnnotation.valueiftype==-1',`a_value`BLOBCOMMENT'BinaryAnnotation.value(),必须小于64KB',`a_type`INTNOTNULLCOMMENT'BinaryAnnotation.type()or-1ifAnnotation',`a_timestamp`BIGINTCOMMENT'UsedtoimplementTTL;Annotation.timestamporzipkin_spans.timestamp',`endpoint_ipv4`INTCOMMENT'NullwhenBinary/Annotation.endpointisnull',`endpoint_ipv6`BINARY(16)COMMENT'NullwhenBinary/Annotation.endpointisnull,ornoIPv6address',`endpoint_port`SMALLINTCOMMENT'NullwhenBinary/Annotation.endpointisnull',`endpoint_service_name`VARCHAR(255)COMMENT'NullwhenBinary/Annotation.endpointisnull')ENGINE=InnoDBROW_FORMAT=COMPRESSEDCHARACTERSET=utf8COLLATEutf8_general_ci;ALTERTABLEzipkin_annotationsADDUNIQUEKEY(`trace_id_high`,`trace_id`,`span_id`,`a_key`,`a_timestamp`)COMMENT'Ignoreinsertonduplicate';ALTERTABLEzipkin_annotationsADDINDEX(`trace_id_high`,`trace_id`,`span_id`)COMMENT'forjoiningwithzipDinderspans;`trace_id_high`,`trace_id`)COMMENT'forgetTraces/ByIds';ALTERTABLEzipkin_annotationsADDINDEX(`endpoint_service_name`)COMMENT'forgetTracesandgetServiceNames';ALTERTABLEzipkin_annotationsADDINDEX(`a_type`)COMMENT'forgetTraces';ALTERTABLEzipkin_annotationsADDINDEX(`zipa_key`)TABLEBERCETIONSCOMMENT'`trace_id`,`span_id`,`a_key`)COMMENT'fordependenciesjob';CREATETABLEIFNOTEXISTSzipkin_dependencies(`day`DATENOTNULL,`parent`VARCHAR(255)NOTNULL,`child`VARCHAR(255)NOTNULL,`call_count`BIGINT)ENGINE=InnoDBROW_FORMAT=COMPRESSEDCHARACTERSET=utf8COLLATEutf8_general_ci;ALTERTABLEzipkin_dependenciesADDUNIQUEKEY(`day`,`parent`,`child`);启动时间指定mysql信息java-DSTORAGE_TYPE=mysql-DMYSQL_HOST=127.0.0.1-DMYSQL_TCP_PORT=3306-DMYSQL_DB=zipkin-DMYSQL_USER=root-DMYSQL_PASS=root-jarzipkin-server-2.12.9-exec.jarElasticSearch启动ES指定ES信息java-jarzipkin-server-2.12.9-exec.jar--STORAGE_TYPE=elasticsearch--ES-HOST=localhost:9200END到这里我们就完成了分布式系统中服务链接跟踪的解决!这为我们解决了问题?跨微服务API调用出现异常,快速定位跨微服务API调用出现性能瓶颈的问题,快速定位性能瓶颈。