SkyWalking应用监控和链路追踪
APM 软件对应用进行监控和跟踪,帮助我们解决上面这些系统问题。在这种背景下,SkyWalking 作为应用监控和链路跟踪的利器,便脱颖而出。
顶层架构图
SkyWalking 顶层架构抽象分为6层,分别是:
- 应用层:作为数据的产生者,创造数据。
- 探针层:通过探针对应用层进行数据采集。
- 数据传输层:RPC 框架,负责传递探针层采集的数据。
- 服务层:接收数据传输层的数据,进行功能实现。
- 存储层:利用各种存储组件,为服务层的数据进行持久化。
- 展示层:调用服务层接口,通过 Web 界面展示数据。
结合上面6层,最终的流程图如下所示:
为了方便演示,实现全链路监控,ElasticSeach、Nacos、MySQL、Redis采用单机docker简易部署方式
- 搭建依赖环境jdk8、maven,包括 ElasticSeach7、Nacos2.x、SpringCloud分布式项目。
- 安装 SkyWalking,使用Agent启动项目,随后在 SkyWalking 中查看。
- 结合项目代码进行链路跟踪和应用监控的基本使用。
部署流程:
#部署jdk8、maven环境
apt-get purge openjdk* #删除旧环境JDK
apt update
apt install apt-transport-https ca-certificates wget dirmngr gnupg software-properties-common -y
wget -qO - https://adoptopenjdk.jfrog.io/adoptopenjdk/api/gpg/key/public | apt-key add -
add-apt-repository --yes https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/
apt update
apt install adoptopenjdk-8-hotspot -y
java -version
#部署maven环境
cat > /etc/profile.d/apache-maven.sh << 'EOF'
export JAVA_HOME=/usr/lib/jvm/adoptopenjdk-8-hotspot-amd64/
export M2_HOME=/usr/local/apache-maven
export MAVEN_HOME=/usr/local/apache-maven
export PATH=${M2_HOME}/bin:${PATH}
EOF
source /etc/profile.d/apache-maven.sh
vim /etc/profile
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib:$CLASSPATH
export JAVA_PATH=${JAVA_HOME}/bin:${JRE_HOME}/bin
export PATH=$PATH:${JAVA_PATH}
source /etc/profile
mvn -v
#修改源,添加配置。把原生的mirrors删掉或注释,然后新增下面的源
vim /usr/local/apache-maven-3.6.3/conf/settings.xml
<mirrors>
<!-- 阿里云仓库 -->
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>https://maven.aliyun.com/nexus/content/repositories/central/</url>
</mirror>
<!-- 中央仓库1 -->
<mirror>
<id>repo1</id>
<mirrorOf>central</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<url>http://repo1.maven.org/maven2/</url>
</mirror>
<!-- 中央仓库2 -->
<mirror>
<id>repo2</id>
<mirrorOf>central</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<url>http://repo2.maven.org/maven2/</url>
</mirror>
</mirrors>
#然后部署elasticseach,生产环境另外使用集群的方式
docker run --restart=always \
-p 9200:9200 \
-p 9300:9300 \
-e "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms512m -Xmx512m" \
--name='elasticsearch' \
--cpuset-cpus="1" -m 2G \
-d elasticsearch:7.6.2
#部署mysql
docker run --name mysql \
-v /data/docker_mysql:/var/lib/mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=admin123 \
-d mysql:5.7.30
docker exec -it mysql /bin/bash
echo 'skip-grant-tables' >> /etc/mysql/conf.d/docker.cnf
#退出容器,并重启mysql
docker restart mysql
#Nacos环境搭建,生产环境另外使用集群的方式
cd /usr/local/
wget https://github.com/alibaba/nacos/releases/download/2.0.3/nacos-server-2.0.3.tar.gz
tar zxf nacos-server-2.0.3.tar.gz
#进入mysql容器内部,创建数据库和表
create database nacos_config;
use nacos_config;
CREATE TABLE `config_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(255) DEFAULT NULL,
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`app_name` varchar(128) DEFAULT NULL,
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
`c_desc` varchar(256) DEFAULT NULL,
`c_use` varchar(64) DEFAULT NULL,
`effect` varchar(64) DEFAULT NULL,
`type` varchar(64) DEFAULT NULL,
`c_schema` text,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';
CREATE TABLE `config_info_aggr` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(255) NOT NULL COMMENT 'group_id',
`datum_id` varchar(255) NOT NULL COMMENT 'datum_id',
`content` longtext NOT NULL COMMENT '内容',
`gmt_modified` datetime NOT NULL COMMENT '修改时间',
`app_name` varchar(128) DEFAULT NULL,
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';
CREATE TABLE `config_info_beta` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';
CREATE TABLE `config_info_tag` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
`tag_id` varchar(128) NOT NULL COMMENT 'tag_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';
CREATE TABLE `config_tags_relation` (
`id` bigint(20) NOT NULL COMMENT 'id',
`tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
`tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
`nid` bigint(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`nid`),
UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';
CREATE TABLE `group_capacity` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值',
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';
CREATE TABLE `his_config_info` (
`id` bigint(64) unsigned NOT NULL,
`nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`data_id` varchar(255) NOT NULL,
`group_id` varchar(128) NOT NULL,
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL,
`md5` varchar(32) DEFAULT NULL,
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`src_user` text,
`src_ip` varchar(50) DEFAULT NULL,
`op_type` char(10) DEFAULT NULL,
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
PRIMARY KEY (`nid`),
KEY `idx_gmt_create` (`gmt_create`),
KEY `idx_gmt_modified` (`gmt_modified`),
KEY `idx_did` (`data_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';
CREATE TABLE `tenant_capacity` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';
CREATE TABLE `tenant_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`kp` varchar(128) NOT NULL COMMENT 'kp',
`tenant_id` varchar(128) default '' COMMENT 'tenant_id',
`tenant_name` varchar(128) default '' COMMENT 'tenant_name',
`tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
`create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
`gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
`gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';
CREATE TABLE `users` (
`username` varchar(50) NOT NULL PRIMARY KEY,
`password` varchar(500) NOT NULL,
`enabled` boolean NOT NULL
);
CREATE TABLE `roles` (
`username` varchar(50) NOT NULL,
`role` varchar(50) NOT NULL,
UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
);
CREATE TABLE `permissions` (
`role` varchar(50) NOT NULL,
`resource` varchar(255) NOT NULL,
`action` varchar(8) NOT NULL,
UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
);
INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);
INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');
#修改nacos配置文件,取消注释并改成对应的连接地址
vim /usr/local/nacos/conf/application.properties
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=admin123
#单机启动
/usr/local/nacos/bin/startup.sh -m standalone
#通过http://localhost:8848/nacos访问 Nacos,并创建dev的命名空间。
#部署redis
docker run -p 6379:6379 --name redis \
-v /etc/redis/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf \
--appendonly yes
springcloud项目搭建
gitee:https://gitee.com/chezhe2/swcourse/tree/swcourse
#下载swcourse-springcloud模块
#在配置中修改为nacos 命名空间地址。注意代码里的配置文件路径,consumer、provider两个模块都需要修改
vim swcourse-swcourse/swcourse-springcloud/swcourse-springcloud-provider/src/main/resources/bootstrap-dev.yml
server:
port: 8081
spring:
application:
name: provider
cloud:
nacos:
discovery:
namespace: 711add01-8a7d-45b0-9032-6458943ce665 #修改成nacos的命名空间id
server-addr: 127.0.0.1:8848
datasource:
url: jdbc:mysql://localhost:3306/midian?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true&serverTimezone=UTC
username: root
password: admin123
driver-class-name: com.mysql.jdbc.Driver
hikari:
minimum-idle: 5
maximumPoolSize: 5
redis:
database: 11
host: 127.0.0.1
port: 6379
ssl: false
lettuce:
pool:
max-idle: 3
max-active: 3
min-idle: 3
max-wait-millis: 1
test-on-borrow: true
test-on-return: true
test-while-idle: true
timeout: 0
time-between-eviction-runs-millis: 1
num-tests-per-eviction-run: 10
min-evictable-idle-time-millis: 1
vim swcourse-swcourse/swcourse-springcloud/swcourse-springcloud-consumer/src/main/resources/bootstrap-dev.yml
server:
port: 8082
spring:
application:
name: consumer
cloud:
nacos:
discovery:
namespace: 711add01-8a7d-45b0-9032-6458943ce665
server-addr: 127.0.0.1:8848
#在 MySQL 中创建数据库:midian,建表:DDL语句如下所示。
create database midian;
CREATE TABLE `punch_record` (
`id` int NOT NULL AUTO_INCREMENT,
`time` datetime DEFAULT NULL,
`open_id` varchar(63) DEFAULT NULL,
`nick_name` varchar(63) DEFAULT NULL,
`name` varchar(63) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='打卡记录表';
#分别启动 consumer 和 provider 两个项目(不区分先后顺序)。
1、先构建成jar包
cd swcourse-swcourse/swcourse-springcloud/
mvn clean package
#然后分别开启2个创建,进入对应的目录,执行两个模块,执行exec命名的
swcourse-springcloud-consumer/target
java -jar swcourse-springcloud-consumer-1.0.0-SNAPSHOT-exec.jar
cd swcourse-springcloud-provider/target
java -jar swcourse-springcloud-provider-1.0.0-SNAPSHOT-exec.jar
#启动成功后,通过http://localhost:8082/echo/333调用 Consumer 的接口,返回 Hello Nacos Discovery 333时代表项目搭建成功。
#如果启动失败了,或调用接口报错,则需要退出重新运行jar包。具体报错查看前台打印的日志
SkyWalking 安装,需要下载es7版本的安装包
#进入目录,找到`config/apllication.yaml`配置文件,这个配置文件隶属于服务层,主要用于配置 SkyWalking 的配置模块,存储组件,数据收集插件。修改 ES 存储组件,有密码的添加密码(也可以不配置,直接使用内存数据库H2)
vim apache-skywalking-apm-bin-es7/config/application.yml
storage:
selector: ${SW_STORAGE:elasticsearch7}
elasticsearch7:
nameSpace: ${SW_NAMESPACE:"elasticsearch"}
clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:127.0.0.1:9200}
user: ${SW_ES_USER:""}
password: ${SW_ES_PASSWORD:""}
#skywalking-webapp 默认监听在 8080 端口,很容易出现端口占用冲突的情况,可以通过修改webapp/webapp.yml 配置文件使用其它端口。
cat apache-skywalking-apm-bin-es7/webapp/webapp.yml
server:
port: 8088
collector:
path: /graphql
ribbon:
ReadTimeout: 10000
# Point to all backend's restHost:restPort, split by ,
listOfServers: 127.0.0.1:12800
#进入bin目录,sh startup.sh启动。
#使用 JPS 命令查看进程,OAPServerStartUp(服务层)和skywalking-webapp(展示层)代表启动成功
jps
3104 skywalking-webapp.jar
6738 jar
31107 Jps
11462 nacos-server.jar
3046 OAPServerStartUp
7293 jar
#启动之后访问 localhost:8088,稍等一会,看到下方所示的界面表示成功了一半。
springcloud项目使用
直接启动项目,携带skywalking-agent(Provider 和 Consumer 都需要)
#把上面启动的两个窗口取消,重新运行下面命令
配置路径:由于我们使用项目启动时进行加载,所以需要配置在启动时自己的 jar 包路径。
配置服务名称:服务层启动时,首先会去探针层的配置文件中读取服务名称,如果配置文件为空,则读取系统变量。
配置服务层地址:探针层获取数据后,需要上传到服务层进行数据加工。因此我们需要配置服务层IP和端口。
配置完成后启动项目,启动完成后刷新页面,可以看到当前应用的数据已经上传到服务层。
cd swcourse-springcloud-consumer/target
java -javaagent:/root/apache-skywalking-apm-bin-es7/agent/skywalking-agent.jar -Dskywalking.agent.service_name=consumer -Dskywalking.collector.backend_service=127.0.0.1:11800 -jar swcourse-springcloud-consumer-1.0.0-SNAPSHOT-exec.jar
cd swcourse-springcloud-provider/target
java -javaagent:/root/apache-skywalking-apm-bin-es7/agent/skywalking-agent.jar -Dskywalking.agent.service_name=provider -Dskywalking.collector.backend_service=127.0.0.1:11800 -jar swcourse-springcloud-provider-1.0.0-SNAPSHOT-exec.jar
功能展示:
APISIX对接skywalking
官方文档:https://apisix.apache.org/zh/docs/apisix/2.15/plugins/skywalking/
#修改helm配置文件,上报skywalking
vim values.yaml
plugins:
- ...
- skywalking #添加插件
vim values.yaml
pluginAttrs:
skywalking:
serice_name: APISIX
service_instance_name: "APISIX Insance Name"
endpoint_addr: http://192.168.28.9:12800
#然后dashboard上面启用插件即可,第一次测试配上路由规则,产生数据。uris这里是匹配的所有路径,转发到所有的worker节点
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"methods": ["GET"],
"uris": [
"/*"
],
"plugins": {
"skywalking": {
"sample_ratio": 1
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"192.168.28.9": 1,
"192.168.28.10": 2,
"192.168.28.11": 3
}
}
}'
curl -v http://127.0.0.1:9180/uid/12
#登录skywalking观察,有数据就代表对接成功。