Java微服务全链路日志监控

351 阅读3分钟

什么是全链路日志监控

微服务全链路日志监控是指在分布式微服务架构中,对多个微服务应用之间的调用关系进行监控的一种方法。这种监控可以理解为对代码的调用进行监控,其目的是在出现问题时,能够通过可视化界面快速定位和解决问题。

在微服务架构中,系统为了接收并处理一个前端用户请求,需要多个微服务应用协同工作。这些微服务应用可能使用不同的编程语言构建,由不同的团队开发,并分布在多台服务器上。单个用户请求会经过多个微服务,相互之间形成复杂的调用关系。因此,传统的监控手段已经不能实现如此复杂的链路之间的监控,需要一些可以帮助理解系统行为、用于分析性能问题的工具。

全链路监控就是其中的一种方法,它对微服务之间的调用关系进行监控,了解每个应用如何调用。这样可以实现对整个微服务链路的监控,从用户请求到各个微服务的调用过程都可以被监控到。

什么是traceId

全链路日志的traceId是一种分布式全局唯一id标识,由系统第一个被调起的模块生成,并在各个span间传递。通过spanId和traceId可以定位到具体的模块的一次请求。

在微服务架构中,由于系统调用链路长且复杂,使用traceId可以帮助快速定位问题。当出现问题时,通过查看日志中traceId的调用链路,可以迅速找到问题所在,提高排错效率。

单应用日志链路监控

单应用的日志链路监控实现比较简单,本文就不做赘述了。可自行百度 “ Spring Boot+MDC 实现全链路调用日志跟踪” 。本文主要解决如下两个问题

  • 异步线程,如何保障 tradeId 的传递
  • 跨微服务,如何保障 tradeId 的传递

异步线程,如何保障 tradeId 的传递

当我们在应用中使用线程池时,会发现tradeId未按照预期进行传递。当主线程第一次设置traceId后,线程池线程再次被复用时,仍是首次设置的traceId。

image.png

使用 TestThreadPoolExecutor 解决这个问题,代码如下。可以发现,每次循环请求,线程池线程被复用时,都可以获取到主线程设置的 traceId

import com.alibaba.ttl.threadpool.TtlExecutors;

public class TestThreadPoolExecutor {

    ExecutorService executorService;

    public TestThreadPoolExecutor(int i, int i1, long l, TimeUnit timeUnit, BlockingQueue<Runnable> blockingQueue) {
        executorService = TtlExecutors.getTtlExecutorService(new ThreadPoolExecutor(i, i1, l, timeUnit, blockingQueue));
    }

    public TestThreadPoolExecutor(int i, int i1, long l, TimeUnit timeUnit, BlockingQueue<Runnable> blockingQueue, ThreadFactory threadFactory) {
        executorService = TtlExecutors.getTtlExecutorService(new ThreadPoolExecutor(i, i1, l, timeUnit, blockingQueue, threadFactory));
    }

    public TestThreadPoolExecutor(int i, int i1, long l, TimeUnit timeUnit, BlockingQueue<Runnable> blockingQueue, RejectedExecutionHandler rejectedExecutionHandler) {
        executorService = TtlExecutors.getTtlExecutorService(new ThreadPoolExecutor(i, i1, l, timeUnit, blockingQueue, rejectedExecutionHandler));
    }

    public TestThreadPoolExecutor(int i, int i1, long l, TimeUnit timeUnit, BlockingQueue<Runnable> blockingQueue, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
        executorService = TtlExecutors.getTtlExecutorService(new ThreadPoolExecutor(i, i1, l, timeUnit, blockingQueue, threadFactory, rejectedExecutionHandler));
    }


    public ExecutorService getExecutorService() {
        return executorService;
    }

    public void setExecutorService(ExecutorService executorService) {
        this.executorService = executorService;
    }
}

image.png

TtlExecutors源码分析

跨微服务,如何保障 tradeId 的传递

Dubbo调用源码分析