分布式日志追踪的最佳实践1(代码片段)

keep-go-on keep-go-on     2023-02-27     191

关键词:

分布式日志追踪

分布式环境中无可避免的需要做微服务之间的调用,这导致追踪到整个的业务流程变得麻烦。分布式日志追踪解决了那些问题:

  1. 分布式的性能优化。通过日志追踪可以看出各个环境,各个服务消耗的时间,为性能优化定位问题。
  2. 追踪业务流程。通过链路追踪码,可以追踪到业务发生的整体流程。
  3. 异常追踪。但服务发生异常时,服务可以通过埋点的方式收集追踪码,从而定位问题。

适用范围

框架除Gateway外全部采用Servlet,本文代码不适用与WebFlux等非阻塞模型。

框架采用了PlumeLog分布式框架,因此在工具类中使用了PlumeLog的工具类。

如何在主流的微服务框架中实现日志追踪 ?

本文以使用FeignRestTemplate进行微服务直接调用的案例作为实例,如下图:

图中是一个比较常见的服务调用案例,在请求在各个微服务模块中传递时,我们可以通过服务的拦截器对请求添加标识(链路追踪码),标记请求的流转过程。在微服务模块中需要对业务处理流程添加标识,这样标识就标记了本次请求的整个生命周期。

具体的请求顺序对应的操作如下:

  1. 前端向网关发起请求。
  2. 网关对请求添加标记(一般放到请求头中),然后调用微服务1。具体见下方 :Servlet日志追踪
  3. 微服务1在Servlet拦截器中拦截请求,并从请求中获取标记,同时将标记标记当前线程,然后通过Feign调用微服务2,这时触发Feign拦截器,拦截器见标记添加到请求中,发送给下个微服务。具体见下方 :Servlet日志追踪Feign的日志追踪
  4. 微服务2接到请求后,同样接收标记并应用,随后通过RestTemplate调用微服务3,这时触发RestTemplate拦截器,拦截器见标记添加到请求中,发送给下个微服务。具体见下方 :Servlet日志追踪RestTemplate的日志追踪
  5. 微服务3接到请求后,同样接收标记并标记业务流程,处理完成后返回给微服务2
  6. 微服务2接到返回后,继续处理业务,完成后返回给微服务1
  7. 微服务1完成业务后,返回给网关
  8. 网关将请求结果返回给前端

Feign的日志追踪

Feign的日志追踪可以通过Feign的拦截器进行处理,如下:

import feign.RequestInterceptor;
import feign.RequestTemplate;
public class FeignTraceRequestInterceptor implements RequestInterceptor 
    @Override
    public void apply(RequestTemplate requestTemplate) 
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        RequestContextHolder.setRequestAttributes(attributes, true);
        if(ObjectUtil.isNull(attributes)) 
            return;
        
        HttpServletRequest request = attributes.getRequest();
        String traceId = request.getHeader(TraceUtil.TRACE_NAME);
        traceId = StringUtils.isBlank(traceId) ? TraceUtil.get() : traceId;
        traceId = StringUtils.isBlank(traceId) ? TraceUtil.getTraceId() : traceId;
        // 如果追踪码不是空白就传递
        requestTemplate.header(TraceUtil.TRACE_NAME,traceId);
    

当feign调用时,拦截器会拦截到Feign的请求 :

  1. 首先我们从请求中获取追踪码。有可能追踪码来源于上一个服务的请求。
  2. 如果追踪码为空,就中线程中(业务流程中)获取当前追踪码。
  3. 如果追踪码还是空,就新创建一个追踪码。
  4. 最后将追踪码放到请求头中,传递给下个服务。

应用Feign拦截器

首先,声明Feign配置:

public class FeignHeaderConfig
    @Bean
    public RequestInterceptor requestInterceptor()
        return new FeignBasicAuthRequestInterceptor();
    
    @Bean
    public FeignTraceRequestInterceptor FeignTraceRequestInterceptor()
        return new FeignTraceRequestInterceptor();
    

声明配置器时需要将写的拦截器注入到配置

然后应用配置:

@FeignClient(value = "feign-test-service",configuration = FeignHeaderConfig.class)

RestTemplate的日志追踪

RestTemplate的日志追踪同样使用拦截器处理:

import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
public class RestTraceInterceptor implements ClientHttpRequestInterceptor 

    @Override
    public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException 
        // 从头里获取追踪码
        String traceId = TraceUtil.getTraceId(httpRequest);
        // 如果追踪码是个空,就从 线程里去追踪码
        traceId = StringUtils.isBlank(traceId) ? TraceUtil.get() : traceId;
        // 如果线程追踪码还是空,就创建新的追踪码
        traceId = StringUtils.isBlank(traceId) ? TraceUtil.getTraceId() : traceId;
        // 请求头传递参数
        httpRequest.getHeaders().add(TraceUtil.TRACE_NAME, traceId);
        // 保证请求继续被执行
        return clientHttpRequestExecution.execute(httpRequest, bytes);
    

