Apache SkyWalking入门

Apache SkyWalking是一个开源的应用程序性能监控系统,专注于微服务、云原生和容器环境。其功能包括服务追踪、性能指标分析、依赖关系分析和告警。通过Java Agent或Service Mesh接入微服务,支持多种语言和数据库持久化。SkyWalking提供链路追踪、性能优化和自定义日志集成,同时具备告警功能,确保系统高可用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 介绍

SkyWalking:一个APM(应用程序性能监视器)系统,专门为微服务,云原生和基于容器(Docker,Kubernetes,Mesos)的体系结构而设计。

SkyWalking是一个开源APM系统,包括对Cloud Native体系结构中的分布式系统的监视,跟踪,诊断功能。核心功能如下:

  • 服务,服务实例,端点指标分析
  • 根本原因分析。在运行时分析代码。阅读Apache SkyWalking:使用分析来修复分布式跟踪的盲点。
  • 服务拓扑图分析
  • 服务,服务实例和端点依赖关系分析
  • 检测到慢速服务和端点
  • 性能优化
  • 分布式跟踪和上下文传播
  • 数据库访问指标。检测慢速数据库访问语句(包括SQL语句)。
  • 报警

1.1 SkyWalking是什么

skywalking是一个国产开源框架,2015年由吴晟开源,2017年加入Apache孵化器。skywalking是分布式系统的应用程序性能监视工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。它是一款优秀的APM(Application Perfomance Management)工具,包括了分布式追踪、性能指标分析、应用和服务依赖分析等。

官网
下载
文档
中文文档

1.2 链路追踪框架对比

  1. Zipkin是Twitter开源的调用链分析工具,目前基于springcloud sleuth得到了广泛的使用,特点是轻量,使用部署简单。
  2. Pinpoit是韩国人开源的基于字节码注入的调用链分析,以及应用监控分析工具。特点是支持多种插件,UI功能强大,接入端无代码侵入。
  3. skywalking是本土开源的基于字节码注入的调用链分析,以及应用监控分析工具。特点是支持多种插件,U功能较强,接入端无代码侵入。目前已加入Apache孵化器。
  4. CAT是大众点评开源的基于编码和配置的调用链分析,应用监控分析,日志采集,监控报警等一系列的监控平台工具。

1.3 Skywalking主要功能特性

  1. 多种监控手段,可以通过语言探针和service mesh获得监控的数据;
  2. 支持多种语言自动探针,包括Java,.NET Core和Node.JS;
  3. 轻量高效,无需大数据平台和大量的服务器资源;
  4. 模块化,UI、存储、集群管理都有多种机制可选;
  5. 支持告警;
  6. 优秀的可视化解决方案;

2 环境部署

在这里插入图片描述

  • skywalking agent和业务系统绑定在一起,负责收集各种监控数据
  • Skywalking oapservice是负责处理监控数据的,比如接受skywalking agent的监控数据,并存储在数据库中;接受skywalking webapp的前端请求,从数据库查询数据,并返回数据给前端。Skywalking oapservice通常以集群的形式存在
  • skywalking webapp,前端界面,用于展示数据
  • 用于存储监控数据的数据库,比如mysql、elasticsearch等。

2.1 下载

  • 下载
  • 安装的时候一定要注意安装文件夹不能有空格,否则不能启动。
  • 若出现启动错误可以查看日志分析:logs/skywalking-oap-server

2.2 安装文件目录结果

目录结构

  • web app: Ul前端(web 监控页面)的jar包和配置文件;
  • oap-libs:后台应用的jar包,以及它的依赖jar包,里边有一个server-starter-*.jar就是启动程序;
  • config:启动后台应用程序的配置文件,是使用的各种配置
  • bin:各种启动脚本,一般使用脚本startup.*来启动web页面和对应的后台应用;
    • oapService.:默认使用的后台程序的启动脚本;(使用的是默认模式启动,还支持其他模式,各模式区别见启动模式). oapServicelnit.:使用init模式启动;在此模式下,OAP服务器启动以执行初始化工作,
      然后退出
    • oapServiceNoInit.*:使用no init模式启动;在此模式下,OAP服务器不进行初始化。
    • webappService.*: UI前端的启动脚本;
    • startup.*:组合脚本,同时启动oapService.*脚本;webappService.*脚本;
  • agent:
    • skywalking-agent.jar:代理服务jar包. config:代理服务启动时使用的配置文件
    • plugins:包含多个插件,代理服务启动时会加载改目录下的所有插件(实际是各种jar包)
    • optional-plugins:可选插件,当需要支持某种功能时,比如SpringCloud Gateway,则需要把对应的jar包拷贝到plugins目录下(默认不包含Gateway);

