编程的魅力
首页
分类
标签
归档
动态
关于我
hyuga
2021-06-17
335
2021-06-23 16:05:26
原创
spring-cloud-starter-sleuth微服务链路日志ID
# 背景 多个微服务之间调用,日志无法串联,排查问题难度大。 需要一个链路ID贯穿所有服务日志。 # sleuth ## 什么是分布式服务跟踪系统 分布式服务跟踪是整个分布式系统中跟踪一个用户请求的过程(包括数据采集、数据传输、数据存储、数据分析、数据可视化),捕获此类跟踪让我们构建用户交互背后的整个调用链的视图,这是调试和监控微服务的关键工具。Spring Cloud Sleuth是Spring Cloud为分布式服务跟踪提供的解决方案,有了它,我们可以: - 提供链路追踪,故障快速定位:可以通过调用链结合业务日志快速定位错误信息。 - 可视化各个阶段耗时,进行性能分析 - 各个调用环节的可用性、梳理服务依赖关系以及优化 - 数据分析,优化链路:可以得到用户的行为路径,汇总分析应用在很多业务场景。 ## 引入 ```xml
org.springframework.cloud
spring-cloud-starter-sleuth
``` ## 日志打印 ```xml
#HYUGA# [%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] %highlight(%-5level) %cyan(%logger{50}-%line) [${sleuth:-},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}] %msg #e_logger#%n
``` 具体的网上一堆文章,就不贴了。 可以自行查询`traceId` `spanId` `sleuth` `export`,每个日志信息。 这样配置完代码中各服务的日志,只要是同一个请求的,`traceId`都是一样的,利于排查日志问题。 ## 特别注意 需要特别注意的有线程池的问题,引入sleuth后,子线程的日志是打印不出traceId相关信息,需要封装一层线程池。 代码如下: ```java @ComponentScan(basePackageClasses = HyugaSpringBeanPicker.class) public class SleuthThreadConfig { @Resource private BeanFactory beanFactory; public static final String THREAD_FACTORY_NAME = "HYUGA-SLEUTH-THREAD-POOL-%d"; public static final String THREAD_SCHEDULED_FACTORY_NAME = "HYUGA-SLEUTH-SCHEDULED-THREAD-POOL-%d"; public static final String THREAD_COMPLETION_FACTORY_NAME = "HYUGA-SLEUTH-COMPLETION-THREAD-POOL-%d"; @Bean(name = SleuthThreadPool.SLEUTH_EXECUTOR_SERVICE) public ExecutorService sleuthExecutorService() { // 定义线程工厂名称 final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(THREAD_FACTORY_NAME).build(); // 定义工作队列:有边界阻塞队列,边界值为【Integer.MAX_VALUE】 final LinkedBlockingQueue
workQueue = new LinkedBlockingQueue<>(); // 中止政策 ThreadPoolExecutor.AbortPolicy abortPolicy = new ThreadPoolExecutor.AbortPolicy(); HyugaThreadPoolExecutor hyugaThreadPoolExecutor = new HyugaThreadPoolExecutor(10, 20, 60L, TimeUnit.SECONDS, workQueue, threadFactory, abortPolicy); return new TraceableExecutorService(this.beanFactory, hyugaThreadPoolExecutor); } @Bean(name = SleuthThreadScheduledPool.SLEUTH_SCHEDULED_EXECUTOR_SERVICE) public ScheduledExecutorService sleuthScheduledExecutorService() { // 定义线程名称 ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(THREAD_SCHEDULED_FACTORY_NAME).build(); ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10, threadFactory); return new TraceableScheduledExecutorService(this.beanFactory, scheduledExecutorService); } @Bean(name = SleuthCompletionServicePool.SLEUTH_COMPLETION_EXECUTOR_SERVICE) public ExecutorService sleuthCompletionExecutorService() { // 定义线程名称 ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(THREAD_COMPLETION_FACTORY_NAME).build(); ExecutorService completionExecutorService = Executors.newFixedThreadPool(5, threadFactory); return new TraceableScheduledExecutorService(this.beanFactory, completionExecutorService); } ``` ```java ExecutorService executorService = (ExecutorService) HyugaSpringBeanPicker.getApplicationContext().getBean(SLEUTH_EXECUTOR_SERVICE); executorService.submit(() -> {}); ``` 项目启动类引入`SleuthThreadConfig.class`
标签:
JAVA
评论
发布
留言
评论