1 简介

大型的几十、百个微服务构成的微服务架构系统,通常遇到如下问题:

  1. 如何串联整个调用链路,快速定位问题?
  2. 如何理清各微服务之间的依赖关系?
  3. 如何进行各微服务接口的性能分折?
  4. 如何跟踪整个业务流程的调用处理顺序?

skywalking是国产开源框架,15年由吴晟开源,17年加入Apache孵化器。分布式系统的应用程序性能监视工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。SkyWalking是观察性分析平台和应用性能管理系统,提供分布式追踪、服务网格遥测分析、度量聚合和可视化一体化解决方案。

1.1 主要功能特性

1、多种监控手段,可以通过语言探针和service mesh获得监控的数据

2、支持多种语言自动探针,包括 Java,.NET Core 和 Node.JS

3、轻量高效,无需大数据平台和大量的服务器资源

4、模块化,UI、存储、集群管理都有多种机制可选

5、支持告警

6、优秀的可视化解决方案

2 Skywalking整体架构

skywalking+ES下载安装,单点/集群部署、告警机制详解_jar

1、上部分Agent :从应用中,收集链路信息,发给 SkyWalking OAP 服务器

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

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

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

3 SkyWalking支持的探针(Probe)

3.1 Agent

基于ByteBuddy字节码增强技术实现,通过JVM的agent参数加载,并在程序启动时拦截指定的方法,来收集数据。

3.2 SDK

程序中显式调用SkyWalking提供的SDK来收集数据,对应用有侵入。

3.3 Service Mesh

通过Service mesh的网络代理来收集数据。

后端(Backend)接受探针发送过来的数据,进行度量分析,调用链分析和存储。后端主要分为:

  • OAP(Observability Analysis Platform)- 进行度量分析和调用链分析的后端平台,支持将数据存储到各种数据库如ES,MySQL,InfluxDB
  • OAL(Observability Analysis Language)- 用来进行度量分析的DSL,类似于SQL,用于查询度量分析结果和警报

界面(UI)

  • RocketBot UI – SkyWalking 7.0.0 的默认web UI
  • CLI – 命令行界面

这三个模块的交互流程:

skywalking+ES下载安装,单点/集群部署、告警机制详解_java_02

4 概念

服务(Service)

表示对请求提供相同行为的一系列或一组工作负载,在使用Agent时,可定义服务的名字。

服务实例(Service Instance)

上述的一组工作负载中的每一个工作负载称为一个实例, 一个服务实例实际就是os上的一个真实进程。

端点(Endpoint)

对于特定服务所接收的请求路径,如HTTP的URI路径和gRPC服务的类名 + 方法签名。

skywalking+ES下载安装,单点/集群部署、告警机制详解_java_03

5 Agent跟踪微服务

5.1 通过jar包方式接入

准备一个SpringBoot程序,打成可执行jar包,写个shell脚本,在启动项目的Shell脚本上,通过 -javaagent 参数进行配置SkyWalking Agent来跟踪微服务。

startup.sh脚本:

1#!/bin/sh2# SkyWalking Agent配置3export SW_AGENT_NAME=springboot-skywalking-demo #Agent名字,一般使用`spring.application.name`4export SW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800 #配置 Collector 地址。5export SW_AGENT_SPAN_LIMIT=2000 #配置链路的最大Span数量,默认为 300。6export JAVA_AGENT=-javaagent:/usr/local/soft/apache-skywalking-apm-bin-es7/agent/skywalking-agent.jar7java $JAVA_AGENT -jar springboot-skywalking-demo-0.0.1-SNAPSHOT.jar #jar启动

业务服务的启动脚本:

