| skywalking是一个国产开源框架,2015年由吴晟开源 , 2017年加入Apache孵化器。skywalking是分布式系统的应用程序性能监视工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。SkyWalking 是观察性分析平台和应用性能管理系统,提供分布式追踪、服务网格遥测分析、度量聚合和可视化一体化解决方案。
由于使用微服务以及dubbo,一个请求的日志追踪成为了问题,为了解决这个问题,考虑引入skywalking
我们这里主要用来做traceid日志检测(也可以做APM分析)
故事背景
如图示:一个稍微复杂的微服务架构,如果有用户反馈某个页面很慢,我们知道这个页面的请求调用链是 A ——-> C ——-> B ——-> D,此时如何定位可能是哪个模块引起的问题。每个服务 Service A,B,C,D 都有好几台机器。怎么知道某个请求调用了服务的具体哪台机器呢?
可以明显看到,由于无法准确定位每个请求经过的确切路径,在微服务这种架构下有以下几个痛点
- 排查问题难度大,周期长
- 特定场景难复现
- 系统性能瓶颈分析较难
分布式调用链就是为了解决以上几个问题而生,它主要的作用如下
- 自动采取数据
- 分析数据产生完整调用链:有了请求的完整调用链,问题有很大概率可复现
- 数据可视化:每个组件的性能可视化,能帮助我们很好地定位系统的瓶颈,及时找出问题所在
通过分布式追踪系统能很好地定位如下请求的每条具体请求链路,从而轻易地实现请求链路追踪,每个模块的性能瓶颈定位与分析。
要保证全局唯一 ,我们可以采用分布式或者本地生成的 ID,使用分布式话需要有一个发号器,每次请求都要先请求一下发号器,会有一次网络调用的开销,所以 SkyWalking 最终采用了本地生成 ID 的方式,它采用了大名鼎鼎的 snowflow 算法,性能很高。 |
| —- |
效果展示
sky walking主要分为四部分 - 上部分 Agent :负责从应用中,收集链路信息,发送给 SkyWalking OAP 服务器。我们使用的是 java-agent - 下部分 SkyWalking OAP :负责接收 Agent 发送的 Tracing 数据信息,然后进行分析(Analysis Core) ,存储到外部存储器( Storage ),最终提供查询( Query )功能。 - 右部分 Storage :Tracing 数据存储。目前支持 ES、MySQL、Sharding Sphere、TiDB、H2 多种存储器。而我们目前采用的是 ES - 左部分 SkyWalking UI :负责提供控台,查看链路等等。 |
---|
#docker-compose.yml
#安装es
#安装iap
#安装ui
elasticsearch:
image: docker.io/elasticsearch:7.6.1
environment:
- node.name=elk
- cluster.name=icp-test-es
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms8g -Xmx8g"
- discovery.type=single-node
volumes:
- /usr/local/icp/elasticsearch/data:/usr/share/elasticsearch/data
- /usr/local/icp/elasticsearch/plugins:/usr/share/elasticsearch/plugins
- /usr/local/icp/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
- /usr/local/icp/elasticsearch/logs:/usr/share/elasticsearch/logs
- /usr/local/icp/elasticsearch/backups:/usr/share/elasticsearch/backups
container_name: elasticsearch
hostname: elasticsearch
restart: always
privileged: true
ports:
- "9200:9200"
- "9300:9300"
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: "65536"
hard: "65536"
oap:
image: apache/skywalking-oap-server:8.9.1
container_name: oap
depends_on:
- elasticsearch
links:
- elasticsearch
restart: always
ports:
- 11800:11800
- 12800:12800
healthcheck:
test: ["CMD-SHELL", "/skywalking/bin/swctl"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
environment:
TZ: Asia/Shanghai
SW_STORAGE: elasticsearch
SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200
SW_ES_USER: elastic
SW_ES_PASSWORD: onehome
ui:
image: apache/skywalking-ui:8.9.1
container_name: ui
depends_on:
- oap
links:
- oap
restart: always
ports:
- 8088:8080
environment:
TZ: Asia/Shanghai
SW_OAP_ADDRESS: http://oap:12800
#下载ui tar
wget https://downloads.apache.org/skywalking/java-agent/8.8.0/apache-skywalking-java-agent-8.8.0.tgz
#解压
tar zxvf apache-skywalking-java-agent-8.8.0.tgz
#采用 logback + agent方式使用
#pom.xml导入lib
<!-- https://mvnrepository.com/artifact/org.apache.skywalking/apm-toolkit-logback-1.x -->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>${apm.version}</version>
</dependency>
# logback-spring.xml %tid即为tracdId
# grpc_log 打印tid
# 运行测试:
# 方式1 IDE VM options配置
-javaagent:E:\software\skywalking-agent\skywalking-agent.jar
-DSW_AGENT_NAME=flex-consumer
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=10.8.0.102:11800
# 方式2 jar运行 添加 javaagent:skywalking+backend_service
java -Dspring.profiles.active=test -javaagent:skywalking-agent/skywalking-agent.jar=agent.service_name=flex-consumer -Dskywalking.collector.backend_service=10.8.0.102:11800 -jar -Xmx512M -Xms512M flex-consumer-0.0.1-SNAPSHOT.jar --spring.cloud.nacos.server-addr=10.8.0.101:8848
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<contextName>${APP_NAME}</contextName>
<springProperty name="APP_NAME" scope="context" source="spring.application.name"/>
<springProperty name="LOG_FILE" scope="context" source="logging.file" defaultValue="../logs/application/${APP_NAME}"/>
<springProperty name="LOG_POINT_FILE" scope="context" source="logging.file" defaultValue="../logs/point"/>
<springProperty name="LOG_AUDIT_FILE" scope="context" source="logging.file" defaultValue="../logs/audit"/>
<springProperty name="LOG_MAXFILESIZE" scope="context" source="logback.filesize" defaultValue="50MB"/>
<springProperty name="LOG_FILEMAXDAY" scope="context" source="logback.filemaxday" defaultValue="7"/>
<springProperty name="ServerIP" scope="context" source="spring.cloud.client.ip-address" defaultValue="0.0.0.0"/>
<springProperty name="ServerPort" scope="context" source="server.port" defaultValue="0000"/>
<!-- 彩色日志格式 -->
<!-- 日志格式中添加 %tid 即可输出 trace id -->
<property name="CONSOLE_LOG_PATTERN"
value="[${APP_NAME}:${ServerIP}:${ServerPort}] %clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}){magenta} %clr([%tid]){yellow} %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}" />
<property name="CONSOLE_LOG_PATTERN_NO_COLOR" value="[${APP_NAME}:${ServerIP}:${ServerPort}] %d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%X{traceId}] [%thread] %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}" />
<property name="CONSOLE_LOG_PATTERN_SKY_WALKING" value="[${APP_NAME}:${ServerIP}:${ServerPort}] %clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}){magenta} %clr([%tid]){yellow} %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}" />
<!-- 控制台日志 -->
<appender name="StdoutAppender" 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_SKY_WALKING}</Pattern>
</layout>
</encoder>
</appender>
<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>${CONSOLE_LOG_PATTERN_SKY_WALKING}</Pattern>
</layout>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
。。。。。。。
<root level="INFO">
<appender-ref ref="StdoutAppender"/>
<appender-ref ref="file_async"/>
<appender-ref ref="grpc_log"/>
</root>
</configuration>