Spring Cloud Alibaba 实战(八)SkyWalking篇

1. SkyWalking 简介

Skywalking 是由国内开源爱好者吴晟(原 OneAPM 工程师,目前在华为)开源并提交到 Apache 孵化器的产品,它同时吸收了 Zipkin/Pinpoint/CAT 的设计思路,支持非侵入式埋点。是一款基于分布式跟踪的应用程序性能监控系统。另外社区还发展出了一个叫 OpenTracing 的组织,旨在推进调用链监控的一些规范和标准工作。

  • SkyWalking 是一个开源监控平台,用于从服务和云原生基础设施收集、分析、聚合和可视化数据。

  • SkyWalking 提供了一种简单的方法来维护分布式系统的清晰视图,甚至可以跨云查看。它是一种现代APM,专门为云原生、基于容器的分布式系统设计。

  • SkyWalking 从三个维度对应用进行监视:service(服务), service instance(实例), endpoint(端点)。服务和实例就不多说了,端点是服务中的某个路径或者说URI。

  • SkyWalking 允许用户了解服务和端点之间的拓扑关系,查看每个服务/服务实例/端点的度量,并设置警报规则。

SkyWalking的组成

SkyWalking主要的几个组成模块:

  1. Agent 主要负责从系统中采集各种指标,链路数据,发送给 oap 服务。

  2. oap 服务接收 Agent 发送过来的数据,存储,执行分析,提供查询和报警功能。

  3. Storage 和 UI 负责存储数据以及查看数据。

2. 使用 Docker 快速搭建 SkyWalking 8.0

  1. 在 linux 服务器上选择并建立目录

mkdir skywalking-docker
  1. 进入 skywalking-docker 目录,建立一个名为 skywalking.yaml 的脚本文件,内容如下

version: '3'
services:
  elasticsearch7:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.5.0
    container_name: elasticsearch7
    restart: always
    ports:
      - 9023:9200
    environment:
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
      - TZ=Asia/Shanghai
    ulimits:
      memlock:
        soft: -1
        hard: -1
    networks:
      - skywalking
    volumes:
      - elasticsearch7:/usr/share/elasticsearch/data
  oap:
    image: apache/skywalking-oap-server:8.0.1-es7
    container_name: oap
    depends_on:
      - elasticsearch7
    links:
      - elasticsearch7
    restart: always
    ports:
      - 9022:11800
      - 9021:12800
    networks:
      - skywalking
    volumes:
      - ./ext-config:/skywalking/ext-config
  ui:
    image: apache/skywalking-ui:8.0.1
    container_name: ui
    depends_on:
      - oap
    links:
      - oap
    restart: always
    ports:
      - 9020:8080
    environment:
      SW_OAP_ADDRESS: oap:12800
    networks:
      - skywalking

networks:
  skywalking:
    driver: bridge

volumes:
  elasticsearch7:
    driver: local

注意:如果我们想覆盖 oap 镜像中的 /skywalking/config 目录下的配置文件,我们可以在 docker 中挂载一个 /skywalking/ext-config 目录,将配置文件丢到此目录中即可。

  1. 执行 skywalking.yaml 脚本启动容器

docker-compose -f skywalking.yaml up
  1. 进入 skywalking 的控制台,发现各种仪表盘,开始当然是空的

http://(安装SkyWalking机器的IP):9020

图片

3. 在 Spring 项目中引入 SkyWalking 客户端

全局日志追踪 traceId 的使用:

  1. 添加 pom 文件依赖

        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-logback-1.x</artifactId>
            <version>8.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-trace</artifactId>
            <version>8.0.1</version>
        </dependency>
  1. 在 resources 目录下 添加 logback-spring.xml 文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <property name="logger.path" value="/mnt/logs"/>

    <!-- 彩色日志 -->
    <!-- 彩色日志依赖的渲染类 -->
    <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="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>


    <!-- 输出到控制台 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>info</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- ConsoleAppender:把日志输出到控制台 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
                <Pattern>
                    <![CDATA[%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} [%X{tid}] %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}]]></Pattern>
            </layout>
        </encoder>
    </appender>

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

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

    <!--
        root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
        不能设置为INHERITED或者同义词NULL。默认是DEBUG
        可以包含零个或多个元素,标识这个appender将会添加到这个logger。
    -->
    <root level="info">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="STDOUT"/>
        <!--<appender-ref ref="DEBUG_FILE" />-->
        <appender-ref ref="INFO_FILE"/>
        <!--<appender-ref ref="WARN_FILE" />-->
        <appender-ref ref="ERROR_FILE"/>
    </root>

</configuration>

注意:其他都是日志常规配置,主要是这部分 <appender-ref ref="STDOUT"/> 的配置。

  1. 进入 skywalking 官网下载 SkyWalking APM,主要是要用到 agent

skywalking 官网下载地址:http://skywalking.apache.org/downloads/

  1. 解压下载的 apache-skywalking-apm-es7-8.0.1.tar.gz 包,目录结构如图

