详解最新链路追踪skywalking框架介绍、架构、环境本地部署&配置、整合微服务springcloudalibaba 、日志收集、自定义链路追踪、告警等

1.skywalking介绍

  • 多种监控手段,可以通过语言探针和service mesh 获得监控数据
  • 支持多种语言自动探针,包含java/net/nodejs
  • 轻量高效,无需大数据平台和大量的服务器资源
  • 模块化,UI、存储、集群管理都有多种机制可选
  • 支持告警
  • 优秀的可视化解决方案

整体架构

  • 上部分 Agent :负责从应用中收集链路信息,发送给SkyWalking OAP服务器,目前支持SkyWalking、Zikpin、Jaeger等提供的Tracing 数据信息。而目前采用的是SkyWalking Agent收集 SkyWalking Tracing数据,传递给服务器

  • 下部分SkyWalking OAP :负责接收Agent发送的Tracing数据信息,然后进行分析(Analysis Core) ,存储到外部存储器(Storage ),最终提供查询( Query )功能

  • 右部分 Storage :Tracing 数据存储。目前支持ES、MySQL、Sharding Sphere、TiDB、H2多种存储器,目前采用的是 ES ,主要考虑是 SkyWalking 开发团队自己的生产环境采用 ES 为主

  • 左部分 SkyWalking UI :负责提供控台,查看链路等等

skywalking demo

默认登录账户: skywalking skywalking

https://demo.skywalking.apache.org/

资料

官网:https://skywalking.apache.org/

下载 skywalking本地安装包:

https://skywalking.apache.org/downloads/

文档:https://skywalking.apache.org/docs/#SkyWalking

github: https://github.com/apache/skywalking

https://skywalking.apache.org/docs/main/latest/en/setup/backend/backend-setup/#applicationyml

  1. SkyWalking 环境搭建部署(单机版)


1.安装elasticSearch

  • 参考之前博文安装&启动

    elasticsearch.bat 或者elasticsearch.sh启动服务

  • 访问默认地址:http://localhost:9200/

2.搭建skywalking 服务

  • 下载skywalking 安装包

    对于 SkyWalking 的软件包,有两种方式获取:

    • 手动编译
    • 官方包 (建议官方包,bug少)
  • 修改 skywalking config目录application.yml配置

  • 修改skywalking 安装目录中的webapp目录中的webapp.yml配置

  • 启动skywalking server &webapp 执行如下命令:

    备注说明:如果启动有问题,可以查看日志

  • skywalking ui访问地址:

    默认 http://localhost:8080

    3.启动一个 Spring Boot 应用,并配置 SkyWalking Agent

首先,下载skywalking agent 包如下:


其次,启动探针

通过探针方式配置微服务链路追踪*

properties 复制代码
   java -javaagent:/path/to/skywalking-agent.jar \
     -Dskywalking.agent.service_name=order-service \
     -Dskywalking.collector.backend_service=localhost:11800 \
     -jar order-service.jar

linux启动

idea中配置探针

properties 复制代码
#设置skywalking-agent.jar路径
-javaagent:D:\resource\skywalking\skywalking-agent\skywalking-agent.jar
#在skywalking上显示微服务名称
-DSW_AGENT_NAME=wemedia-oss-user
#skywalking的collector服务的ip以及端口
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=localhost:11800

启动服务之后,调用服务api:http://127.0.0.1:8889/api/user/vipRecharge ,在skywalking ui上查看服务如下:

查看拓扑图如下:

发现拓扑图不显示gateway服务 ,分析这是skywalking的bug,解决方法:
到agent optional-plugins目录下 复制最新的gateway lib到agent plugins目录里

重启skywalking

重启微服务

重新访问接口微服务:http://127.0.0.1:8889/api/user/vipRecharge

再次访问skywalking ui:

