今天我们通过代码的形式来了解下,如何在项目中使用Skywalking。
前几篇文章可以参考:
《学习Skywalking · 搭建篇》
《Skywalking执行效果 · 多图篇》
《Skywalking的ES索引 · 收藏篇》
今天说说代码篇。
先说下比较常见的开源 APM 如下:
- CAT:由国内美团点评开源的,基于 Java 语言开发,目前提供 Java、C/C 、Node.js、Python、Go 等语言的客户端,监控数据会全量统计。国内很多公司在用,例如美团点评、携程、拼多多等。CAT 需要开发人员手动在应用程序中埋点,对代码侵入性比较强。
- Zipkin:由 Twitter 公司开发并开源,Java 语言实现。侵入性相对于 CAT 要低一点,需要对web.xml 等相关配置文件进行修改,但依然对系统有一定的侵入性。Zipkin 可以轻松与 Spring Cloud 进行集成,也是 Spring Cloud 推荐的 APM 系统。
- Pinpoint:韩国团队开源的 APM 产品,运用了字节码增强技术,只需要在启动时添加启动参数即可实现 APM 功能,对代码无侵入。目前支持 Java 和 PHP 语言,底层采用 HBase 来存储数据,探针收集的数据粒度非常细,但性能损耗较大,因其出现的时间较长,完成度也很高,文档也较为丰富,应用的公司较多。
- SkyWalking:国人开源的产品,2019 年 4 月 17 日 SkyWalking 从 Apache 基金会的孵化器毕业成为顶级项目。目前 SkyWalking 支持 Java、.Net、Node.js 等探针,数据存储支持MySQL、ElasticSearch等。SkyWalking 与 Pinpoint 相同,Java 探针采用字节码增强技术实现,对业务代码无侵入。探针采集数据粒度相较于 Pinpoint 来说略粗,但性能表现优秀。目前,SkyWalking 增长势头强劲,社区活跃,中文文档齐全,没有语言障碍,支持多语言探针,这些都是 SkyWalking 的优势所在,还有就是 SkyWalking 支持很多框架,包括很多国产框架,例如,Dubbo、gRPC、SOFARPC 等等,也有很多开发者正在不断向社区提供更多插件以支持更多组件无缝接入 SkyWalking。还有很多不开源的 APM 系统,例如,淘宝鹰眼、Google Dapper 等等,不再展开介绍了。
SkyWalking 的核心功能
- 服务、服务实例、端点指标分析。
- 服务拓扑图分析
- 服务、服务实例和端点(Endpoint)SLA 分析
- 慢查询检测
- 告警
- 多语言自动探针,支持 Java、.NET Code 等多种语言。
- 为多种开源项目提供了插件,为 Tomcat、 HttpClient、Spring、RabbitMQ、MySQL 等常见基础设施和组件提供了自动探针。
SkyWalking 三个核心部分
- Agent(探针):Agent 运行在各个服务实例中,负责采集服务实例的 Trace 、Metrics 等数据,然后通过 gRPC 方式上报给 SkyWalking 后端。
- OAP(后端服务):SkyWalking 的后端服务,其主要责任有两个。 一个是负责接收 Agent 上报上来的 Trace、Metrics 等数据,交给 Analysis Core (涉及 SkyWalking OAP 中的多个模块)进行流式分析,最终将分析得到的结果写入持久化存储中。SkyWalking 可以使用 ElasticSearch、H2、MySQL 等作为其持久化存储,一般线上使用 ElasticSearch 集群作为其后端存储。 另一个是负责响应 SkyWalking UI 界面发送来的查询请求,将前面持久化的数据查询出来,组成正确的响应结果返回给 UI 界面进行展示。
- UI(展示界面 ):SkyWalking 前后端进行分离,该 UI 界面负责将用户的查询操作封装为 GraphQL 请求提交给 OAP 后端触发后续的查询操作,待拿到查询结果之后会在前端负责展示。
其他的不多说,直接上代码!
基础依赖安装
1、安装ES
代码语言:javascript复制docker run --name elasticsearch
-p 9200:9200 -p 9300:9300
-e "discovery.type=single-node"
-e ES_JAVA_OPTS="-Xms512m -Xmx512m"
-d elasticsearch:6.8.19
2、安装Kibana
代码语言:javascript复制docker run -d --name kibana
-p 5601:5601
-v D:/Code/k8s/kibana/kibana.yml:/usr/share/kibana/config/kibana.yml kibana:6.8.0
项目迁移案例展示:
1、设置SKYWALKING-OAP 收集服务
代码语言:javascript复制docker run -p 11800:11800 -d
-e SW_NAMESPACE=bg
-e SW_STORAGE=elasticsearch
-e SW_STORAGE_ES_CLUSTER_NODES=xxxxxx
-e SW_ES_USER=xxx
-e SW_ES_PASSWORD=xxx
apache/skywalking-oap-server:8.9.0
2、设置SKYWALKING-OAP API服务
代码语言:javascript复制docker run -p 12800:12800 -d
-e SW_NAMESPACE=bg
-e SW_STORAGE=elasticsearch
-e SW_STORAGE_ES_CLUSTER_NODES=xxxxx
-e SW_ES_USER=xxx
-e SW_ES_PASSWORD=xxx
-e SW_SEARCHABLE_TAG_KEYS=http.method,status_code,db.type,db.instance,mq.queue,mq.topic,mq.broker,input,output,userId,account,number,systemid
apache/skywalking-oap-server:8.9.0
3、设置SKYWALKING-UI
代码语言:javascript复制docker run -p 8080:8080 -d
-e SW_OAP_ADDRESS=http://xxxx:12800
apache/skywalking-ui:8.9.0
以上环境变量均可配置到k8s中。
4、配置CLIENT(ASP.NET Core)
1、安装nuget包,提供探针
代码语言:javascript复制<PackageReference Include="SkyAPM.Agent.AspNetCore" Version="1.3.0" />
2、设置skyapm.json(可配置configmap)
说明
ps:skyapm.json需要设置属性——始终复制
代码语言:javascript复制{
"SkyWalking": {
"ServiceName": "bg::op::gateway",
"Namespace": "",
"HeaderVersions": [
"sw8"
],
"Sampling": {
"SamplePer3Secs": -1,
"Percentage": -1.0,
"IgnorePaths": ["**/nacos/**"]
},
"Logging": {
"Level": "Debug",
"FilePath": "logs/skyapm-{Date}.log"
},
"Transport": {
"Interval": 3000,
"ProtocolVersion": "v8",
"QueueSize": 30000,
"BatchSize": 3000,
"gRPC": {
"Servers": "bg-oap:11800",
"Timeout": 10000,
"ConnectTimeout": 10000,
"ReportTimeout": 600000
}
}
}
}
3、配置K8s环境变量
代码语言:javascript复制ASPNETCORE_HOSTINGSTARTUPASSEMBLIES = SkyAPM.Agent.AspNetCore
4、问题排查
在容器内,会生成skyapm-2022xxxx.log文件,会有详细的连接信息和推送信息。 同时要检查下是否包含skyapm.json文件。
5、配置CLIENT(Java)
1、修改Dockerfile
代码语言:javascript复制FROM apache/skywalking-java-agent:8.8.0-java11 AS bg-base
WORKDIR /app
// ...
COPY --from=bg-base /skywalking/agent/optional-plugins/apm-trace-ignore-plugin-8.8.0.jar /skywalking/agent/plugins/apm-trace-ignore-plugin-8.8.0.jar
ENTRYPOINT ["sh","-c","exec java -Xmx1024m -Xms1024m -Dproject.name=app-bg -Dskywalking.trace.ignore_path='**/nacos/**,**/JDBI/**' -Duser.language=zh -Duser.country=CN -jar /app/app.jar"]
2、配置k8s环境变量
代码语言:javascript复制SW_AGENT_COLLECTOR_BACKEND_SERVICES=bg-oap:11800
SW_AGENT_NAME="bg::op::svc"
3、配置Tag标记(可选项)
1、添加依赖包
代码语言:javascript复制<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
<version>8.7.0</version>
<scope>provided</scope>
</dependency>
2、设计过滤器
代码语言:javascript复制@Slf4j
@Component
public class ApmHttpInfoFilter extends HttpFilter {
private static final ImmutableSet<String> IGNORED_HEADERS;
static {
Set<String> ignoredHeaders = ImmutableSet.of(
"Content-Type",
"User-Agent",
"Accept",
"Cache-Control",
"Postman-Token",
"Host",
"Accept-Encoding",
"Connection",
"Content-Length")
.stream()
.map(String::toUpperCase)
.collect(Collectors.toSet());
IGNORED_HEADERS = ImmutableSet.copyOf(ignoredHeaders);
}
@Override
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
try {
filterChain.doFilter(requestWrapper, responseWrapper);
} finally {
try {
//构造请求信息: 比如 curl -X GET http://localhost:18080/getPerson?id=1 -H 'token: me-token' -d '{ "name": "hello" }'
//构造请求的方法&URL&参数
StringBuilder sb = new StringBuilder("curl")
.append(" -X ").append(request.getMethod())
.append(" ").append(request.getRequestURL().toString());
if (StringUtils.hasLength(request.getQueryString())) {
sb.append("?").append(request.getQueryString());
}
//构造header
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
if (!IGNORED_HEADERS.contains(headerName.toUpperCase())) {
sb.append(" -H '").append(headerName).append(": ").append(request.getHeader(headerName)).append("'");
}
}
//获取body
String body = new String(requestWrapper.getContentAsByteArray(), StandardCharsets.UTF_8);
if (StringUtils.hasLength(body)) {
sb.append(" -d '").append(body).append("'");
}
//输出到input
ActiveSpan.tag("input", sb.toString());
//输出到userId
ActiveSpan.tag("userid", BaseMethodUtil.getUserIdByHeader(request) "");
//获取返回值body
String responseBody = new String(responseWrapper.getContentAsByteArray(), StandardCharsets.UTF_8);
//输出到output
ActiveSpan.tag("output", responseBody);
} catch (Exception e) {
log.warn("fail to build http log", e);
} finally {
//这一行必须添加,否则就一直不返回
responseWrapper.copyBodyToResponse();
}
}
}
}
3、容器启动配置tag
代码语言:javascript复制-e SW_NAMESPACE=bg-e SW_SEARCHABLE_TAG_KEYS=http.method,status_code,db.type,db.instance,mq.queue,mq.topic,mq.broker,input,output,userid
4、挂载告警配置(可选项)
需要企业微信机器人
代码语言:javascript复制-v D:Codek8skibanaalarm-settings.yml:/skywalking/config/alarm-settings.yml
6、配置CLIENT(Vue.js)
1、安装npm
代码语言:javascript复制npm install skywalking-client-js --save
2、注册服务
代码语言:javascript复制import ClientMonitor from 'skywalking-client-js';
ClientMonitor.register({
collector: process.env.VUE_APP_PERMISSION_URL '/ui',
service: process.env.VUE_APP_SW_NAME || 'op::ui',
pagePath: location.href,
serviceVersion: 'v1.0.0',
vue: Vue,
useFmp: true,
enableSPA: false,
traceTimeInterval: 10000,
apiErrors: true,
})
3、拦截器
代码语言:javascript复制// 异常拦截器
Vue.config.errorHandler = (error) => {
console.error(error)
error.message = window.location.href
const _roles = store.state.user.roles
if (_roles) {
error.message = (_roles.name || '') ' ' _roles.number
}
ClientMonitor.reportFrameErrors({
collector: process.env.VUE_APP_PERMISSION_URL '/ui',
service: process.env.VUE_APP_SW_NAME || 'op::ui',
pagePath: window.location.href,
vue: Vue,
serviceVersion: 'v1.0.0'
}, error)
}
// 路由拦截器
import ClientMonitor from 'skywalking-client-js'
ClientMonitor.customOptions.pagePath = location.origin location.pathname '#' to.fullPath
4、配置nginx代理收集器
代码语言:javascript复制server {
listen 80;
listen [::]:80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html-test;
index index.html index.htm;
}
location /ui/browser/ {
rewrite ^. ui/?(.*)$ /$1 break;
include uwsgi_params;
proxy_pass xxxxxx;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
}
location /ui/v3/ {
rewrite ^. ui/?(.*)$ /$1 break;
include uwsgi_params;
proxy_pass xxxxxxx;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
}
location /ui {
try_files $uri $uri/ /index.html;
alias /usr/share/nginx/html-test/ui;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
其他问题记录:
1、 删除索引后,记得删除对应的ES模板; 2、 VUE项目要根据实际情况,做sw服务的nginx的反向代理配置; 3、 skywalking如果遇到问题,可以优先升级最新版本;