1#!/bin/sh2APPLICATION=car-receiver.jar3MAX_MEMORY=2048M45function checkApplicationExist() {6    if [ ! -f $APPLICATION ]; then7        echo "Cannot find $APPLICATION"8        echo "The file is absent or does not have execute permission"9        echo "This file is needed to run this program"10        exit 111    fi12}1314function checkJDKEnv() {15    if [ -z "$JAVA_HOME" -a -z "$JRE_HOME" ]; then16        echo "Neither the JAVA_HOME nor the JRE_HOME environment variable is defined"17        echo "At least one of these environment variable is needed to run this program"18        exit 119    fi20}2122function main() {23    checkApplicationExist24    checkJDKEnv25    nohup java -javaagent:/data/software/skywalking-agent/skywalking-agent.jar \26    -Dskywalking.agent.service_name=car-receiver-test \27    -Dskywalking.collector.backend_service=ip:11800 \28    -Dfile.encoding=UTF-8 -Xmx$MAX_MEMORY -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps \29    -Xloggc:gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 \30    -XX:GCLogFileSize=20M -jar $APPLICATION --spring.config.location=application-prod.yml >> /opt/car-receiver/car-receiver.out 2>&1 &31}3233main

启动日志:

skywalking+ES下载安装,单点/集群部署、告警机制详解_微服务_04

等同于

1java ‐javaagent:/usr/local/soft/apache‐skywalking‐apm‐bin‐es7/agent/skywalking‐agent.jar2‐DSW_AGENT_COLLECTOR_BACKEND_SERVICES=10.51.50.178:118003‐DSW_AGENT_NAME=springboot‐skywalking‐demo ‐jar springboot‐skywalking‐demo‐0.0.1‐SNAPSHOT.jar

参数名对应agent/config/agent.config配置文件中的属性。

属性对应的源码:org.apache.skywalking.apm.agent.core.conf.Config.java

1# The service name in UI2# ${service name} = [${group name}::]${logic name}3# The group name is optional only.4agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}5# Backend service addresses.6collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:10.51.50.187:11800}

也可使用skywalking.+配置文件中的配置名,作为系统配置项来进行覆盖。 javaagent参数配置方式的优先级更高。

如下是简单的 startup.sh 示例,假设你的 SkyWalking Agent jar 包在 skywalking-agent 目录,微服务 jar 包在 target 目录:

1#!/bin/bash2JAVA_OPTS="-javaagent:/data/software/skywalking-agent/skywalking-agent.jar3-Dskywalking.agent.service_name=car-receiver-test4-Dskywalking.collector.backend_service=10.51.50.178:11800"56java $JAVA_OPTS -jar ./target/your-service.jar

在启动程序前加一个-javaagent参数,即可完成对程序的跟踪。

5.2 IDEA中使用Skywalking

在运行的程序配置VM参数:

skywalking+ES下载安装,单点/集群部署、告警机制详解_java_05

5.3 Skywalking跨多个微服务跟踪

跨多个微服务跟踪,只需每个微服务启动时都添加javaagent参数。

启动微服务mall-gateway,mall-order,mall-user ,配置skywalking的JVM参数:

访问 http://localhost:8888/user/findOrderByUserId/1

skywalking+ES下载安装,单点/集群部署、告警机制详解_java_06

skywalking+ES下载安装,单点/集群部署、告警机制详解_jar_07

此处存在bug,跟踪链路不显示gateway。

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

skywalking+ES下载安装,单点/集群部署、告警机制详解_java_08

skywalking+ES下载安装,单点/集群部署、告警机制详解_微服务_09

skywalking+ES下载安装,单点/集群部署、告警机制详解_微服务_10

skywalking+ES下载安装,单点/集群部署、告警机制详解_java_11

6 告警通知

告警的核心由一组规则驱动,定义在config/alarm-settings.yml,告警规则的定义分为:

  • 告警规则:它们定义了应该如何触发度量警报,应该考虑什么条件
  • Webhook:当警告触发时,哪些服务终端需要被通知
  • gRPC钩子:远程gRPC方法的主机和端口,告警触发后调用

为方便,skywalking发行版中提供默认的alarm-setting.yml,包括一些规则,每个规则有英文注释,可根据注释得知每个规则的作用。