3.skywalking 日志收集

  1. 引入skywalking日志收集依赖

    xml 复制代码
        <!--skywalking 日志收集,引入工具类-->
            <dependency>
                <groupId>org.apache.skywalking</groupId>
                <artifactId>apm-toolkit-logback-1.x</artifactId>
                <version>9.3.0</version>
            </dependency>
  2. 调整logback-spring.xml

    xml 复制代码
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration scan="true" scanPeriod=" 5 seconds">
    
        <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径,请根据需求配置路径-->
        <springProperty scope="context" name="log.path" source="path.log"/>
        <springProperty scope="context" name="app.anme" source="spring.application.name"/>
    
        <property name="app.name" value="${app.anme}"/>
    
        <!-- 业务日志路径-->
        <property name="logging.path" value="${log.path}"/>
        <!-- 系统日志路径-->
        <property name="system.log" value="system"/>
        <!-- 日志保存时间(天) -->
        <property name="log.save.time.day" value="30"/>
    
    
        <!-- 彩色日志依赖的渲染类 -->
        <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
        <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
        <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
        <!-- 彩色日志格式 -->
        <property name="CONSOLE_LOG_PATTERN"
                  value="${app.name} >> ${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}]){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(LN:%L){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" />
    
        <!-- 控制台输出 -->
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
                <!--把控制台的日志输出到sKywalking-->
                <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
                    <pattern>${CONSOLE_LOG_PATTERN}</pattern>
                </layout>
                <!--            <pattern>${CONSOLE_LOG_PATTERN}</pattern>-->
                <charset>utf8</charset>
            </encoder>
        </appender>
    
    
        <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
            <discardingThreshold>0</discardingThreshold>
            <queueSize>1024</queueSize>
            <neverBlock>true</neverBlock>
            <appender-ref ref="STDOUT"/>
        </appender>
    
    
        <!--skywalking日志上报-->
        <appender name="grpc-log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
            <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
                <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
                    <pattern>${CONSOLE_LOG_PATTERN}</pattern>
                </layout>
                <charset>utf8</charset>
            </encoder>
        </appender>
    
    
        <!-- 按照每天生成日志文件 -->
        <appender name="FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${log.path}/sys-info.log</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--日志文件输出的文件名-->
                <FileNamePattern>${log.path}/sys-info-%d{yyyy-MM-dd}.log</FileNamePattern>
                <!--日志文件保留天数-->
                <MaxHistory>${log.save.time.day}</MaxHistory>
            </rollingPolicy>
            <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
                <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
                    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n</pattern>
                </layout>
            </encoder>
        </appender>
    
        <!-- 系统错误日志 -->
        <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${log.path}/sys-error.log</file>
            <!-- 循环政策:基于时间创建日志文件 -->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!-- 日志文件名格式 -->
                <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
                <!-- 日志最大的历史 60天 -->
                <maxHistory>${log.save.time.day}</maxHistory>
            </rollingPolicy>
            <encoder>
                <pattern>${log.pattern}</pattern>
            </encoder>
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <!-- 过滤的级别 -->
                <level>ERROR</level>
                <!-- 匹配时的操作:接收(记录) -->
                <onMatch>ACCEPT</onMatch>
                <!-- 不匹配时的操作:拒绝(不记录) -->
                <onMismatch>DENY</onMismatch>
            </filter>
        </appender>
    
        <!-- 显示形成的sql、使用的参数、结果集 生产环境需要删掉 -->
        <logger name="java.sql" level="debug"/>
        <logger name="org.springframework.jdbc" level="debug"/>
    
        <!-- 日志输出级别  ,注意:如果不写<appender-ref ref="FILE" /> ,将导致springbootadmin找不到文件,无法查看日志 -->
        <root level="INFO">
            <appender-ref ref="grpc-log" />
            <appender-ref ref="ASYNC" />
            <appender-ref ref="FILE"/>
        </root>
    
    </configuration>

备注说明: [%X{tid}] :添加skywalking 追踪id,方便追踪整个调用链路

  1. 访问接口,查看skywalking ui log界面,日志正常显示如下:

4.skywalking 自定义链路追踪

  • 自定义链路追踪主要是为了对项目中的业务方法,实现链路追踪,方便排查问题

  • 引入依赖

    xml 复制代码
     <!--自定义skywalking链路,引入工具类-->
            <dependency>
                <groupId>org.apache.skywalking</groupId>
                <artifactId>apm-toolkit-trace</artifactId>
                <version>9.3.0</version>
            </dependency>
  • 自定义链路
    方法1:使用@Trace注解在要追踪的接口上,只需要记录方法的出参 ,入参;如果要打印返回结果,一定要重写返回结果toString()方法,不然返回对象的地址

​ 加入@Tags或@Tag记录参数和返回信息

​ @Tag注解中key= 方法名 value= returnedObj 返回值 arg[0] 参数

java 复制代码
/***
*controller方法
*/

@GetMapping("/vipRecharge")
    public CommonResult<String> vipReCharge() {

        userService.vipReCharge("123");
        return CommonResult.success("vip用户充值成功!");
    }


