- 什么是APM系统
- 什么是
APM (Application Performance Management) 即应用性能管理系统,是对企业系统即时监控以实现
对应用程序性能管理和故障管理的系统化的解决方案。应用性能管理,主要指对企业的关键业务应用进
行监测、优化,提高企业应用的可靠性和质量,保证用户得到良好的服务,降低IT总拥有成本。
APM系统是可以帮助理解系统行为、用于分析性能问题的工具,以便发生故障的时候,能够快速定位和
解决问题。
随着分布式系统和微服务架构的出现,一次用户的请求会经过多个系统,不同服务之间的调用关系十分
复杂,任何一个系统出错都可能影响整个请求的处理结果。以往的监控系统往往只能知道单个系统的健
康状况、一次请求的成功失败,无法快速定位失败的根本原因。
除此之外,复杂的分布式系统也面临这下面这些问题:
性能分析:一个服务依赖很多服务,被依赖的服务也依赖了其他服务。如果某个接口耗时突然变长
了,那未必是直接调用的下游服务慢了,也可能是下游的下游慢了造成的,如何快速定位耗时变长
的根本原因呢?
链路梳理:需求迭代很快,系统之间调用关系变化频繁,靠人工很难梳理清楚系统链路拓扑(系统
之间的调用关系)。
为了解决这些问题,Google 推出了一个分布式链路跟踪系统 Dapper ,之后各个互联网公司都参照
Dapper 的思想推出了自己的分布式链路跟踪系统,而这些系统就是分布式系统下的APM系统。
官方网站:http://skywalking.apache.org/
演示地址:http://demo.skywalking.apache.org/
User: skywalking Password: skywalking
Skywalking是一个可观测性分析平台(Observability Analysis Platform简称OAP)
和应用性能管理系统(Application Performance Management简称APM)
提供分布式链路追踪、服务网格(Service Mesh)遥测分析、度量(Metric)聚合和可视化一体化解决方案。
SkyWalking从三个维度对应用进行监视:service(服务), service instance(实例), endpoint(端点)
多语言自动探针,Java,.NET Core和Node.JS。 多种监控手段,语言探针和service mesh。 轻量高效。不需要额外搭建大数据平台。 模块化架构。UI、存储、集群管理多种机制可选。 支持告警。 优秀的可视化效果。
整体架构包含如下三个组成部分:
1. 探针(agent)负责进行数据的收集,包含了Tracing和Metrics的数据,agent会被安装到服务所在的 服务器上,以方便数据的获取。 2. 可观测性分析平台OAP(Observability Analysis Platform),接收探针发送的数据,并在内存中使 用分析引擎(Analysis Core)进行数据的整合运算,然后将数据存储到对应的存储介质上,比如 Elasticsearch、MySQL数据库、H2数据库等。同时OAP还使用查询引擎(Query Core)提供HTTP查 询接口。 3. Skywalking提供单独的UI进行数据的查看,此时UI会调用OAP提供的接口,获取对应的数据然后 进行展示。1.2.2 Skywalking优势
Skywalking相比较其他的分布式链路监控工具,具有以下特点:
-
社区相当活跃。Skywalking已经进入apache孵化。开发者是国人,可以直接和项目发起人交流进行问题的解决。
-
Skywalking支持Java,.NET Core和Node.JS语言。相对于其他平台:比如Pinpoint支持Java和
PHP,具有较大的优势。 -
探针无倾入性。对比CAT具有倾入性的探针,优势较大。不修改原有项目一行代码就可以进行集
成。 -
探针性能优秀。有网友对Pinpoint和Skywalking进行过测试,由于Pinpoint收集的数据过多,所以
对性能损耗较大,而Skywalking探针性能十分出色。 -
支持组件较多。特别是对Rpc框架的支持,这是其他框架所不具备的。Skywalking对Dubbo、
gRpc等有原生的支持,甚至连小众的motan和sofarpc都支持。
上图中,我们编写了用户服务,这是一个web项目,在生产中部署了两个节点:192.168.1.100和
192.168.1.101。
- 用户服务就是Skywalking的服务(Service),用户服务其实就是一个独立的应用(Application),在
6.0之后的Skywalking将应用更名为服务(Service)。 - 用户服务对外提供的HTTP接口/usr/queryAll就是一个端点,端点就是对外提供的接口。
- 192.168.1.100和192.168.1.101这两个相同服务部署的节点就是实例,实例指同一服务可以部署
多个。
环境说明:
- ES6.4
- Skywalking7.0
- Skywaling6(agent)
- centos7
SkyWalking有两种版本,ES7版本和非ES7版。
如果我们决定采用ElasticSearch7作为存储,那么就下载es7版本。
PS:Skywalking7及以上的agent不兼容jdk7.0及以下的版本,如果项目为jdk7或者以下的版本,建议使用: Skywalking6的agent。
下载地址: https://archive.apache.org/dist/skywalking/2.2 安装
需提前准备好Es环境,保证可用。
- 安装Backend后端服务(oap)
- 安装UI
#创建并切换skywalking目录 mkdir /opt/software/skywalking/ cd /opt/software/skywalking/ #解压压缩包 tar -xf apache-skywalking-apm-7.0.0.tar.gz
目录结构
agent目录将来要拷贝到各服务所在机器上用作探针 bin目录是服务启动脚本 config目录是配置文件 oap-libs目录是oap服务运行所需的jar包 webapp目录是web服务运行所需的jar包
支持的存储有:
H2 ElasticSearch 6, 7 MySQL TiDB InfluxDB2.3 安装配置后端(oap)服务
修改Skywalking存储数据源配置:
cd apache-skywalking-apm-bin/ vim config/application.yml
默认配置中使用H2作为数据源,这里我们使用的是ES。
storage:
selector: ${SW_STORAGE:elasticsearch}
elasticsearch:
nameSpace: ${SW_NAMESPACE:""}
clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:localhost:9200}
protocol: ${SW_STORAGE_ES_HTTP_PROTOCOL:"http"}
trustStorePath: ${SW_SW_STORAGE_ES_SSL_JKS_PATH:"../es_keystore.jks"}
trustStorePass: ${SW_SW_STORAGE_ES_SSL_JKS_PASS:""}
user: ${SW_ES_USER:""}
password: ${SW_ES_PASSWORD:""}
secretsManagementFile: ${SW_ES_SECRETS_MANAGEMENT_FILE:""}
oap服务的配置文件剩下使用默认配置就可以。
bin/oapService.sh #启动oap服务
oap服务默认启动的端口为:11180、12800,如果端口已经启动就可以继续启动UI服务了。
[root@hadoop101 test]# ss -antulp | grep 11800
tcp LISTEN 0 128 [::]:11800 [::]:* users:(("java",pid=10425,fd=259))
[root@hadoop101 test]# ss -antulp | grep 12800
tcp LISTEN 0 50 [::]:12800 [::]:* users:(("java",pid=10425,fd=261))
oap服务的日志打印位置,如果端口没有启动,检查日志文件有无明显报错,一般都是es问题。
logs/skywalking-oap-server-2021-02-25-2.log2.4 安装配置UI服务
查看UI服务配置文件,这里不进行任何修改均使用默认配置。
cat apache-skywalking-apm-bin/webapp/webapp.yml
server:
#web页面启动的端口号
port: 8080
collector:
path: /graphql
ribbon:
ReadTimeout: 10000
# Point to all backend's restHost:restPort, split by
#oap服务,如果是多个oap服务用逗号隔开,对应OAP application.yml core 模块下restPort
listOfServers: 127.0.0.1:12800
目前的默认配置不用修改就可以使用,启动UI程序:
/bin/webappService.sh
然后我们就可以通过浏览器访问Skywalking的可视化页面了,访问地址:http://虚拟机IP地址:8080,如果
出现下面的图,就代表安装成功了。
./apache-skywalking-apm-bin/bin/startup.sh #可直接启动oap服务和ui服务2.4.1 oap server采样率调整
#采样率总数为 10000 如果设置为 5000即为 50%
sampleRate: ${SW_TRACE_SAMPLE_RATE:5000}
2.4.2 oap server优化
# 设置度量数据的超时。超时过期后,度量数据将自动删除.
# 明细记录的有效期
recordDataTTL: ${SW_STORAGE_ES_RECORD_DATA_TTL:2} # Unit is day
otherMetricsDataTTL: ${SW_STORAGE_ES_OTHER_METRIC_DATA_TTL:2} # Unit is day
monthMetricsDataTTL: ${SW_STORAGE_ES_MONTH_METRIC_DATA_TTL:1} # Unit is month
# 调整bulkActions默认1000次请求批量写入一次改到4000次
# 批量处理配置
bulkActions: ${SW_STORAGE_ES_BULK_ACTIONS:4000}
# 并发请求的数量
concurrentRequests: ${SW_STORAGE_ES_CONCURRENT_REQUESTS:2}
# flushInterval每10秒刷新一次堆改为每30秒刷新
flushInterval: ${SW_STORAGE_ES_FLUSH_INTERVAL:30}
#es 每次查询的最大数量
metadataQueryMaxSize: ${SW_STORAGE_ES_QUERY_MAX_SIZE:8000}
# es 查询段最大数量
segmentQueryMaxSize: ${SW_STORAGE_ES_QUERY_SEGMENT_SIZE:200}
#每天一个索引
dayStep: ${SW_STORAGE_DAY_STEP:1}
2.5 agent的使用
agent探针可以让我们不修改代码的情况下,对java应用上使用到的组件进行动态监控,获取运行数据
发送到OAP上进行统计和存储。agent探针在java中是使用java agent技术实现的,不需要更改任何代
码,java agent会通过虚拟机(VM)接口来在运行期更改代码。
文件目录
如下;
apache-skywalking-apm-bin/agent/ ├── activations │ ├── apm-toolkit-log4j-1.x-activation-7.0.0.jar │ ├── apm-toolkit-log4j-2.x-activation-7.0.0.jar ├── bootstrap-plugins │ ├── apm-jdk-http-plugin-7.0.0.jar │ └── apm-jdk-threading-plugin-7.0.0.jar ├── config #配置文件 │ └── agent.config ├── logs ├── optional-plugins #可选插件 │ ├── apm-customize-enhance-plugin-7.0.0.jar │ ├── apm-gson-2.x-plugin-7.0.0.jar ├── plugins #组件的所有插件 │ ├── apm-activemq-5.x-plugin-7.0.0.jar │ ├── apm-armeria-0.84.x-plugin-7.0.0.jar └── skywalking-agent.jar
部分插件在使用上会影响整体的性能或者由于版权问题放置于可选插件包中,不会直接加载,如果需要使用,将可选插件中的jar包拷贝到plugins包下。
将agent目录拷贝至各服务所在的机器上
scp -r ./agent root@192.168.100.12:~/
修改配置文件 配置服务名称和后端服务地址
cd /usr/local/skywalking/apache-skywalking-apm-bin/agent/config
vi agent.config
#这里的配置含义是可以读取到SW_AGENT_NAME配置属性,如果该配置没有指定,那么默认名称为
Your_ApplicationName。这里我们把Your_ApplicationName替换成skywalking_tomcat。
agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
#oap服务地址
collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:192.168.100.17:11800}
# 采样率 默认为 -1 0 负数或者0表示关闭,如果设置为 5000 15000/5000=30%
agent.sample_n_per_3_secs=${SW_AGENT_SAMPLE:5000}
# Logging level
logging.level=${SW_LOGGING_LEVEL:WARN}
# 日志滚存
logging.max_history_files=${SW_LOGGING_MAX_HISTORY_FILES:5}
或者在服务启动的时候用命令行参数 -javaagent 来指定探针
spring boot
java -Dskywalking.agent.service_name=sktest-pdf -Dskywalking.collector.backend_service=192.168.100.17:11800 -javaagent:/software/sky-agent-7.0-pdf/skywalking-agent.jar -jar ./20210202_1_BSDL.jar
Linux 下Tomcat7和8
编辑/usr/local/skywalking/apache-tomcat-8.5.47/bin/catalina.sh 文件,在文件顶部添加:
CATALINA_OPTS="$CATALINA_OPTS -javaagent:/usr/local/skywalking/apache- skywalking-apm-bin/agent/skywalking-agent.jar"; export CATALINA_OPTS
配置好探针后启动项目,Web界面就能看到服务信息了
在之前的案例中,我们每次部署应用都需要复制一份agent,修改其中的服务名称,这样显得非常麻
烦。可以使用Skywalking提供的配置覆盖功能通过启动命令动态指定服务名,这样agent只需要部署一
份即可。Skywalking支持的几种配置方式:
- 系统配置(System properties)
-Dskywalking.agent.service_name=skywalking_mysql
- 探针配置(Agent options)
Add the properties after the agent path in JVM arguments
-javaagent:/path/to/skywalking-agent.jar=[option1]=[value1],[option2]=[value2]
案例: 如果配置中包含分隔符( , 或者 = ) , 就必须使用引号包裹起来
-javaagent:/path/to/skywalking-agent.jar=agent.service_name=skywalking_mysql
- 系统环境变量(System environment variables)
案例: 由于agent.service_name配置项如下所示
# The service name in UI agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
可以在环境变量中设置SW_AGENT_NAME的值来指定服务名。
- 覆盖优先级
探针配置 > 系统配置 >系统环境变量 > 配置文件中的值
2.7 告警编辑 alarm-settings.yml 设置告警规则和通知:
以下是默认的告警规则配置,位于skywalking安装目录下的config文件夹下 alarm-settings.yml 文件中:
rules:
# Rule unique name, must be ended with `_rule`.
endpoint_percent_rule:
# Metrics value need to be long, double or int
metrics-name: endpoint_percent
threshold: 75
op: <
# The length of time to evaluate the metrics
period: 10
# How many times after the metrics match the condition, will trigger alarm
count: 3
# How many times of checks, the alarm keeps silence after alarm triggered, default as same as period.
silence-period: 10
message: Successful rate of endpoint {name} is lower than 75%
service_resp_time_rule:
metrics-name: service_resp_time
# [Optional] Default, match all services in this metrics
include-names:
- dubbox-provider
- dubbox-consumer
threshold: 1000
op: ">"
period: 10
count: 1
#webhooks:
# - http://127.0.0.1/notify/
# - http://127.0.0.1/go-wechat/
以上文件定义了默认的4种规则:
- 最近3分钟内服务的平均响应时间超过1秒
- 最近2分钟服务成功率低于80%
- 最近3分钟90%服务响应时间超过1秒
- 最近2分钟内服务实例的平均响应时间超过1秒
规则中的参数属性如下:
为了使用钉钉机器人通知,接下来,新建一个项目:
4.0.0 org.springframework.boot spring-boot-starter-parent2.4.0 com.wt.monitor skywalking-alarm1.0.0-SNAPSHOT skywalking-alarm 1.8 org.springframework.boot spring-boot-starter-webcom.aliyun alibaba-dingtalk-service-sdk1.0.1 commons-codec commons-codec1.15 com.alibaba fastjson1.2.75 org.projectlombok lomboktrue org.springframework.boot spring-boot-maven-plugin
可选依赖(不建议引入)
org.apache.skywalking server-core 8.2.0
定义告警消息实体类:
package com.wt.monitor.skywalking.alarm.domain;
import lombok.Data;
import java.io.Serializable;
@Data
public class AlarmMessageDTO implements Serializable {
private int scopeId;
private String scope;
private String name;
private String id0;
private String id1;
private String ruleName;
private String alarmMessage;
private long startTime;
}
发送钉钉机器人消息:
package com.wt.monitor.skywalking.alarm.service;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiRobotSendRequest;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
@Slf4j
@Service
public class DingTalkAlarmService {
@Value("${dingtalk.webhook}")
private String webhook;
@Value("${dingtalk.secret}")
private String secret;
public void sendMessage(String content) {
try {
Long timestamp = System.currentTimeMillis();
String stringToSign = timestamp + "n" + secret;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)),"UTF-8");
String serverUrl = webhook + "×tamp=" + timestamp + "&sign=" + sign;
DingTalkClient client = new DefaultDingTalkClient(serverUrl);
OapiRobotSendRequest request = new OapiRobotSendRequest();
request.setMsgtype("text");
OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();
text.setContent(content);
request.setText(text);
client.execute(request);
} catch (ApiException e) {
e.printStackTrace();
log.error(e.getMessage(), e);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
log.error(e.getMessage(), e);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
log.error(e.getMessage(), e);
} catch (InvalidKeyException e) {
e.printStackTrace();
log.error(e.getMessage(), e);
}
}
}
AlarmController.java
package com.wt.monitor.skywalking.alarm.controller;
import com.alibaba.fastjson.JSON;
import com.wt.monitor.skywalking.alarm.domain.AlarmMessageDTO;
import com.wt.monitor.skywalking.alarm.service.DingTalkAlarmService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.MessageFormat;
import java.util.List;
@Slf4j
@RestController
@RequestMapping("/skywalking")
public class AlarmController {
@Autowired
private DingTalkAlarmService dingTalkAlarmService;
@PostMapping("/alarm")
public void alarm(@RequestBody List alarmMessageDTOList) {
log.info("收到告警信息: {}", JSON.toJSONString(alarmMessageDTOList));
if (null != alarmMessageDTOList) {
alarmMessageDTOList.forEach(e->dingTalkAlarmService.sendMessage(MessageFormat.format("-----来自SkyWalking的告警-----n【名称】: {0}n【消息】: {1}n", e.getName(), e.getAlarmMessage())));
}
}
}
2.9 部署测试
首先需要修改告警规则配置文件,将webhook地址修改为:
webhooks: - http://127.0.0.1:8089/webhook
然后重启skywalking。
1、将 skywalking_alarm.jar 上传至 /usr/local/skywalking 目录下。
2、启动skywalking_alarm应用,等待启动成功。
java -javaagent:/usr/local/skywalking/apache-skywalking-apm- bin/agent/skywalking-agent.jar -Dskywalking.agent.service_name=skywalking_alarm -jar skywalking_alarm.jar
3、不停调用接口,接口地址为:http://虚拟机IP:8089/timeout
4、直到出现告警
获取到了告警相关的信息,在生产中使用可以在webhook接口中对接短信、邮件等平台,当告警出现时能迅速发送信息给对应的处理人员,提高故障处理的速度。



