对于一个大型的几十个、几百个微服务构成的微服务架构系统,通常会遇到下面一些问题,比如:
skywalking是一个国产开源框架,2015年由吴晟开源 , 2017年加入Apache孵化器。skywalking是分布式系统的应用程序性能监视工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。它是一款优秀的 APM(Application Performance Management)工具,包括了分布式追踪、性能指标分析、应用和服务依赖分析等。
官网:http://skywalking.apache.org/
下载:http://skywalking.apache.org/downloads/
Github:https://github.com/apache/skywalking
文档:https://skywalking.apache.org/docs/main/v9.2.0/readme/
中文文档: https://skyapm.github.io/document-cn-translation-of-skywalking/
模拟了三种并发用户:500,750,1000。使用jmeter测试,每个线程发送30个请求,设置思考时间为10ms。使用的采样率为1,即100%,这边与生产可能有差别。pinpoint默认的采样率为20,即50%,通过设置agent的配置文件改为100%。zipkin默认也是1。组合起来,一共有12种。下面看下汇总表:
从上表可以看出,在三种链路监控组件中,skywalking的探针对吞吐量的影响最小,zipkin的吞吐量居中。pinpoint的探针对吞吐量的影响较为明显,在500并发用户时,测试服务的吞吐量从1385降低到774,影响很大。然后再看下CPU和memory的影响,在内部服务器进行的压测,对CPU和memory的影响都差不多在10%之内。
1、多种监控手段,可以通过语言探针和service mesh获得监控的数据;
2、支持多种语言自动探针,包括 Java,.NET Core 和 Node.JS;
3、轻量高效,无需大数据平台和大量的服务器资源;
4、模块化,UI、存储、集群管理都有多种机制可选;
5、支持告警;
6、优秀的可视化解决方案;
官方架构图
下载 SkyWalking
下载:http://skywalking.apache.org/downloads/
官方安装说明:https://skywalking.apache.org/docs/main/v9.2.0/en/setup/backend/backend-setup/
官方提供docker和k8s的安装说明
计划在2022年11月30日结束所有v8版本(EOL):https://skywalking.apache.org/events/deprecate-v8/
Sky Walking后端服务器和UI于2022年9月2日发布了重要的9.2.0。凭借新添加的Layer概念、ebpf代理、更广泛的中间件服务器监控(如My SQL和Postgre SQL服务器),Sky Walkingv9比上一个v8版本(8.9.1)强大得多。
从现在起,我们已经解决了9.0.0版本以来发现的所有严重错误,这些错误可能会阻止v8用户升级。v9版本还提供与8.9.1版本相同的兼容性。因此,最终用户在申请升级时不会受到阻碍。
总之不管了,这里安装9.2.0版本,然后我发现这个升级似乎是针对服务端和ui,探针的话还是v8版本
点击tar会跳转正式的下载界面
支持jdk8到jdk17
你可以通过bin/startup.sh
(或cmd) 在默认设置下启动Backend和UI,,同时希望你能了解:
0.0.0.0/11800
,rest相关的API可访问0.0.0.0/12800
。在Java,.NetCore,Node.js, Istio agents/probe中,设置gRPC服务地址为ip/host:11800
。 (ip/host填写Backend暴露的)
8080
端口,同时请求127.0.0.1/12800
来做GraphQL查询。修改config/applicaiton.yml中的core模块
applicaiton.yml中第一级时模块,有集群模块,存储模块,等,第二级是选择器,大致是选择这个模块的具体实现
core:
selector: ${SW_CORE:default}
default:
# Mixed: Receive agent data, Level 1 aggregate, Level 2 aggregate
# Receiver: Receive agent data, Level 1 aggregate
# Aggregator: Level 2 aggregate
role: ${SW_CORE_ROLE:Mixed} # Mixed/Receiver/Aggregator
restHost: ${SW_CORE_REST_HOST:0.0.0.0}
restPort: ${SW_CORE_REST_PORT:12800}
restContextPath: ${SW_CORE_REST_CONTEXT_PATH:/}
restMaxThreads: ${SW_CORE_REST_MAX_THREADS:200}
restIdleTimeOut: ${SW_CORE_REST_IDLE_TIMEOUT:30000}
restAcceptQueueSize: ${SW_CORE_REST_QUEUE_SIZE:0}
httpMaxRequestHeaderSize: ${SW_CORE_HTTP_MAX_REQUEST_HEADER_SIZE:8192}
gRPCHost: ${SW_CORE_GRPC_HOST:0.0.0.0}
gRPCPort: ${SW_CORE_GRPC_PORT:11800}
maxConcurrentCallsPerConnection: ${SW_CORE_GRPC_MAX_CONCURRENT_CALL:0}
maxMessageSize: ${SW_CORE_GRPC_MAX_MESSAGE_SIZE:0}
gRPCThreadPoolQueueSize: ${SW_CORE_GRPC_POOL_QUEUE_SIZE:-1}
gRPCThreadPoolSize: ${SW_CORE_GRPC_THREAD_POOL_SIZE:-1}
gRPCSslEnabled: ${SW_CORE_GRPC_SSL_ENABLED:false}
gRPCSslKeyPath: ${SW_CORE_GRPC_SSL_KEY_PATH:""}
gRPCSslCertChainPath: ${SW_CORE_GRPC_SSL_CERT_CHAIN_PATH:""}
gRPCSslTrustedCAPath: ${SW_CORE_GRPC_SSL_TRUSTED_CA_PATH:""}
打开webapp下的webapp.yml
server:
port: 8729 # 默认是8080
spring:
cloud:
gateway:
routes:
- id: oap-route
uri: lb://oap-service
predicates:
- Path=/graphql/**
discovery:
client:
simple:
instances:
oap-service:
- uri: http://127.0.0.1:12800 # 对应backend后端服务的端口,似乎可以配置多个
# - uri: http://:
# - uri: http://:
config/applicaiton.yml
默认是选择h2作为数据库,h2是基于内存的,为了避免数据丢失,可以修改选择mysql或者elasticsearch,然后修改对应选择的配置项
storage:
selector: ${SW_STORAGE:mysql}
mysql:
properties:
jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://127.0.0.1:32306/skywalking?rewriteBatchedStatements=true"}
dataSource.user: ${SW_DATA_SOURCE_USER:root}
dataSource.password: ${SW_DATA_SOURCE_PASSWORD:Jeol@1201}
dataSource.cachePrepStmts: ${SW_DATA_SOURCE_CACHE_PREP_STMTS:true}
dataSource.prepStmtCacheSize: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_SIZE:250}
dataSource.prepStmtCacheSqlLimit: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_LIMIT:2048}
dataSource.useServerPrepStmts: ${SW_DATA_SOURCE_USE_SERVER_PREP_STMTS:true}
metadataQueryMaxSize: ${SW_STORAGE_MYSQL_QUERY_MAX_SIZE:5000}
maxSizeOfBatchSql: ${SW_STORAGE_MAX_SIZE_OF_BATCH_SQL:2000}
asyncBatchPersistentPoolSize: ${SW_STORAGE_ASYNC_BATCH_PERSISTENT_POOL_SIZE:4}
添加mysql数据驱动包到oap-libs目录下
select version()
然后到仓库里找一下对应的驱动
./bin/startup.sh
# 单独启动服务端
/bin/oapService.sh
# 单独启动ui
/bin/webappService.sh
然后数据库会生成很多表,过一段时间后就可以访问了
会在skywalking根目录下生成logs文件夹。
skywalking通过探针来手机数据,不同语言,不同应用有不同的探针,之前v8版本agent是在其安装包下的agent目录内
现在的话从我之前提供的地址下载
官方使用说明界面:https://skywalking.apache.org/docs/main/next/en/setup/service-agent/server-agents/
你可以找到一些探针的使用说明,就java agent而言,你还可以找到docker中的使用说明和k8s中的使用说明
目录结构如下,使用时这整个目录应该是一起使用的,启动时会加载config下面的一下配置
skywalking是无侵入的,你只需要添加java命名的启动参数即可
-DSW_AGENT_SPAN_LIMIT似乎是限制收集数据的大小,不可过大,避免占用过多内存,小了似乎也不行,查看https://blog.csdn.net/fernny_atobe/article/details/115484527
java -javaagent:D:\jeol\Desktop\jar\skywalking-agent\skywalking-agent.jar
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=43.143.136.203:11800
-DSW_AGENT_NAME=nacos-producer
# -DSW_AGENT_SPAN_LIMIT=300
注意放通端口
gateway加入相同启动参数后,skywalking端没反应
我们需要从agent可选插件目录optional-plugins中复制gateway插件到 plugins目录中,根据需要选择版本
如果我们希望对项目中的业务方法,实现链路追踪,方便我们排查问题,可以使用如下的代码
版本和探针的版本一致即可,
org.apache.skywalking
apm-toolkit-trace
8.13.0
@Service
public class DemoServiceImpl implements DemoService {
@Override
// 在调用链中看到这个方法只需要@trace.,需要看到详细参数添加@Tags注解
@Trace
@Tags({@Tag(key = "param", value = "arg[0]"),
@Tag(key = "result", value = "returnedObj")})
public String skywalkingTest(int param, String s) {
return "123456";
}
}
具体参数点击进去可以看到
logback官方配置
log4j官方配置
log4j2j官方配置
总之就是应用本地打印日志,包含了tid(用于在ui界面上检索日志),然后日志上传skywalking
依赖
<dependency>
<groupId>org.apache.skywalkinggroupId>
<artifactId>apm-toolkit-logback-1.xartifactId>
<version>8.13.0version>
dependency>
添加logback-spring.xml文件,并配置 %tid 占位符
'%clr(%d{${LOG_DATEFORMAT_PATTERN:yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} [%tid] %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n}'
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<appender name="console" 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.TraceIdPatternLogbackLayout">
<Pattern>${CONSOLE_LOG_PATTERN}Pattern>
layout>
encoder>
appender>
<root level="INFO">
<appender-ref ref="console"/>
root>
configuration>
gRPC报告程序可以将收集到的日志转发到SkyWalking OAP服务器上
logback-spring.xml中添加
<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%nPattern>
layout>
encoder>
appender>
<root level="info">
<appender-ref ref="grpc-log" />
打开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}
以上配置是默认配置信息,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 告警功能是在6.x版本新增的,其核心由一组规则驱动,这些规则定义在config/alarm-settings.yml文件中。 告警规则的定义分为两部分:
SkyWalking 的发行版都会默认提供config/alarm-settings.yml文件,里面预先定义了一些常用的告警规则。如下:
这些预定义的告警规则,打开config/alarm-settings.yml文件即可看到
告警规则配置项的说明:
Webhook可以简单理解为是一种Web层面的回调机制,通常由一些事件触发,与代码中的事件回调类似,只不过是Web层面的。由于是Web层面的,所以当事件发生时,回调的不再是代码中的方法或函数,而是服务接口。例如,在告警这个场景,告警就是一个事件。当该事件发生时,SkyWalking就会主动去调用一个配置好的接口,该接口就是所谓的Webhook。
SkyWalking的告警消息会通过 HTTP 请求进行发送,请求方法为 POST,Content-Type 为 application/json,其JSON 数据实基于List进行序列化的。JSON数据示例:
[{
"scopeId": 1,
"scope": "SERVICE",
"name": "serviceA",
"id0": "12",
"id1": "",
"ruleName": "service_resp_time_rule",
"alarmMessage": "alarmMessage xxxx",
"startTime": 1560524171000
}, {
"scopeId": 1,
"scope": "SERVICE",
"name": "serviceB",
"id0": "23",
"id1": "",
"ruleName": "service_resp_time_rule",
"alarmMessage": "alarmMessage yyy",
"startTime": 1560524171000
}]
字段说明:
根据以上两个小节的介绍,可以得知:SkyWalking是不支持直接向邮箱、短信等服务发送告警信息的,SkyWalking只会在发生告警时将告警信息发送至配置好的Webhook接口。
但我们总不能人工盯着该接口的日志信息来得知服务是否发生了告警,因此我们需要在该接口里实现发送邮件或短信等功能,从而达到个性化的告警通知。
接下来开始动手实践,这里基于Spring Boot进行实现。首先是添加依赖:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-mailartifactId>
dependency>
#邮箱配置
spring:
mail:
host: smtp.163.com
#发送者邮箱账号
username: 你的邮箱@163.com
#发送者密钥
password: 你的邮箱服务密钥
default-encoding: utf-8
port: 465 #端口号465或587
protocol: smtp
properties:
mail:
debug:
false
smtp:
socketFactory:
class: javax.net.ssl.SSLSocketFactory
用于接收的数据对象
@Data
public class SwAlarmDTO {
private Integer scopeId;
private String scope;
private String name;
private Integer id0;
private Integer id1;
private String ruleName;
private String alarmMessage;
private Long startTime;
}
处理代码
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/alarm")
public class SwAlarmController {
private final JavaMailSender sender;
@Value("${spring.mail.username}")
private String from;
/**
* 接收skywalking服务的告警通知并发送至邮箱
*/
@PostMapping("/receive")
public void receive(@RequestBody List<SwAlarmDTO> alarmList) {
SimpleMailMessage message = new SimpleMailMessage();
// 发送者邮箱
message.setFrom(from);
// 接收者邮箱
message.setTo(from);
// 主题
message.setSubject("告警邮件");
String content = getContent(alarmList);
// 邮件内容
message.setText(content);
sender.send(message);
log.info("告警邮件已发送...");
}
private String getContent(List<SwAlarmDTO> alarmList) {
StringBuilder sb = new StringBuilder();
for (SwAlarmDTO dto : alarmList) {
sb.append("scopeId: ").append(dto.getScopeId())
.append("\nscope: ").append(dto.getScope())
.append("\n目标 Scope 的实体名称: ").append(dto.getName())
.append("\nScope 实体的 ID: ").append(dto.getId0())
.append("\nid1: ").append(dto.getId1())
.append("\n告警规则名称: ").append(dto.getRuleName())
.append("\n告警消息内容: ").append(dto.getAlarmMessage())
.append("\n告警时间: ").append(dto.getStartTime())
.append("\n\n---------------\n\n");
}
return sb.toString();
}
}
最后将该接口配置到SkyWalking中,Webhook的配置位于config/alarm-settings.yml文件的末尾调用接口的配置
webhooks:
# - http://127.0.0.1/notify/
# - http://127.0.0.1/go-wechat/
你可以发送到webchat、dingtalk等,而无需添加新的代码,具体参考官方文档
v9版本的界面和v8版本的界面还是有很大的不同,不过v9版本左侧的大部分菜单可能是用于其他agent探针获取到的数据,这里主要说一下我知道的几个界面
似乎可以查看相关指标
对于一个请求,这里展示其经过了那些节点,每个节点的耗时,分为自身耗时,和总耗时,你可以根据日子中打印的tid,再这里搜索到相关数据
**服务(Service) :**表示对请求提供相同行为的一系列或一组工作负载,在使用Agent时,可以定义服务的名字;
**服务实例(Service Instance) :**上述的一组工作负载中的每一个工作负载称为一个实例, 一个服务实例实际就是操作系统上的一个真实进程;
**端点(Endpoint) :**对于特定服务所接收的请求路径, 如HTTP的URI路径和gRPC服务的类名 + 方法签名;
应用上传的日志可以在这里查看,找到日志后可以跳转链路跟踪界面
这个似乎这个版本已经没有了
第一栏:Global、Service、Instance、Endpoint不同展示面板;
Services load:服务每分钟请求数;
Slow Services:慢响应服务,单位ms;
Un-Health services(Apdex): Apdex性能指标,1为满分;
Slow Endpoint:慢响应端点,单位ms;
Global Response Latency:百分比响应延时,不同百分比的延时时间,单位ms;
Global Heatmap:服务响应时间热力分布图,根据时间段内不同响应时间的数量显示颜色深度;
Service Apdex(数字):当前服务的评分;
Service Apdex(折线图):不同时间的Apdex评分;
Service Avg Response Times:平均响应延时,单位ms;
Service Response Time Percentile:百分比响应延时;
Successful Rate(数字):请求成功率;
Successful Rate(折线图):不同时间的请求成功率;
Servce Load(数字):每分钟请求数;
Servce Load(折线图):不同时间的每分钟请求数;
Servce Instances Load:每个服务实例的每分钟请求数;
Show Service Instance:每个服务实例的最大延时;
Service Instance Successful Rate:每个服务实例的请求成功率;
Service Instance Load:当前实例的每分钟请求数;
Service Instance Successful Rate:当前实例的请求成功率;
Service Instance Latency:当前实例的响应延时;
JVM CPU:jvm占用CPU的百分比;
JVM Memory:JVM内存占用大小,单位m;
JVM GC Time:JVM垃圾回收时间,包含YGC和OGC;
JVM GC Count:JVM垃圾回收次数,包含YGC和OGC;
JVM Thread Count:JVM线程数;
。。。。。。。
左侧菜单-设置部分
官方提供k8s的集群安装说明。这里还是通过文件安装
在大多数生产环境中,后端应用需要支持高吞吐量并且支持高可用来保证服务的稳定,所以你始终需要在生产环境进行集群管理。
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代理统一入口)
操作
以下仅供参考,未测试
1.修改config/application.yml文件集群模块部分
使用nacos作为注册中心
2.修改存储策略,上面讲过了
3、配置ui服务webapp.yml文件的listOfServers,写两个地址
spring:
cloud:
gateway:
routes:
- id: oap-route
uri: lb://oap-service
predicates:
- Path=/graphql/**
discovery:
client:
simple:
instances:
oap-service:
- uri: http://127.0.0.1:12800 # 对应backend后端服务的端口
# - uri: http://:
# - uri: http://:
4、.启动服务测试
启动Skywalking服务,指定springboot应用的jvm参数
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.3.10:11800,192.168.3.12:11800
kubernetes中使用java探针:https://skywalking.apache.org/zh/2022-04-19-how-to-use-the-java-agent-injector/
你可以在其blog界面找到更多使用说明:https://skywalking.apache.org/zh/