当RestTemplate调用时,拦截器会拦截到请求 几乎和Feign一致:

  1. 首先我们从请求中获取追踪码。有可能追踪码来源于上一个服务的请求。
  2. 如果追踪码为空,就中线程中(业务流程中)获取当前追踪码。
  3. 如果追踪码还是空,就新创建一个追踪码。
  4. 最后将追踪码放到请求头中,传递给下个服务。

应用RestTemplate拦截器

在创建RestTemplate时,声明使用拦截器即可:

@Configuration
public class MyLoadBalanceConfig 
    @Bean
    public RestTraceInterceptor restTraceInterceptor()
        return new RestTraceInterceptor();
    
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate()
        RestTemplate restTemplate =  new RestTemplate();
        restTemplate.setInterceptors(Collections.singletonList(restTraceInterceptor()));
        return restTemplate;
    

如果在分布式环境中必须要加上 @LoadBalanced 注解,否则服务使用服务名进行调用。

Servlet中日志追踪

同样,在servlet中以旧使用Servlet拦截器处理:

import com.kgo.trace.utils.TraceUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TraceInterceptor extends HandlerInterceptorAdapter 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception 
        // 从请求中获取追踪码
        String traceId = TraceUtil.getTraceId(request);
        // 如果追踪码是个空,就从 线程里去追踪码
        traceId = StringUtils.isBlank(traceId) ? TraceUtil.get() : traceId;
        // 如果线程追踪码还是空,就创建新的追踪码
        traceId = StringUtils.isBlank(traceId) ? TraceUtil.getTraceId() : traceId;
        // 放到线程中
        TraceUtil.set(traceId);
        return true;
    


处理逻辑与RestTemplate和Feign的处理逻辑几乎一致,不再赘述。

应用 Servlet拦截器

这个比较简单,不做赘述:

@Configuration
public class ContractMvcConfig implements WebMvcConfigurer 
    @Override
    public void addInterceptors(InterceptorRegistry registry) 
        registry.addInterceptor(getTraceInterceptor()).addPathPatterns("/**");
    

    @Bean
    public TraceInterceptor getTraceInterceptor() 
        return new TraceInterceptor();
    

如果在分布式环境中必须要加上 @LoadBalanced 注解,否则服务使用服务名进行调用。


日志工具类源码请见下篇分解

java基础学习总结(203)——生成唯一id打印日志记录最佳实践(代码片段)

原因几乎所有的Java项目中的默认日志框架都会选择slf4j,在打印日志时,每行数据都有一个请求ID,这样会方便追踪日志。也可以使用一些链路追踪框架来实现这种目的。实现slf4j里有一个MDC类,是ThreadLocal的实现,保存在这里的... 查看详情

rocketmqxopentelemetry分布式全链路追踪最佳实践

在分布式系统中,多个服务之间的交互涉及到复杂的网络通信和数据传输,其中每个服务可能由不同的团队或组织负责维护和开发。因此,在这样的环境下,当一个请求被发出并经过多个服务的处理后,如果出现了问题或错误,... 查看详情

elasticsearchelasticsearch日志场景最佳实践(代码片段)

1.概述转载:Day12-Elasticsearch日志场景最佳实践相似文章:【Elasticsearch】Elasticsearch最佳实践系列之分片恢复并发故障Elasticsearch可广泛应用于日志分析、全文检索、结构化数据分析等多种场景,大幅度降低维护多套专用... 查看详情

java基础学习总结(203)——生成唯一id打印日志记录最佳实践(代码片段)

原因几乎所有的Java项目中的默认日志框架都会选择slf4j,在打印日志时,每行数据都有一个请求ID,这样会方便追踪日志。也可以使用一些链路追踪框架来实现这种目的。实现slf4j里有一个MDC类,是ThreadLocal的实现,保存在这里的... 查看详情

浅议分布式链路追踪与日志的整合(代码片段)

本文内容.NET中的分布式追踪ActivitySource与Activity.NET与OpenTelemetry分布式追踪和日志整合NLog.DiagnosticSource自定义LayoutRenderer本文小结最近拜读了Artech大佬的新文章《几个Caller-特性的妙用》,可以说是受益匪浅。不过,对我而言,最... 查看详情

