使用sleuth实现微服务跟踪
2017-09-04 15:08
429 查看
![](http://upload-images.jianshu.io/upload_images/6944619-23cecac667fc1c11.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
在微服务架构中,众多的微服务之间互相调用,如何清晰地记录服务的调用链路是一个需要解决的问题。同时,由于各种原因,跨进程的服务调用失败时,运维人员希望能够通过查看日志和查看服务之间的调用关系来定位问题,而
Spring cloud sleuth组件正是为了解决微服务跟踪的组件。
sleuth的原理介绍可以参考这篇文章: [服务链路追踪(Spring Cloud Sleuth)](http://blog.csdn.net/forezp/article/details/70162074)
本文主要讲解sleuth的两方面用法
- sleuth+elk 结合,聚合微服务日志
- sleuth+ zipkin结合,显示文件调用链路
本文代码参考hello+world+helloworldh+helloworldfeign+track这5个项目
sleuth+elk聚合日志
sleuth配置- 在微服务项目引入下列依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency>
配置文件
application.yml增加
logging: level: root: INFO org.springframework.web.servlet.DispatcherServlet: DEBUG org.springframework.cloud.sleuth: DEBUG
依次启动
hello项目和
helloworld项目,在浏览器输入
http://localhost:8020/message后两个项目的控制台输出如下日志
![](http://upload-images.jianshu.io/upload_images/6944619-e9069c441e6488e6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](http://upload-images.jianshu.io/upload_images/6944619-36f199dabedd9c16.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
其中
a7c81616d25c1a88是TraceId,后面跟着的是SpanId,依次调用有一个全局的TraceId,将调用链路串起来。
查看日志文件并不是一个很好的方法,当微服务越来越多日志文件也会越来越多,通过ELK可以将日志聚合,并进行可视化展示和全文检索。
sleuth配合elk使用
ELK是一款日志分析系统,它是
Logstash+
ElasticSearch+
Kibana的技术组合,它可以通过logstash收集各个微服务日志,并通过Kibana进行可视化展示,而且还可以对大量日志信息通过ElasticSearch进行全文检索。
![](http://upload-images.jianshu.io/upload_images/6944619-a82676d1f24a531a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
操作步骤:
- 安装ELK,我使用了docker安装了ELK,具体安装步骤可参考这篇文章:
[Docker ElK安装部署使用教程](http://www.cnblogs.com/soar1688/p/6849183.html)
区别是在启动logstash时,指定了日志来源路径
/opt/logstash/bin/logstash -e 'input { file { codec => json path => "/opt/build/*.json" } } output { elasticsearch { hosts => ["localhost"] } }'
项目添加依赖
<dependency> <groupId>net.logstash.logback</groupId> <artifactId>logstash-logback-encoder</artifactId> <version>4.9</version> </dependency>
在src/java/resources目录下新建logback-spring.xml,配置如下内容
<?xml version="1.0" encoding="UTF-8" ?> <configuration> <include resource="org/springframework/boot/logging/logback/defaults.xml"/> <springProperty scope="context" name="springAppName" source="spring.application.name"/> <property name="LOG_FILE" value="${BUILD_FOLDER:-build}/${springAppName}"/> <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/> <!-- 控制台输出 --> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>DEBUG</level> </filter> <encoder> <pattern>${CONSOLE_LOG_PATTERN}</pattern> </encoder> </appender> <!-- 按照每天生成日志文件 --> <appender name="filelog" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_FILE}</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!--日志文件输出的文件名--> <FileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.gz</FileNamePattern> <!--日志文件保留天数--> <MaxHistory>7</MaxHistory> </rollingPolicy> <encoder> <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> <pattern>${CONSOLE_LOG_PATTERN}</pattern> </encoder> <!--日志文件最大的大小--> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <MaxFileSize>10MB</MaxFileSize> </triggeringPolicy> </appender> <!-- 使用json格式保存日志文件 --> <appender name="jsonlog" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_FILE}.json</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!--日志文件输出的文件名--> <FileNamePattern>${LOG_FILE}.json.%d{yyyy-MM-dd}.gz</FileNamePattern> <!--日志文件保留天数--> <MaxHistory>7</MaxHistory> </rollingPolicy> <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder"> <providers> <timestamp> <timeZone>UTC</timeZone> </timestamp> <pattern> <pattern> { "severity": "%level", "service": "${springAppName:-}", "trace": "%X{X-B3-TraceId:-}", "span": "%X{X-B3-SpanId:-}", "parent": "%X{X-B3-ParentSpanId:-}", "exportable": "%X{X-Span-Export:-}", "pid": "${PID:-}", "thread": "%thread", "class": "%logger{40}", "rest": "%message" } </pattern> </pattern> </providers> </encoder> <!--日志文件最大的大小--> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <MaxFileSize>10MB</MaxFileSize> </triggeringPolicy> </appender> <root level="INFO"> <appender-ref ref="console"/> <appender-ref ref="jsonlog"/> <appender-ref ref="filelog"/> </root> </configuration>
因为上面的日志文件用到spring.application.name,所以需要项目名称的配置挪到bootstrap.yml。
- 测试结果,在浏览器输入
http://localhost:8020/message发起几次调用后,打开
http://localhost:5601后看到上述的Kibana页面,说明可以正常使用ELK查询,分析跟踪日志。
sleuth 结合zipkin
通过查看日志分析微服务的调用链路并不是一个很直观的方案,结合zipkin可以很直观地显示微服务之间的调用关系。![](http://upload-images.jianshu.io/upload_images/6944619-44715639e9d77dcb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](http://upload-images.jianshu.io/upload_images/6944619-5c897960a2ae93f7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](http://upload-images.jianshu.io/upload_images/6944619-7700a7b9707d1e03.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
通过zipkin可以将调用链路可视化显示。
下面讲解配置步骤:
服务端zipkin-server配置
新建项目track,并引入依赖
<dependency> <groupId>io.zipkin.java</groupId> <artifactId>zipkin-server</artifactId> </dependency> <dependency> <groupId>io.zipkin.java</groupId> <artifactId>zipkin-autoconfigure-ui</artifactId> </dependency>
启动类添加
@EnableDiscoveryClient和
@EnableZipkinServer注解
配置文件
application.yml
spring: application: name: sleuth-server server: port: 9411 eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ instance: instanceId: ${spring.application.name}:${spring.cloud.client.ipAddress}:${server.port}
以上服务端就搭建好了
客户端整合zipkin步骤
客户端添加依赖<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency>
配置文件添加
spring: zipkin: base-url: http://127.0.0.1:9411 sleuth: sampler: percentage: 1.0
指定了zipkin server的地址,下面制定需采样的百分比,默认为0.1,即10%,这里配置1,是记录全部的sleuth信息,是为了收集到更多的数据(仅供测试用)。在分布式系统中,过于频繁的采样会影响系统性能,所以这里配置需要采用一个合适的值。
zipkin改进
在这里对zipkin进行改进,主要包含两方面- 通过消息中间件收集sleuth数据
- 持久化sleuth数据
1、通过消息中间件收集sleuth数据
通过消息中间件可以将zipkin server和微服务解耦,微服务无需知道zipkin server地址,只需将sleuth数据传入消息中间件。同时,也可以解决zipkin server与微服务网络不通情况。
改造服务端
- 修改zipkin server(trace项目)配置
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-zipkin-stream</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream-binder-rabbit</artifactId> </dependency> <!-- <dependency> <groupId>io.zipkin.java</groupId> <artifactId>zipkin-server</artifactId> </dependency>--> <dependency> <groupId>io.zipkin.java</groupId> <artifactId>zipkin-autoconfigure-ui</artifactId> </dependency>
配置文件application.yml增加
rabbitmq: host: localhost port: 5673 username: guest password: guest
这是sleuth数据来源
- 启动类
@EnableZipkinServer改为
@EnableZipkinStreamServe
以上服务端改造完毕,下面改造客户端(以
helloworld-feign项目为例)
改造客户端
以
helloworldfeign项目为例
- 修改依赖
<!-- 使用消息中间件后,不再直接和zipkin server--> <!-- <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency>--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-stream</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream-binder-rabbit</artifactId> </dependency>
配置文件增加
spring: rabbitmq: host: localhost port: 5673 username: guest password: guest
并删除下面指向zipkin server的配置
spring: zipkin: base-url: http://127.0.0.1:9411[/code]
这样就完成了客户端的配置,依次启动track和helloworldfeign项目,通过http://localhost:8030/message调用其他服务后,在zipkin server 成功获取了helloworldfeign的sleuth数据。
在以上的过程中,只要重启zipkin server,发现之前的数据丢失。这是因为zipkin server获取的数据是放在内存的,我们可以获取的服务追踪数据放入到ElasticSearch
2、持久化sleuth数据
- 修改依赖<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-zipkin-stream</artifactId> </dependency> <!-- 持久化到ElasticSearch--> <!--<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency>--> <dependency> <groupId>io.zipkin.java</groupId> <artifactId>zipkin-autoconfigure-storage-elasticsearch-http</artifactId> <version>1.29.2</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream-binder-rabbit</artifactId> </dependency> <dependency> <groupId>io.zipkin.java</groupId> <artifactId>zipkin-autoconfigure-ui</artifactId> </dependency>
配置文件增加zipkin: storage: type: elasticsearch elasticsearch: cluster: elasticsearch hosts: http://localhost:9200 index: zipkin index-shards: 5 index-replicas: 1
再次启动track项目后,可以将数据持久化到elasticsearch。
相关文章推荐
- 使用Zipkin和Brave 实现dubbo服务调用跟踪
- 使用Zipkin 和 Brave 实现http(springmvc)服务调用跟踪(二)
- 使用Zipkin和Brave 实现dubbo服务调用跟踪
- 使用Zipkin 和 Brave 实现http(springmvc)服务调用跟踪(一)
- 使用各种 ESB 实现灵活的服务连接性
- 在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(二)----使用方法
- 使用开放源代码框架的 Java 应用程序的 Web 服务集成模式,第 1 部分: 实现调用模式
- C#使用异步Socket实现TCP网络服务的CS的通讯构架(二)使用方法
- 使用开放源代码框架的 Java 应用程序的 Web 服务集成模式,第 2 部分: 实现接收模式
- 在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(二)----使用方法
- 完成了WF工作流持久化和对持久化介质数据的加载, 但是仅仅用持久化,不能够保存工作流当前的执行状态,需要跟踪服务支持,怎样使用Tracing 服务呢?
- C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(一)
- SOA服务的基本实现方法—使用HTTP协议传输XML请求(POX-over-HTTP)
- 使用 WebSphere Service Registry and Repository 实现和执行服务生命周期
- 在ASP.NET AJAX中使用应用程序服务和本地化(2):示例程序:实现用户登录和注销
- PHP网页服务实现注册和商店NPC管理(安装+搭建+使用+问题处理)
- 在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(一)----基础类库部分
- 使用终端服务 实现网络远程连接
- 在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(一)----基础类库部分
- 【转】在windows 2000中使用Bind实现域名服务