数据库访问{name}的响应时间在过去10分钟的2分钟内超过1000ms 只要我们的服务请求符合alarm-setting.yml中的某一条规则就会触发告警。

如service_resp_time_rule规则:

skywalking+ES下载安装,单点/集群部署、告警机制详解_微服务_12

该规则表示服务{name}的响应时间在最近10分钟的3分钟内超过1000ms。

编写接口,模拟慢查询:

1@RequestMapping("/info/{id}")2public User info(@PathVariable("id") Integer id){34    try {5        Thread.sleep(2000);6    } catch (InterruptedException e) {7        e.printStackTrace();8    }910    return userService.getById(id);11}

回调接口

@RequestMapping("/notify")
public String notify(@RequestBody Object obj){
    //TODO 告警信息,给技术负责人发短信,钉钉消息,邮件,微信通知等
    System.err.println(obj.toString());
    return "notify successfully";
}

在config/alarm-settings.yml中配置回调接口,并重启skywalking服务

skywalking+ES下载安装,单点/集群部署、告警机制详解_微服务_13

测试访问:http://localhost:8000/user/info/1,满足告警规则后,控制台输出告警信息

SkyWalking UI显示告警信息。

skywalking+ES下载安装,单点/集群部署、告警机制详解_java_14

对接钉钉

skywalking+ES下载安装,单点/集群部署、告警机制详解_微服务_15

Webhook回调通知

SkyWalking告警Webhook回调要求接收方是一个Web容器(比如tomcat服务),告警的消息会通过HTTP请求进行 发送, 请求方法为POST, Content-Type为application/json,

JSON格式基于List<org.apache.skywalking.oap.server.core.alarm.AlarmMessage>的集合对象数据, 集合中的每个

AlarmMessage包含以下信息:

1、scopeId. 所有可用的Scope,参考:org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;

2、name. 目标 Scope 的实体名称; 3、id0. Scope 实体的 ID;

4、id1. 未使用

5、ruleName. 在 alarm-settings.yml 中配置的规则名; 6、alarmMessage. 报警消息内容;

7、startTime. 告警时间, 位于当前时间与 UTC 1970/1/1 之间;

[{
	scopeId = 2,
	scope = SERVICE_INSTANCE,
	name = 98e1839 a6fdf48b0aedb0ecabb8ea5f7 @192 .168 .233 .1 of springboot - skywalking - demo,
	id0 = c3ByaW5nYm9vdC1za3l3YWxraW5nLWRlbW8 = .1 _OThlMTgzOWE2ZmRmNDhiMGFlZGIwZWNhYmI4ZWE1ZjdAMTkyLjE2OC4yMzMuMQ == ,
	id1 = ,
	ruleName = service_instance_resp_time_rule,
	alarmMessage = Response time of service instance 98e1839 a6fdf48b0aedb0ecabb8ea5f7 @192 .168 .233 .1 of springboot - skywalking - demo is more than 1000 ms in 2 minutes of last 10 minutes,
	startTime = 1613913565462
}, {
	scopeId = 6,
	scope = ENDPOINT_RELATION,
	name = User in User to / user / info / {
		id
	} in springboot - skywalking - demo,
	id0 = VXNlcg == .0 _VXNlcg == ,
	id1 = c3ByaW5nYm9vdC1za3l3YWxraW5nLWRlbW8 = .1 _L3VzZXIvaW5mby97aWR9,
	ruleName = endpoint_relation_resp_time_rule,
	alarmMessage = Response time of endpoint relation User in User to / user / info / {
		id
	} in springboot - skywalking - demo is more than 1000 ms in 2 minutes of last 10 minutes,
	startTime = 1613913565462
}]

7 持久化数据

7.1 基于MySQL

修改config目录下的application.yml,使用mysql作为持久化存储的仓库

skywalking+ES下载安装,单点/集群部署、告警机制详解_jar_16

修改mysql连接配置:

skywalking+ES下载安装,单点/集群部署、告警机制详解_java_17