(转)java日志框架解析(下)-最佳实践(代码片段)

上一篇文章中,讲了Java常用的日志库以及之间的关系,现在来说说我们在项目中怎么使用日志库。1.总是使用LogFacade,而不是具体LogImplementation正如之前所说的,使用LogFacade可以方便的切换具体的日志实现。而且,如果依赖多个项... 查看详情

分布式链路追踪在数字化金融场景的最佳实践

作者|张冀责编|Carol出品|CSDN(ID:CSDNnews)【CSDN编者按】在以微服务和容器化为主导应用的现代化浪潮下,系统的可观测性变得越来越重要,而链路追踪技术就成为软件系统实现“无人驾驶”的关键手段。本文... 查看详情

serilog最佳实践(代码片段)

Serilog最佳实践概述Serilog[1]是Microsoft.NET的结构化日志记录库,并已成为Checkout.com上NET的首选日志记录库。它支持各种日志记录目的地(称为接收器[2])包从标准控制台和基于文件的接收器到日志服务,如Datadog。本... 查看详情

日志采集最佳实践(代码片段)

概述本文介绍如何利用腾讯云容器服务TKE的日志功能对日志进行采集、存储与查询,分析各种功能用法与场景,给出一些最佳实践建议。注:本文仅适用于TKE集群。如何快速上手?TKE的日志功能入口在集群运维-日志规则,更多关于... 查看详情

浅议分布式链路追踪与日志的整合(代码片段)

本文内容.NET中的分布式追踪ActivitySource与Activity.NET与OpenTelemetry分布式追踪和日志整合NLog.DiagnosticSource自定义LayoutRenderer本文小结最近拜读了Artech大佬的新文章《几个Caller-特性的妙用》,可以说是受益匪浅。不过,对我而言,最... 查看详情

轻量级分布式日志标记追踪神器,十分钟即可接入到项目!(代码片段)

一.TLog简介TLog提供了一种最简单的方式来解决日志追踪问题,它不收集日志,也不需要另外的存储空间,它只是自动的对你的日志进行打标签,自动生成TraceId贯穿你微服务的一整条链路。并且提供上下游节点信息... 查看详情

flinkonyarn实时日志收集最佳实践(代码片段)

...控Flink 最新的模板背景在Flinkonyarn的模式下,程序运行的日志会分散的存储在不同的DN上,当Flink任务发生异常的时候,我们需要查看日志来定位问题,一般我们会选择通过FlinkUI上面的logs来查看日志,或者登录到对 查看详情

最佳实践|什么是好的日志记录实践?(代码片段)

作为软件开发人员,我们在使用某些库或框架时都遇到过那些烦人的、不太有用的错误消息:“无法解析配置文件”、“缺少此操作的权限”等。好的,好的,所以显然出了点问题;但究竟是什么?什么配置文件?哪些权限?你... 查看详情

自实现分布式链路追踪方案&实践

前言:排查问题是程序员的基本能力也是必须要会的,在开发环境,我们可以debug,但是一旦到了服务器上,就很难debug了,最有效的方式就是通过日志揪出bug,而一次请求的日志如果没有一个唯一的链路标识(我们下边称他为trac... 查看详情

guavacache原理分析与最佳实践(代码片段)

...hCache、GuavaCache、Caffeine等。本系列文章会选取本地缓存和分布式缓存(NoSQL)的优秀框架比较他们各自的优缺点、应用场景、项目中的最佳实践以及原理分 查看详情

最佳实践携程clickhouse日志分析实践

ElasticSearch是一种基于Lucene的分布式全文搜索引擎,携程用ES处理日志,目前服务器规模500+,日均日志接入量大约200TB。随着日志量不断增加,一些问题逐渐暴露出来:一方面ES服务器越来越多,投入的成... 查看详情

springcloud-springcloudalibaba之skywalking分布式链路跟踪;跨多服务追踪,集成日志(十五)(代码片段)

一、SkyWalking跨多服务追踪1、关闭防火墙,如果nacos使用MySQL持久化规则,则启动MySQL服务systemctlstopfirewalld2、启动单机版Nacos,浏览器输入http://192.168.133.129:8848/nacos[root@eureka8761~]#cd/opt/software/nacos/bin/[ 查看详情

分布式技术追踪2018年第十四期

分布式系统实践1. 聊聊ChaosEngineering的历史、原则和最佳实践https://mp.weixin.qq.com/s/-8gpUlbmlDDyOf7AqaFdTAhttps://www.jianshu.com/p/c8f78b8db2a0?from=timeline&isappinstalled=0摘要: 混沌工程是进行分布式异常测试的一种有效手段,自Ne 查看详情