2.3 搭建Skywalking OAP服务

  • 启动脚本bin/startup.bat
  • 日志存储在logs目录 在这里插入图片描述
  • 启动成功后会启动两个服务,一个是skywalking-oap-server,一个是skywalking-web-ui : localhost:8080
    skywalking-oap-server服务启动后会暴露11800和12800两个端口,分别为收集监控数据的端口 11800接受前端请求的端口12800
  • 修改端口可以修改config/applicaiton.yml
  • skywalking-web-ui服务会占用8080端口,修改端口可以修改webapp/webapp.yml
    在这里插入图片描述
  • server.port: SkyWalking UI服务端口,默认是8080;
  • collector.ribbon.listOfServers:SkyWalking OAP服务地址数组,SkyWalking UI界面的数据是通过请求SkyWalking OAP服务来获得;

2.4 SkyWalking中三个概念

  • 服务(Service): 表示对请求提供相同行为的一系列或一组工作负载,在使用Agent时,可以定义服务的名字;
  • 服务实例(Service Instance): 上述的一组工作负载中的每一个工作负载称为一个实例,一个服务实例实际就是操作系统上的一个真实进程;
  • 端点(Endpoint): 对于特定服务所接收的请求路径,如HTTP的URI路径和gRPC服务的类名+方法签名;
    在这里插入图片描述

3.SkyWalking接入微服务

3.1 linux环境—通过jar包方式接入

  • 准备一个spingboot程序,打成可执行jar包,写一个shell脚本,在启动项目的Shel脚本上,通过-javaagent参数进行配置SkyWalking Agent来跟踪微服务;
  • startup.sh脚本:
# Skywalking Agent配置
export SW_AGENT_NAME=springboot-skywalking-demo #Agent名字,一般使用`spring.application.name'
export SW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800 #配置collector地址。
export SW_AGENT_SPAN_LIMIT=2000 #配置链路的最大span数量,默认为300。
export JAVA_AGENT=-javaagent:/usr/local/soft/apache-skywalking-apm-bin-es7/agent/skywalking-agent.jar

java $JAVA_AGENT -jar springboot-skywalking-demo-0.0.1-SNAPSHOT.jar #jar启动

在这里插入图片描述

3.2 windows环境—在IDEA中使用Skywalking

在运行的程序配置jvm参数,如下图所示:
在这里插入图片描述

# skywalking-agent.jar的本地磁盘的路径
-javaagent:D:apache\apache-skywalking-apm-es7-8.4.0\apache-skywalking-apm-bin-es7\agent\skywalking-agent.jar
#在skywalking上显示的服务名
-DSW_AGENT_NAME=tps_service
# skywalking的collector服务的IP及端口
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800

注意: 跟踪链路不显示gateway

  • 拷贝agent/optional-plugins目录下的gateway插件到agent/plugins目录

3.3 Skywalking跨多个微服务跟踪

  • Skywalking跨多个微服务跟踪,只需要每个微服务启动时添加javaagent参数即可。
  • 测试:
    启动微服务mall-gateway,mall-order,mall-user,配置skywalking的jvm参数http://localhost:8888/user/findOrderByUserld/1

4. Skywalking持久化跟踪数据

默认使用的H2数据库存储,configlapplication.yml
在这里插入图片描述

4.1基于mysql持久化:

1.修改config目录下的application.yml,使用mysql作为持久化存储的仓库
在这里插入图片描述
2.修改mysql连接配置
在这里插入图片描述
3. 注意oap-libs内没有MySql驱动
需要自行复制MySql驱动jar包到该目录。

5 自定义SkyWalking链路追踪

如果我们希望对项目中的业务方法,实现链路追踪,方便我们排查问题,可以使用如下的代码引入依赖:

< ! -- Skywalking工具类,和服务版本一致-->
<dependency>
	<groupId>org.apache.skywalking</groupId>
	<artifactId>apm-toolkit-trace</artifactId>
	<version>8.5.0</version>
</dependency>

5.1 @Trace将方法加入追踪链路

如果一个业务方法想在ui界面的跟踪链路上显示出来,只需要在业务方法上加上@Trace注解即可

5.2加入@Tags或@Tag

我们还可以为追踪链路增加其他额外的信息,比如记录参数和返回信息。实现方式:在方法上增加@Tag或者@Tags。
在这里插入图片描述
@Tag注解中key =方法名,value = returnedObj表示返回值,arg[0]表示参数

6 性能分析

skywalking的性能分析,在根据服务名称、端点名称,以及相应的规则建立了任务列表后,在调用了此任务列表的端点后。sky walking会自动记录,剖析当前端口,生成剖析结果。
在这里插入图片描述

在这里插入图片描述

7 Skywalking集成日志框架

1.logback官方配置
2.log4j官方配置
3.log4j2j官方配置引入依赖
这里主要介绍logback的使用

  • 引入依赖
<!--apm-toolkit-logback-1.x -->
<dependency>
    <groupId>org.apache.skywalking</groupId>
    <artifactId>apm-toolkit-logback-1.x</artifactId>
    <version>8.5.0</version>
</dependency>
  • 引入logback配置文件,并加入[%tid]来记录链路id
<?xml version="1.0" encoding="UTF-8"?>
<configuration  scan="true" scanPeriod="10 seconds">
    <!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
    <!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
    <!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
    <!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->

    <contextName>logback</contextName>
    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
    <property name="log.path" value="C:/document/javaCode/log" />

    <!-- 彩色日志 -->
    <!-- 配置格式变量:CONSOLE_LOG_PATTERN 彩色日志格式 -->
    <!-- magenta:洋红 -->
    <!-- boldMagenta:粗红-->
    <!-- cyan:青色 -->
    <!-- white:白色 -->
    <!-- magenta:洋红 -->
    <property name="CONSOLE_LOG_PATTERN"
              value="%yellow(%date{yyyy-MM-dd HH:mm:ss})[%tid] |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>


    <!--输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <!-- 例如:如果此处配置了INFO级别,则后面其他位置即使配置了DEBUG级别的日志,也不会被输出 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>


    <!--输出到文件-->
    <!-- 时间滚动输出 level为 INFO 日志 -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_info.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 WARN 日志 -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_warn.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录warn级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 ERROR 日志 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_error.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <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>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}] [%thread] %-5level %logger{36} -%msg%n</Pattern>
            </layout>
        </encoder>
    </appender>
    <!--
        <logger>用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>。
        <logger>仅有一个name属性,
        一个可选的level和一个可选的addtivity属性。
        name:用来指定受此logger约束的某一个包或者具体的某一个类。
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
              如果未设置此属性,那么当前logger将会继承上级的级别。
    -->
    <!--
        使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
        第一种把<root level="INFO">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
        第二种就是单独给mapper下目录配置DEBUG模式,代码如下,这样配置sql语句会打印,其他还是正常DEBUG级别:
     -->
    <!--开发环境:打印控制台-->
    <springProfile name="dev">
        <!--可以输出项目中的debug日志,包括mybatis的sql日志-->
        <logger name="com.guli" level="INFO" />

        <!--
            root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
            level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,默认是DEBUG
            可以包含零个或多个appender元素。
        -->
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
        </root>
    </springProfile>


    <!--生产环境:输出到文件-->
    <springProfile name="pro">

        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="DEBUG_FILE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="ERROR_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="grpc-log" />
        </root>
    </springProfile>

</configuration>
  • 引入gRPC reporter
    <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>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}] [%thread] %-5level %logger{36} -%msg%n</Pattern>
            </layout>
        </encoder>
    </appender>

  • 配置skyworking,若Skyworking不在本地
    在agient/config进行配置

8 Skywalking告警功能