图片

我们只要其中的 agent 目录就行,agent 里的东西大概有这些:

图片

把 agent 目录复制到一个妥善的目录下,一会儿需要配置 JVM 启动参数目录,当然作者直接放到了项目里:

图片

  1. 在 idea 程序启动命令增加如下 JVM 启动参数

-javaagent:(agent文件夹所在的目录)\agent\skywalking-agent.jar -Dskywalking.agent.service_name=(服务名)-service -Dskywalking.agent.instance_name=(服务名)-instance -Dskywalking.collector.backend_service=(安装SkyWalking机器的IP):9022

图片

因为 skywalking 是非侵入式埋点实现分布式链路跟踪和性能监控,所以一般采用 javaagent 的方式。

Javaagent 是什么(JVM 启动前静态 Instrument)?

Javaagent 是 java 命令的一个参数。参数 javaagent 可以用于指定一个 jar 包,并且对该 java 包有两个要求:

  1. 这个 jar 包的 MANIFEST.MF 文件必须指定 Premain-Class 项。

  2. Premain-Class 指定的那个类必须实现 premain() 方法。

premain() 方法,从字面上理解,就是运行在 main() 函数之前的的类。当 Java 虚拟机启动时,在执行 main() 函数之前,jvm 会先运行 -javaagent 所指定 jar 包内 Premain-Class 这个类的 premain() 方法 。

  1. 我们前几篇文章中搭建了完整的项目,在这些项目中全部按照上边的配置一遍,启动看下效果

  • 网关服务:herring-gateway,zuul 统一网关微服务。

  • 认证服务:herring-oauth2,oauth2 认证中心微服务。

  • 会员服务:herring-member-service,微服务之一,接收到请求后会到认证中心验证。

  • 订单服务:herring-orders-service,微服务之二,接收到请求后会到认证中心验证。

  • 商品服务:herring-product-service,微服务之三,接收到请求后会到认证中心验证。

图片

  1. 我们来测试一下,先请求下 token,然后再请求 /api/member/update

#### 

POST http://localhost:8080/oauth2-service/oauth/token?grant_type=password&username=admin&password=123456&client_id=app-client&client_secret=client-secret-8888&scope=all
Accept: */*
Cache-Control: no-cache

得到返回结果 token:

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiZ2F0ZXdheS1zZXJ2aWNlIl0sInVzZXJfbmFtZSI6ImFkbWluIiwiand0LWV4dCI6IkpXVCDmianlsZXkv6Hmga8iLCJzY29wZSI6WyJhbGwiXSwiZXhwIjoxNjEzOTcwMDk2LCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6IjU4MDY5ODlhLWUyNDQtNGQyMy04YTU5LTBjODRiYzE0Yjk5OSIsImNsaWVudF9pZCI6ImFwcC1jbGllbnQifQ.EP4acam0tkJQ9kSGRGk_mQsfi1y4M_hhiBL0H931v60",
  "token_type": "bearer",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiZ2F0ZXdheS1zZXJ2aWNlIl0sInVzZXJfbmFtZSI6ImFkbWluIiwiand0LWV4dCI6IkpXVCDmianlsZXkv6Hmga8iLCJzY29wZSI6WyJhbGwiXSwiYXRpIjoiNTgwNjk4OWEtZTI0NC00ZDIzLThhNTktMGM4NGJjMTRiOTk5IiwiZXhwIjoxNjE0MDM0ODk2LCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6IjQxZGM1ZDc1LTZmZDgtNDU3My04YmRjLWI4ZTMwNWEzMThmMyIsImNsaWVudF9pZCI6ImFwcC1jbGllbnQifQ.CGmGx_msqJBHxa95bBROY2SAO14RyeRklVPYrRxZ7pQ",
  "expires_in": 7199,
  "scope": "all",
  "jwt-ext": "JWT 扩展信息",
  "jti": "5806989a-e244-4d23-8a59-0c84bc14b999"
}

请求执行 /api/member/update

####

GET http://localhost:8080/member-service/api/member/update
Accept: */*
Cache-Control: no-cache
Authorization: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiZ2F0ZXdheS1zZXJ2aWNlIl0sInVzZXJfbmFtZSI6ImFkbWluIiwiand0LWV4dCI6IkpXVCDmianlsZXkv6Hmga8iLCJzY29wZSI6WyJhbGwiXSwiZXhwIjoxNjEzOTcwMDk2LCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6IjU4MDY5ODlhLWUyNDQtNGQyMy04YTU5LTBjODRiYzE0Yjk5OSIsImNsaWVudF9pZCI6ImFwcC1jbGllbnQifQ.EP4acam0tkJQ9kSGRGk_mQsfi1y4M_hhiBL0H931v60

仪表盘结果展示:

图片

图片

图片

拓扑图结果展示

图片

图片

链路追踪结果展示

图片

猜你喜欢

转载自blog.csdn.net/adparking/article/details/119681449