当前位置: 首页 > 科技观察

链接跟踪:Sleuth集成ZipKin

时间:2023-03-19 09:48:49 科技观察

在《SpringCloud Alibaba实战》专栏的上一篇文章中,我们实现了用户微服务、商品微服务、订单微服务之间的远程调用,实现了服务调用的负载均衡。还基于阿里开源的Sentinel实现了服务的限流和容错,详细介绍了Sentinel的核心技术和配置规则。简单介绍了服务网关,简单说明了SpringCloudGateway的核心架构。项目中还集成了SpringCloudGateway网关,实现通过网关访问后端微服务。Stream函数,详细介绍了SpringCloudGateway的核心技术。在链接跟踪章节中,我们简单介绍了分布式链接跟踪技术和解决方案,然后在项目中集成了Sleuth来实现链接跟踪。本章概述本章概述了我们在集成Sleuth实现链接跟踪时,通过查看日志了解系统调用的链接状态。这不是一个好的解决方案。如果系统包含的微服务越来越多,通过查看日志来分析系统调用是非常复杂的,在实际项目中根本行不通。此时,我们可以整合Sleuth和ZipKin,使用ZipKin聚合日志,可视化链接日志,支持全文搜索。Zipkin核心架构Zipkin是Twitter的一个开源项目。它是基于GoogleDapper论文实现的。可以采集微服务运行过程中的实时链路数据,并展示出来。ZipKin简介Zipkin是一个分布式链接跟踪系统,可以在微服务运行过程中实时采集调用链接信息,并将调用链接信息显示在web界面上,供开发者分析。开发者可以从ZipKin入手,分析调用环节的性能瓶颈,找出问题应用,进而定位并解决问题。ZipKin核心架构ZipKin的核心架构图如下图所示。注:图片来源:zipkin.io/pages/architecture.html其中,ZipKin核心组件的功能如下。Reporter:ZipKin中上报链路数据的模块,主要配置在具体的微服务应用中。Transport:ZipKin中传输链路数据的模块。该模块可以配置为Kafka、RocketMQ、RabbitMQ等。Collector:ZipKin中收集和消费链接数据的模块。默认情况下,它通过http协议收集,并且可以配置为Kafka消费。Storage:ZipKin中存储链接数据的模块。该模块可以配置为ElasticSearch、Cassandra或MySQL。目前,ZipKin支持这三种数据持久化方式。API:ZipKin中的API组件,主要用于对外提供访问接口。比如向客户端显示跟踪信息,或者开放给外部系统进行监控。UI:ZipKin中的UI组件,基于API组件实现的上层应用。通过UI组件,用户可以方便、直观地查询和分析跟踪信息。Zipkin一般分为两端,一端是Zipkinserver,另一端是Zipkinclient。客户端主要配置在微服务应用中,收集微服务中的调用链接信息,并将数据发送给Zipkin服务端。项目集成ZipKinZipkin一般分为server和client。我们需要下载并启动ZipKin服务端的Jar包,并在微服务中集成ZipKin客户端。下载并安装ZipKin服务器(1)下载ZipKin服务器的Jar文件,可以直接在浏览器中输入以下链接进行下载。https://search.maven.org/remote_content?g=io.zipkin.java&a=zipkin-server&v=LATEST&c=exec如果你使用的是Linux操作系统,也可以在命令行输入以下命令进行下载。wgethttps://search.maven.org/remote_content?g=io.zipkin.java&a=zipkin-server&v=LATEST&c=exec这里我通过浏览器下载的ZipKinserverJar文件是:zipkin-server-2.12.9-执行.jar。(2)在命令行输入以下命令启动ZipKin服务器。java-jarzipkin-server-2.12.9-exec.jar(3)由于ZipKinserver启动,默认监听端口号为9411,所以在浏览器中输入http://localhost:9411链接打开该界面ZipKin如下所示。在浏览器中输入http://localhost:9411链接,打开如上页面,即表示ZipKin服务器准备就绪。项目集成ZipKin客户端(1)在每个微服务中添加ZipKin依赖(用户微服务商店-用户、产品微服务商店-产品、订单微服务商店-订单、网关服务商店-网关),如下图。org.springframework.cloudspring-cloud-starter-zipkin(2)在网关服务店的application.yml文件中添加如下内容-网关配置。spring:sleuth:sampler:probability:1.0zipkin:base-url:http://127.0.0.1:9411discovery-client-enabled:false各配置说明如下。spring.sleuth.sampler.probability:表示Sleuth的采样百分比。spring.zipkin.base-url:ZipKin服务器的地址。spring.zipkin.discovery-client-enabled:配置为false,这样Nacos会把它当作一个URL来处理,而不是按照服务名来处理。(3)分别启动用户微服务、商品微服务、订单微服务和服务网关,在浏览器中访问链接http://localhost:10001/server-order/order/submit_order?userId=1001&productId=1001&count=1,如如下。(4)在Zipkin界面点击Find按钮,如下图。点击后界面如下。可以看到点击搜索按钮后会出现一个请求链接,其中:网关服务server-gateway耗时63.190毫秒,订单微服务server-order耗时53.101毫秒,用户微服务server-user耗时14.640毫秒,商品微服务服务器产品耗时10.941毫秒。(5)点击ZipKin界面显示的调用链接,如下图。点击后的界面如下图。整个调用的接入环节可以看得很清楚。我们也可以点击具体的节点,查看具体的调用信息。比如我们点击网关微服务,可以查看网关的具体链接,如下图。点击后的效果如下图。接下来查看订单微服务调用链接的具体信息,如下图。点击后的效果如下图。可以看到,通过ZipKin可以查看服务的调用链接,可以查看具体微服务的调用情况。我们可以基于ZipKin分析系统的调用环节,找出系统的瓶颈,然后进行针对性的优化。另外,ZipKin还支持下载系统调用链接的Json数据,如下图。点击JSON按钮后,效果如下。其中,显示的Json数据如下。[[{"traceId":"9d244edbc1668d92","parentId":"3f01ba499fac4ce9","id":"5f0932b5d06fe757","kind":"SERVER","name":"get/get/{pid}","时间戳”:1652413758790051,“持续时间”:10941,“localEndpoint”:{“服务名称”:“服务器产品”,“ipv4”:“192.168.0.111”},“remoteEndpoint”:{“ipv4”:“192.168.0.111”","port":54140},"tags":{"http.method":"GET","http.path":"/product/get/1001","mvc.controller.class":"ProductController","mvc.controller.method":"getProduct"},"shared":true},{"traceId":"9d244edbc1668d92","parentId":"3f01ba499fac4ce9","id":"c020c7f6e0fa1604","kind":“服务器”,“名称”:“get/update_count/{pid}/{count}”,“时间戳”:1652413758808052,“持续时间”:5614,“localEndpoint”:{“服务名称”:“服务器产品”,“ipv4":"192.168.0.111"},"remoteEndpoint":{"ipv4":"192.168.0.111","port":54140},"tags":{"http.method":"GET","http.path":"/product/update_count/1001/1","mvc.controller.class":"ProductController","mvc.controller.method":"updateCount"},"shared":true},{"traceId":"9d244edbc1668d92","parentId":"9d244edbc1668d92","id":"3f01ba499fac4ce9","kind":"CLIENT","name":"get","timestamp":1652413758763816,"duration":54556,"localEndpoint":{"serviceName":"server-gateway","ipv4":"192.168.0.111"},"remoteEndpoint":{"ipv4":"192.168.0.111","port":8080},"tags":{"http.method":"GET","http.path":"/order/submit_order"}},{"traceId":"9d244edbc1668d92","parentId":"9d244edbc1668d92","id":"475ff483fb0973b1","kind":“客户”,“名称”:“获取”,“时间戳”:1652413758759023,“持续时间”:59621,“localEndpoint”:{“服务名称”:“服务器网关”,“ipv4”:“192.168.0.111”},“标签”:{"http.method":"GET","http.path":"/order/submit_order"}},{"traceId":"9d244edbc1668d92","id":"9d244edbc1668d92","kind":"SERVER","name":"get","timestamp":1652413758757034,"duration":63190,"localEndpoint":{"serviceName":"server-gateway","ipv4":"192.168.0.111"},"remoteEndpoint":{“ipv4”:“127.0.0.1”,“端口”:54137},“标签”:{“http.method”:“GET”,“http.path”:“/server-order/order/submit_order”}},{"traceId":"9d244edbc1668d92","parentId":"3f01ba499fac4ce9","id":"a048eda8d5fd3dc9","kind":"CLIENT","name":"get","timestamp":1652413758774201,“持续时间”:12054,"localEndpoint":{"serviceName":"server-order","ipv4":"192.168.0.111"},"tags":{"http.method":"GET","http.path":"/user/get/1001"}},{"traceId":"9d244edbc1668d92","parentId":"3f01ba499fac4ce9","id":"5f0932b5d06fe757","kind":"CLIENT","name":"get","timestamp":1652413758787924,"duration":12557,"localEndpoint":{"serviceName":"server-order","ipv4":"192.168.0.111"},"tags":{"http.method":"GET","http.path":"/product/get/1001"}},{"traceId":"9d244edbc1668d92","parentId":"3f01ba499fac4ce9","id":"c020c7f6e0fa1604","kind":"CLIENT","name":"get","timestamp":1652413758805787,"duration":7031,"localEndpoint":{"serviceName":"server-order","ipv4":"192.168.0.111"},“标签”:{“http.method”:"GET","http.path":"/product/update_count/1001/1"}},{"traceId":"9d244edbc1668d92","parentId":"9d244edbc1668d92","id":"3f01ba499fac4ce9","kind"“:“服务器”,“名称”:“get/submit_order”,“时间戳”:1652413758765048,“持续时间”:53101,“localEndpoint”:{“服务名称”:“服务器顺序”,“ipv4”:“192.168。0.111"},"remoteEndpoint":{"ipv4":"127.0.0.1"},"tags":{"http.method":"GET","http.path":"/order/submit_order","mvc.controller.class":"OrderController","mvc.controller.method":"submitOrder"},"shared":true},{"traceId":"9d244edbc1668d92","parentId":"3f01ba499fac4ce9","id":"a048eda8d5fd3dc9","kind":"SERVER","name":"get/get/{uid}","timestamp":1652413758777073,"duration":14640,"localEndpoint":{"serviceName":"server-用户”,“ipv4”:“192.168.0.111”},“remoteEndpoint”:{“ipv4”:“192.168.0.111”,“端口”:54139},“标签”:{“http.method”:“GET”,“http.path":"/user/get/1001","mvc.controller.class":"UserController","mvc.controller.method":"getUser"},"shared":true}]]朋友也照Json数据分析,系统调用链接ZipKin数据持久化我们在项目中已经实现了ZipKin的集成,但是此时我们集成ZipKin之后,ZipKin中的数据是存储在系统内存中的。如果我们重启ZipKin,那么系统内存中保存的数据就会丢失,那么如何避免数据丢失呢?ZipKin支持数据持久化以防止数据丢失,并且可以将数据保存到ElasticSearch、Cassandra或MySQL。这里重点介绍如何将数据保存到MySQL和ElasticSearch中。将Zipkin数据持久化到MySQL(1)将Zipkin数据持久化到MySQL,我们需要知道MySQL的数据表结构。好在ZipKin提供了MySQL脚本,小伙伴们可以链接到:https://github.com/openzipkin从/zipkin/tree/master/zipkin-storage下载。当然我把下载的MySQL脚本放在网关服务shop-gateway的resources目录下的scripts目录下。(2)在MySQL数据库中新建一个zipkin数据库,如下图。如果zipkin不存在则创建数据库;(3)在新建的数据库zipkin中运行mysql.sql脚本,脚本运行后效果如下。可以看到在zipkin数据库中新建了三个数据表zipkin_annotations、zipkin_dependencies和zipkin_spans。(4)启动ZipKin时指定MySQL数据源,如下图。java-jarzipkin-server-2.12.9-exec.jar--STORAGE_TYPE=mysql--MYSQL_HOST=127.0.0.1--MYSQL_TCP_PORT=3306--MYSQL_DB=zipkin--MYSQL_USER=root--MYSQL_PASS=root(5)开始ZipKin之后,在浏览器中访问链接http://localhost:10001/server-order/order/submit_order?userId=1001&productId=1001&count=1,如下图。(6)查看zipkin数据库中的数据,发现zipkin_annotations数据表和zipkin_spans数据表中已有系统调用链接数据。zipkin_annotations数据表中的部分数据如下所示。zipkin_spans数据表中的部分数据如下所示。可以看出ZipKin已经将数据持久化到MySQL中了。重启ZipKin后,会从MySQL中读取数据,数据不会丢失。ZipKin数据持久化到ElasticSearch(1)到ElasticSearch官网下载ElasticSearch,链接为:https://www.elastic.co/cn/downloads/elasticsearch。这里下载的安装包是:elasticsearch-8.2.0-windows-x86_64.zip。(2)解压elasticsearch-8.2.0-windows-x86_64.zip,解压后在bin目录下找到elasticsearch.bat脚本,双击运行ElasticSearch。(3)启动ZipKin服务器时,指定ElasticSearch,如下图。java-jarzipkin-server-2.12.9-exec.jar--STORAGE_TYPE=elasticsearch--ESHOST=localhost:9200(4)启动ZipKin服务器后,在浏览器中访问链接http://localhost:10001/server-order/order/submit_order?userId=1001&productId=1001&count=1如下图。ZipKin会将请求的链接信息保存到ElasticSearch中进行持久化。