storage:
  #选择使用mysql   默认使用h2,不会持久化,重启skyWalking之前的数据会丢失
  selector: ${SW_STORAGE:mysql}
  #使用mysql作为持久化存储的仓库
  mysql:
    properties:
      #数据库连接地址
      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://1ocalhost:3306/swtest"}
      #用户名
      dataSource.user: ${SW_DATA_SOURCE_USER:root}
      #密码
      dataSource.password: ${SW_DATA_SOURCE_PASSWORD:root}

添加MySQL数据驱动包,因为在lib目录下是没有mysql数据驱动包的,所以修改完配置启动是会报错,启动失败的。

skywalking+ES下载安装,单点/集群部署、告警机制详解_jar_18

添加mysql数据驱动包到oap-libs目录:

skywalking+ES下载安装,单点/集群部署、告警机制详解_jar_19

启动Skywalking:

skywalking+ES下载安装,单点/集群部署、告警机制详解_微服务_20

查看swtest数据库,可以看到生成很多表:

skywalking+ES下载安装,单点/集群部署、告警机制详解_java_21

说明启动成功,打开配置对应的地址http://localhost:8080/,可以看到skywalking的web界面。

重启skywalking,验证跟踪数据会不会丢失。

7.2 基于ES持久化

  1. 准备好elasticsearch环境启动elasticsearch服务

启动elasticsearch-head服务

su - es
cd /usr/local/soft/elasticsearch-7.6.1/
bin/elasticsearch -d

访问http://192.168.3.100:9100

cd /usr/local/soft/elasticsearch-head/node_modules/grunt
nohup bin/grunt server &
  1. 修改config/application.yml配置文件:

修改elasticsearch7的连接配置

skywalking+ES下载安装,单点/集群部署、告警机制详解_java_22

  1. 启动Skywalking服务

skywalking+ES下载安装,单点/集群部署、告警机制详解_微服务_23

启动时会向elasticsearch中创建大量的index索引用于持久化数据,每天会产生一个新的索引文件。

测试:

动应用程序,查看跟踪数据是否已经持久化到elasticsearch的索引中,然后重启skywalking,验证跟踪数据会不会丢失

skywalking+ES下载安装,单点/集群部署、告警机制详解_jar_24

8 自定义链路追踪

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

引入依赖

<!-- SkyWalking 工具类 -->
<dependency>
    <groupId>org.apache.skywalking</groupId>
    <artifactId>apm-toolkit-trace</artifactId>
    <version>8.4.0</version>
</dependency>

在业务方法中可以TraceContext获取到traceId

@RequestMapping("/list")
public List<User> list(){

    //TraceContext可以绑定key-value
    TraceContext.putCorrelation("name", "fox");
    Optional<String> op = TraceContext.getCorrelation("name");
    log.info("name = {} ", op.get());
    //获取跟踪的traceId
    String traceId = TraceContext.traceId();
    log.info("traceId = {} ", traceId);

    return userService.list();
}

测试 http://localhost:8000/user/list

skywalking+ES下载安装,单点/集群部署、告警机制详解_java_25

在Skywalking UI中查询tranceId

skywalking+ES下载安装,单点/集群部署、告警机制详解_微服务_26

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

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

skywalking+ES下载安装,单点/集群部署、告警机制详解_jar_27

测试:

skywalking+ES下载安装,单点/集群部署、告警机制详解_微服务_28

2.4.2 加入@Tags或@Tag

还可为追踪链路增加其他额外的信息,比如记录参数和返回信息。实现方式:在方法上增加@Tag或@Tags。

@Trace
@Tag(key = "list", value = "returnedObj")
public List<User> list(){
    return userMapper.list();
}

@Trace
@Tags({@Tag(key = "param", value = "arg[0]"),
        @Tag(key = "user", value = "returnedObj")})
public User getById(Integer id){
    return userMapper.getById(id);
}

skywalking+ES下载安装,单点/集群部署、告警机制详解_java_29

9 Skywalking集成日志框架