8.1 告警功能简介

  • Skywalking每隔一段时间根据收集到的链路追踪的数据和配置的告警规则(如服务响应时间、服务响应 时间百分比)等,判断如果达到阈值则发送相应的告警信息。
  • 发送告警信息是通过调用webhook接口完成,具体的webhook接口可以使用者自行定义,从而开发者可以在指定的webhook接口中编写各种告 警方式,比如邮件、短信等。
  • 告警的信息也可以在RocketBot中查看到。

文件定义了默认的4种告警规则

  • 最近3分钟内服务的平均响应时间超过1秒
  • 最近2分钟服务成功率低于80%
  • 最近3分钟90%服务响应时间超过1秒
  • 最近2分钟内服务实例的平均响应时间超过1秒 规则中的参数属性如下

以下是默认的告警规则配置,位于skywalking安装目录下的config文件夹下 alarm-settings.yml文件 中:

rules:
  # Rule unique name, must be ended with `_rule`.
  service_resp_time_rule:
    metrics-name: service_resp_time #oal脚本中的度量名称
    op: ">" # 比较操作符,可以设定>,<,=
    threshold: 1000 #阈值,与metrics-name和比较符号相匹配
    period: 10 #多久检查一次当前的指标数据是否符合告警规则,单位分钟
    count: 3 #达到多少次后,发送告警消息
    silence-period: 5 #在多久之内,忽略相同的告警消息
    message: Response time of service {name} is more than 1000ms in 3 minutes of last 10 minutes. #告警消息内容
  service_sla_rule:
    # Metrics value need to be long, double or int
    metrics-name: service_sla
    op: "<"
    threshold: 8000
    # The length of time to evaluate the metrics
    period: 10
    # How many times after the metrics match the condition, will trigger alarm
    count: 2
    # How many times of checks, the alarm keeps silence after alarm triggered, default as same as period.
    silence-period: 3
    message: Successful rate of service {name} is lower than 80% in 2 minutes of last 10 minutes
  service_resp_time_percentile_rule:
    # Metrics value need to be long, double or int
    metrics-name: service_percentile
    op: ">"
    threshold: 1000,1000,1000,1000,1000
    period: 10
    count: 3
    silence-period: 5
    message: Percentile response time of service {name} alarm in 3 minutes of last 10 minutes, due to more than one condition of p50 > 1000, p75 > 1000, p90 > 1000, p95 > 1000, p99 > 1000
  service_instance_resp_time_rule:
    metrics-name: service_instance_resp_time
    op: ">"
    threshold: 1000
    period: 10
    count: 2
    silence-period: 5
    message: Response time of service instance {name} is more than 1000ms in 2 minutes of last 10 minutes
  database_access_resp_time_rule:
    metrics-name: database_access_resp_time
    threshold: 1000
    op: ">"
    period: 10
    count: 2
    message: Response time of database access {name} is more than 1000ms in 2 minutes of last 10 minutes
  endpoint_relation_resp_time_rule:
    metrics-name: endpoint_relation_resp_time
    threshold: 1000
    op: ">"
    period: 10
    count: 2
    message: Response time of endpoint relation {name} is more than 1000ms in 2 minutes of last 10 minutes
#  Active endpoint related metrics alarm will cost more memory than service and service instance metrics alarm.
#  Because the number of endpoint is much more than service and instance.
#
#  endpoint_avg_rule:
#    metrics-name: endpoint_avg
#    op: ">"
#    threshold: 1000
#    period: 10
#    count: 2
#    silence-period: 5
#    message: Response time of endpoint {name} is more than 1000ms in 2 minutes of last 10 minutes

webhooks:
#  - http://127.0.0.1/notify/
#  - http://127.0.0.1/go-wechat/

9 Skywalking高可用

在大多数生产环境中,后端应用需要支持高吞吐量并且支持高可用来保证服务的稳定,所以你始终需要在生产环境进行集群管理。

Skywalking集群是将skywalking oap作为一个服务注册到nacos上,只要skywalking oap服务没有全部宕机,保证有一个skywalking oap在运行,就能进行跟踪。

  • 搭建一个skywalking oap集群需要:
    (1)至少一个Nacos (也可以是nacos集群)
    (2)至少一个ElasticSearch/mysql(也可以是es/msql集群)
    (3)至少2个skywalking oap服务;
    (4)至少1个UI(UI也可以集群多个,用Nginx代理统一入口)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值