/***
* servrice方法
*/
 
   @Trace
   @Tags({@Tag(key = "vipReCharge",value = "returnedObj"),
   @Tag(key = "vipReCharge",value = "arg[0]")
   })
 @SentinelResource(value = "vipReCharge",blockHandler ="vipReChargeFallback" )
    @Override
    public CommonResult<String> vipReCharge(String num) {
        List<TUser> userList=tUserMapper.selectAll();
        System.out.println("userList:"+userList.size());
        CommonResult<String> result=payFeignApi.callWechatPay();
        System.out.println("调用第三方payFeignApi.callWechatPay 返回结果:"+result);
        return CommonResult.success("调用支付服务成功!");
    }

再次查看skywalking链路追踪trace,发现上面该方法已经被加载进链路中

增加Tags之后, 查看方法请求和返回值

方法2:编码的方式,适合逻辑比较多,多个地方需要记录一些参数或关键信息,info,debug 或堆栈日志等

使用skywalking 的 ActiveSpan.error(); ActiveSpan.info();ActiveSpan.debug()等在需要追踪的关键地方记录日志

java 复制代码
    @GetMapping("/callWechatPay")
    public CommonResult<String> callWechatPay(HttpServletRequest request) {
        log.info("X-Token value:"+request.getHeader("X-Token"));

        ActiveSpan.tag("PayController.callWechatPay()","调用支付controller中callWechatPay()方法!");


        try {
            //模拟异常情况:
            int i=10/0;
//            TimeUnit.SECONDS.sleep(2);
        } catch (Exception e) {
            //ActiveSpan.error();//skywalking追踪事件为error级别 或debug或info级别
           // ActiveSpan.error("是除零异常");//错误message
            ActiveSpan.error(new RuntimeException("是除零异常"));
           // throw new RuntimeException(e);
        }
        return CommonResult.success("调用微信支付成功!");
    }

再次查看skywalking ui结果如下:

方法3 使用OpenTracing Java API定义链路追踪

  1. 在pom文件中引入依赖

    xml 复制代码
     <dependency>
                <groupId>org.apache.skywalking</groupId>
                <artifactId>apm-toolkit-opentracing</artifactId>
                <version>9.3.0</version>
            </dependency>
  2. 在代码中增加自定义的链路追踪代码,最后一定要进行finish,否则也收集不到信息。

    java 复制代码
    //在service中增加自定义链路追踪代码 
    
    @Override
        public CommonResult<String> vipReCharge(String num) {
            //在代码中使用opentracing代码自定义链路追踪
            Tracer tracer=new SkywalkingTracer();
            Tracer.SpanBuilder spanBuilder=tracer.buildSpan("UserServiceImpl.vipRecharge(String num)方法");
            Span span=spanBuilder.withTag("startTag",false).startManual();
    
            List<TUser> userList=tUserMapper.selectAll();
            System.out.println("userList:"+userList.size());
            CommonResult<String> result=payFeignApi.callWechatPay();
            System.out.println("调用第三方payFeignApi.callWechatPay 返回结果:"+result);
            
            span.log("调用第三方payFeignApi.callWechatPay 返回结果:"+result);
            span.finish();
            return CommonResult.success("调用支付服务成功!");
        }
  3. 查看结果如下:

5.skywalking 告警

配置告警接口:

实现高级接口nofity或go-wechat

6.参考资料

相关推荐
lxsy几秒前
spring-ai-alibaba-deepresearch 学习(十三)——ResearcherNode
java·源码分析·deepresearch·ai-alibaba
曾经的三心草21 分钟前
微服务的编程测评系统22-项目部署结束
微服务·云原生·架构
ShineWinsu21 分钟前
对于单链表相关经典算法题:206. 反转链表及876. 链表的中间结点的解析
java·c语言·数据结构·学习·算法·链表·力扣
迦蓝叶26 分钟前
JAiRouter 配置文件重构纪实 ——基于单一职责原则的模块化拆分与内聚性提升
java·网关·ai·重构·openai·prometheus·单一职责原则
ST.J29 分钟前
系统架构思考20241204
java·笔记·系统架构
TDengine (老段)1 小时前
TDengine 时间函数 TIMETRUNCATE 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
给我个面子中不2 小时前
JUC、JVM八股补充
java·开发语言·jvm
mask哥2 小时前
详解flink性能优化
java·大数据·微服务·性能优化·flink·kafka·stream
hqxstudying2 小时前
Kafka 深入研究:从架构革新到性能优化的全面解析
java·开发语言·微服务·kafka·springcloud
失散134 小时前
并发编程——17 CPU缓存架构详解&高性能内存队列Disruptor实战
java·缓存·架构·并发编程