log4j2j官方配置](https://skywalking.apache.org/docs/main/v8.4.0/en/setup/service-agent/java-agent/application-toolkit-log4j-2.x)

引入依赖

1<!-- apm-toolkit-logback-1.x -->2<dependency>3    <groupId>org.apache.skywalking</groupId>4    <artifactId>apm-toolkit-logback-1.x</artifactId>5    <version>8.4.0</version>6</dependency>

添加logback-spring.xml文件,并配置 %tid 占位符

skywalking+ES下载安装,单点/集群部署、告警机制详解_java_30

测试:

skywalking+ES下载安装,单点/集群部署、告警机制详解_微服务_31

Skywalking通过grpc上报日志 (需v8.4.0)

gRPC报告程序可以将收集到的日志转发到SkyWalking OAP服务器上

logback-spring.xml中添加

<!-- v8.4.0提供 -->
 <appender name="grpc-log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender"/>
<root level="info">
    <appender-ref ref="grpc-log" />
</root>

skywalking+ES下载安装,单点/集群部署、告警机制详解_微服务_32

打开agent/config/agent.config配置文件,添加如下配置信息:

plugin.toolkit.log.grpc.reporter.server_host=${SW_GRPC_LOG_SERVER_HOST:192.168.3.100}
plugin.toolkit.log.grpc.reporter.server_port=${SW_GRPC_LOG_SERVER_PORT:11800}
plugin.toolkit.log.grpc.reporter.max_message_size=${SW_GRPC_LOG_MAX_MESSAGE_SIZE:10485760}
plugin.toolkit.log.grpc.reporter.upstream_timeout=${SW_GRPC_LOG_GRPC_UPSTREAM_TIMEOUT:30}

以上配置是默认配置信息,agent与oap在本地的可以不配

配置名

解释

默认值



plugin.toolkit.log.transmit_formatted

是否以格式化或未格式化的格式传输记录的数据

true



plugin.toolkit.log.grpc.reporter.server_host

指定要向其报告日志数据的grpc服务器的主机

127.0.0.1



plugin.toolkit.log.grpc.reporter.server_port

指定要向其报告日志数据的grpc服务器的端口

11800



plugin.toolkit.log.grpc.reporter.max_message_size

指定grpc客户端要报告的日志数据的最大大小

10485760



plugin.toolkit.log.grpc.reporter.upstream_timeout

客户端向上游发送数据时将超时多长时间。单位是秒

30



agent配置信息大全

Skywalking UI效果:

skywalking+ES下载安装,单点/集群部署、告警机制详解_jar_33

此处日期格式存在问题

https:///apache/skywalking-rocketbot-ui/pull/428

skywalking+ES下载安装,单点/集群部署、告警机制详解_微服务_34

10 集群部署

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

搭建一个skywalking oap集群需要:

(1) 至少一个Nacos(也可以把nacos集群)

(2) 至少一个ElasticSearch(也可以把es集群)

(3) 至少2个skywalking oap服务;

(4) 至少1个UI(UI也可以集群多个,用Nginx代理统一入口)

  1. 修改config/application.yml文件使用nacos作为注册中心

skywalking+ES下载安装,单点/集群部署、告警机制详解_微服务_35

修改nacos配置:

skywalking+ES下载安装,单点/集群部署、告警机制详解_java_36

可以选择性修改监听端口:

skywalking+ES下载安装,单点/集群部署、告警机制详解_jar_37

修改存储策略,使用elasticsearch7作为storage:

skywalking+ES下载安装,单点/集群部署、告警机制详解_微服务_38

skywalking+ES下载安装,单点/集群部署、告警机制详解_微服务_39

  1. 配置ui服务webapp.yml文件的listOfServers,写两个地址

skywalking+ES下载安装,单点/集群部署、告警机制详解_微服务_40

  1. 启动服务测试

启动Skywalking服务,指定应用的JVM参数。

-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.3.10:11800,192.168.3.12:11800

参考: