提示:学习记录
APM概述:
早期监控工具功能比较单一,主要以监控CPU使用率、I/O、内存资源、网速等网络基础设施为主(cacti、nagios)
后来随着中间件技术的不断发展,APM也开始监控缓存、数据库、MQ等各种基础组件的性能(zabbix、prometheus)
微服务兴起之后,系统功能被模块化,再加上k8s与容器化的兴起及应用数量的爆炸式增长,各模块和服务之的调用链路、响应时间、负载等越来越不好通过传统的工具进行监控和统计,此时APM系统诞生了(应运而生)。
监控应用程序调用的中间件的性能(依赖调用):应用程序也可能由于其依赖的中间件或者其它的API的性能有问题、例如被调用的数据库、缓存、Web 服务器、第三方服务等响应慢而导致应用程序变慢,因此不仅要监控应用程序自身,还要监控其所有的外部依赖项。
在代码级别实现性能分析:通过在代码级别分析应用程序中的class等,APM工具可以深入了解并分析导致应用程序性能较低的代码,另外目前安卓、IOS等手机APP都有Agent用于记录APP的启动时间、首屏加载时间、使用的网络类型、版本信息、崩溃记录等信息并提交到服务端进行统计分析和展示。
监控应用程序资源使用情况:监控资源使用情况尤其是CPU和内存的使用情况至关重要(如java程序的内存使用等),尤其是想根据资源利用率实现自动弹性伸缩应用程序。
统一展示监控数据和日志:应用程序的性能统计、访问和错误日志在统一的平台进行展示(devops运维平台),方便快速查询与故障定位
- APM项目
CAT: 由国内美团点评开源的,基于Java语言开发,目前提供Java、C/C++、Node.js、Python、Go等语言的客户端,监控数据会全量统计,国内很多公司在用,例如美团点评、携程、拼多多等,CAT需要开发人员手动在应用程序中埋点,对代码侵入性比较强。
Zipkin: 由Twitter公司开发并开源,基于Java语言实现,侵入性相对于CAT要低一点,需要对web.xml等相关配置文件进行修改,但依然对系统有一定的侵入性,Zipkin可以轻松与Spring Cloud进行集成,也是Spring Cloud推荐的APM系统。
jaeger 是Uber推出的一款开源分布式追踪系统,主要使用go语言开发,对业务代码侵入性较少。
Pinpoint: 韩国团队开源的APM产品,运用了字节码增强技术,只需要在启动时添加启动参数即可实现APM功能,对代码无侵入,目前支持Java和 PHP语言,底层采用HBase来存储数据,探针收集的数据粒度非常细,但性能损耗较大,因其出现的时间较长,完成度也很高,文档也较为丰富,应用的公司较多。
SkyWalking: Skywalking是由国内开源爱好者吴晟开源并提交到Apache孵化器的开源项目,2017年12月SkyWalking成为Apache国内首个个人孵化项目,2019年4月17日SkyWalking从Apache基金会的孵化器毕业成为顶级项目,目前SkyWalking支持Java、.Net、Node.js、go、python等探针,数据存储支持MySQL、ElasticSearch等,SkyWalking与Pinpoint相同,对业务代码无侵入,不过探针采集数据粒度相较于Pinpoint来说略粗,但性能表现优秀,目前SkyWalking增长势头强劲,社区活跃,中文文档齐全,没有语言障碍,支持多语言探针,这些都是 SkyWalking的优势所在,还有就是SkyWalking支持很多框架,包括很多国产框架,例如,Dubbo、gRPC、SOFARPC 等等,同时也有很多开发者正在不断向社区提供更多插件以支持更多组件无缝接入SkyWalking。
开源:piwik等 #http://blogs.studylinux.net/?p=750
商业的:百度统计/growingio等
skywalking 基于谷歌的dapper设计理念
- 设计要求
i. 无处不在的部署: 任务服务都i应该被监控到
ii. 持续的监控: 7*24- 设计目标
i. 低消耗,对服务影响最小,CPU、内存尽可能低
ii. 对应用透明,不用植入代码
iii. 可伸缩性:针对未来众多的服务和大规模业务集群- 请求链路
i. 为每次请求添加跟踪标识符(timestamped events)
ii. 基于dapper或类似的跟踪系统,跟踪客户额完整请求
todo: Apm系统对比
注:测试虚拟机系统都是Ubuntu20.04LTS
简化安装elasticsearch,关闭SSL校验,单机部署。通过deb安装上传elasticearch的deb安装包
dpkg -i elasticsearch-8.5.2-amd64.deb
修改elasticsearch配置文件
grep -v '#' /etc/elasticsearch/elasticsearch.yml | grep -v '^$'
cluster.name: my-application
node.name: db-node-1
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
network.host: 192.168.182.62
http.port: 9200
discovery.seed_hosts: ["192.168.182.62"]
cluster.initial_master_nodes: ["192.168.182.62"]
xpack.security.enabled: false
xpack.security.enrollment.enabled: false
xpack.security.http.ssl:
enabled: true
keystore.path: certs/http.p12
xpack.security.transport.ssl:
enabled: true
verification_mode: certificate
keystore.path: certs/transport.p12
truststore.path: certs/transport.p12
http.host: 0.0.0.0
启动服务查看服务状态
通过插件链接查看链接成功,由于没有配置认证,直接链接成功
skywalking官网下载链接地址
apt update && apt install openjdk-11-jdk -y
root@skywalking-server:/apps# tar xvf apache-skywalking-apm-9.3.0.tar.gz
ln -sv /apps/apache-skywalking-apm-bin/ /apps/skywalking
vim /apps/skywalking/config/application.yml
storage:
selector: ${SW_STORAGE:elasticsearch}
vim /etc/systemd/system/skywalking.service
[Unit]
Description=Apache Skywalking
After=network.target
[Service]
Type=oneshot
User=root
WorkingDirectory=/apps/skywalking/bin/
ExecStart=/bin/bash /apps/skywalking/bin/startup.sh
RemainAfterExit=yes
RestartSec=5
[Install]
WantedBy=multi-user.target
# 启动服务
systemctl daemon-reload && systemctl restart skywalking.service && systemctl enable skywalking.service
skywalking端口
8080–UI端口 。12800–http端口(用于接收agent发送的http请求)。11800–gRPC端口(用于接收gRPC客户端发发送的数据)
前端访问空白,F12查看有接口报错500,遂取查看服务日志:
/data/skywalking-agent/config/agent.config
agent.service_name=${SW_AGENT_NAME:Halo-agent}
agent.namespace=${SW_AGENT_NAMESPACE:Halo1}
collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:192.168.182.61:11800}
apt update && apt install openjdk-11-jdk -y
java -javaagent:/data/skywalking-agent/skywalking-agent.jar -jar /apps/halo-1.6.1.jar
# 生产环境启动命令参考
java -javaagent:/skywalking-agent/skywalking-agent.jar \
-DSW_AGENT_NAMESPACE=xyz \
-DSW_AGENT_NAME=abc-application \
-Dskywalking.collector.backend_service=skywalking.abc.xyz.com:11800 \
-jar abc-xyz-1.0-SNAPSHOT.jar
vim /apps/apache-tomcat/bin/catalina.sh
# 加入启动命令参数
CATALINA_OPTS="$CATALINA_OPTS -javaagent:/data/skywalking-agent/skywalking-agent.jar -Dskywalking.collector.backend_service=192.168.182.61:11800 -Dskywalking.agent.service_name=Jenkins -Dskywalking.agent.namespace=Jenkins-namespace"; export CATALINA_OPTS
- service:服务列表,服务svc表示对请求提供相同行为的一系列或一组工作负载,在使用agent或者SDK的时候,可以自定义服务的名字,如果不定义,skywalking将会使用你在平台上定义的名字
load(cals/min): 每分钟访问次数;success Rate(%):成功率;latency(ms):延迟时间;apdex:应用性能指数- topology:拓扑图
- log:日志
Service Apdex(数字):当前服务的评分
Successful Rate(数字):请求成功率
Service Load (calls / min) 数字: 分钟请求数
Service Avg Response Times(ms):平均响应延时,单位ms
Service Apdex(折线图):一段时间内Apdex评分
Service Response Time Percentile (ms)折线图:服务响应时间百分比
Service Load (calls / min) 折线图: 分钟请求数
Success Rate (%)折线图:分钟请求成功百分比
Message Queue Consuming Count(折线图):消息队列消耗计数
Message Queue Avg Consuming Latency (ms)折线图:消息队列平均消耗延迟(毫秒)
Service Instances Load (calls / min):节点请求次数
Slow Service Instance (ms):每个服务实例(物理机、云主机、pod)的最大延时
Service Instance Success Rate (%):每个服务实例的请求成功率
Endpoint Load in Current Service (calls / min):每个端点(URL)的请求次数
Slow Endpoints in Current Service (ms):当前端点(URL)的最慢响应时间
Success Rate in Current Service (%):当前服务成功率(%)
微服务发现需要借助注册中心,常用zookeeper,类似K8S中的svc
本实验需要有服务端和客户端,服务端创建新的虚拟机,安装zk以及服务端,客户端安装在elasticsearch服务器上
不论服务端还是客户端,都需要安装skywalking javaagent
此次测试用的服务端和客户端都依赖jdk8
apt update && apt install openjdk-8-jdk -y
cp /apps/apache-zookeeper-3.7.1-bin/conf/zoo_sample.cfg /apps/apache-zookeeper-3.7.1-bin/conf/zoo.cfg
/apps/apache-zookeeper-3.7.1-bin/bin/zkServer.sh start
# 查看端口是否起来
lsof -i:2181
root@unbntu-sev-2:/data# grep -e collector.backend_service -e agent.namespace -e agent.service_name /data/skywalking-agent/config/agent.config | grep -v '#'
agent.service_name=${SW_AGENT_NAME:dubbo-server1}
agent.namespace=${SW_AGENT_NAMESPACE:dubbo}
collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:skywalking.example.com:11800}
# 配置本机hosts配置,识别域名解析
echo "192.168.182.61 skywalking.example.com" >> /etc/hosts
mkdir -p /apps/dubbo/provider
/apps/dubbo/provider/dubbo-server.jar
# 配置环境变量zk地址
vim /etc/profile
export ZK_SERVER1=192.168.182.64
# 使配置生效
source /etc/profile
# 验证配置
root@unbntu-sev-2:/apps# echo $ZK_SERVER1
java -javaagent:/data/skywalking-agent/skywalking-agent.jar -jar /apps/dubbo/provider/dubbo-server.jar
apt update && apt install openjdk-8-jdk -y
# 客户端上传至路径如下
/apps/dubbo/consumer/dubbo-client.jar
# 环境变量增加ZK配置
# 配置环境变量zk地址
vim /etc/profile
export ZK_SERVER1=192.168.182.64
# 使配置生效
source /etc/profile
root@db-elasticsearch:/data# grep -e collector.backend_service -e agent.namespace -e agent.service_name /data/skywalking-agent/config/agent.config | grep -v '#'
agent.service_name=${SW_AGENT_NAME:dubbo-consumer1}
agent.namespace=${SW_AGENT_NAMESPACE:dubbo}
collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:skywalking.example.com:11800}
# 增加本地hosts配置
echo "192.168.182.61 skywalking.example.com" >> /etc/hosts
java -javaagent:/data/skywalking-agent/skywalking-agent.jar -jar /apps/dubbo/consumer/dubbo-client.jar
dobboadmin依赖jdk8,直接在上面的服务器 dubbo-zk上安装
cd /apps/apache-tomcat-8.5.84/webapps/
rm -rf ./*
mv /home/zja/dubboadmin.war ./
unzip dubboadmin.war
# 修改ZK配置
cat /apps/apache-tomcat-8.5.84/webapps/dubboadmin/WEB-INF/dubbo.properties
dubbo.registry.address=zookeeper://$ZK_SERVER1:2181
dubbo.admin.root.password=root
dubbo.admin.guest.password=guest
# 查看环境变量(上面设置过,直接引用)
`这里直接引用环境变量启动不生效,后面替换为了IP或者域名!`
root@dubbo-zk:/apps/apache-tomcat-8.5.84/webapps# echo $ZK_SERVER1
192.168.182.64
/apps/apache-tomcat-8.5.84/bin/catalina.sh run
# 修改tomcat监听端口为8081,然后重启服务
vim /apps/apache-tomcat-8.5.84/conf/server.xml
<Connector port="8081" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
# 重新启动服务
/apps/apache-tomcat-8.5.84/bin/catalina.sh run
vim /apps/apache-tomcat-8.5.84/webapps/dubboadmin/WEB-INF/dubbo.properties
#dubbo.registry.address=zookeeper://192.168.182.64:2181
dubbo.registry.address=zookeeper://zookeeper1.zja.svc.local:2181
dubbo.admin.root.password=root
dubbo.admin.guest.password=guest
# 直接使用IP或者配置域名,服务可以正常启动
echo "192.168.182.64 zookeeper1.zja.svc.local" >> /etc/hosts
# 告警核心指标,参考文件 core.oal
cat /apps/skywalking/config/oal/core.oal
- service_resp_time #服务的响应时间
- service_sla #服务的http请求成功率SLA,比如99%等。
- service_cpm #表示每分钟的吞吐量. service_apdex : 应用性能指数是0.8是0.x
- service_percentile: 指定最近多少数据范围内的响应时间百分比,即p99, p95, p90, p75, p50在内的数据统计结果
- endpoint_relation_cpm #端点的每分钟的吞吐量
- endpoint_relation_resp_time #端点的响应时间
- endpoint_relation_sla #端点的http请求成功率SLA,比如99%等。
- endpoint_relation_percentile ##端点的最近多少数据范围内的响应时间百分比,即p99、p95、p90、p75、p50在内的数据统计结果
# 备份原告警alarm文件,然后自定义测试配置文件
cp /apps/skywalking/config/alarm-settings.yml /apps/skywalking/config/alarm-settings.yml-bak
vim /apps/skywalking/config/alarm-settings.yml
rules: # 定义rule规则
service_cpm_rule: # 唯一的规则名称,必须以_rule结尾
# Metrics value need to be long, double or int
metrics-name: service_cpm # 指标名称
op: ">" # 操作符,>, >= , <, <= , ==
threshold: 1 #指标阈值
# The length of time to evaluate the metrics
period: 2 #评估指标的间隔周期
# How many times after the metrics match the condition, will trigger alarm
count: 1 #匹配成功多少次就会触发告警
# How many times of checks, the alarm keeps silence after alarm triggered, default as same as period. #silence-period: 3
silence-period: 2 #触发告警后的静默时间
message: "dubbo-provider service_cpm 请求次数大于1了" #告警信息
dingtalkHooks:
textTemplate: |-
{
"msgtype": "text",
"text": {
"content": "Apache SkyWalking Alarm: \n %s."
}
}
webhooks:
- url: https://oapi.dingtalk.com/robot/send?access_token=dd9dbe4db622af7419b733a719e0c19f7794bbcc78fe394b985a7073b3fd5eb6 #注意钉钉关键字
# 修改完配置需要重启服务使配置生效!!
systemctl restart skywalking.service
需要安装python3,在dubo-zk服务器安装python进行测试
skywalking-python agent 官网指导链接
# 安装python3以及pip命令
apt install python3 -y
apt install python3-pip -y
# 安装skywalking模块
pip3 install "apache-skywalking"
from skywalking import agent, config
config.init(collector_address='192.168.182.61:11800', service_name='python-app-test') #测试注册
agent.start()
cd /apps/django-test/
#- 安装依赖模块:
pip3 install -r requirements.txt
#- 创建django项目mysite,如果解压包里含有同名的mysite, rm -rf mysite,或者换个名字
django-admin startproject mysite
#- 创建应用
cd mysite
python3 manage.py startapp myapp
#- 初始化数据库
python3 manage.py makemigrations
python3 manage.py migrate
# ---
# 创建管理员,用于登录web控制台 root/root:
python3 manage.py createsuperuser
# skywarking环境变量:
export SW_AGENT_NAME='python-app1-django'
export SW_AGENT_NAMESPACE='python-project'
export SW_AGENT_COLLECTOR_BACKEND_SERVICES='192.168.182.61:11800'
# 修改配置,允许任何客户端可以访问:
vim mysite/settings.py
ALLOWED_HOSTS = ["*",]
# 启动服务
sw-python -d run python3 manage.py runserver 192.168.182.64:80
OpenResty 是基于nginx做的二次开发,兼容nginx配置并支持LUA
nginx是通过lua扩展,需要将nginx重新编译,用来支持lua
# 编译环境
apt install iproute2 ntpdate tcpdump telnet traceroute nfs-kernel-server nfs-common lrzsz tree openssl libssl-dev libpcre3 libpcre3-dev zlib1g-dev ntpdate tcpdump telnet traceroute gcc openssh-server lrzsz tree openssl libssl-dev libpcre3 libpcre3-dev zlib1g-dev ntpdate tcpdump telnet traceroute iotop unzip zip
cd /apps
wget https://openresty.org/download/openresty-1.21.4.1.tar.gz
tar xvf openresty-1.21.4.1.tar.gz
cd openresty-1.21.4.1/
./configure --prefix=/apps/openresty \
--with-luajit \
--with-pcre \
--with-http_iconv_module \
--with-http_realip_module \
--with-http_sub_module \
--with-http_stub_status_module \
--with-stream \
--with-stream_ssl_module
make && make install
/apps/openresty/bin/openresty -t
# 启动服务
/apps/openresty/bin/openresty
https://github.com/apache/skywalking-nginx-lua
cd /data/
wget https://github.com/apache/skywalking-nginx-lua/archive/refs/tags/v0.6.0.tar.gz
# 修改安装包名字更容易识别
mv v0.6.0.tar.gz skywalking-nginx-lua-v0.6.0.tar.gz
tar xvf skywalking-nginx-lua-v0.6.0.tar.gz
cd /apps/openresty/nginx/conf/
vim nginx.conf
include /apps/openresty/nginx/conf/conf.d/*.conf;
mkdir conf.d
vim /apps/openresty/nginx/conf/conf.d/www.myserver.com.conf
lua_package_path "/data/skywalking-nginx-lua-0.6.0/lib/?.lua;;";
# Buffer represents the register inform and the queue of the finished segment
lua_shared_dict tracing_buffer 100m;
# Init is the timer setter and keeper
# Setup an infinite loop timer to do register and trace report.
init_worker_by_lua_block {
local metadata_buffer = ngx.shared.tracing_buffer
metadata_buffer:set('serviceName', 'myserver-openresty-nginx') ---#在skywalking 显示的当前server 名称,用于区分事件是有哪个服务产生的
-- Instance means the number of Nginx deloyment, does not mean the worker instances
metadata_buffer:set('serviceInstanceName', 'myserver-openresty-nginx-node1') --- #当前示例名称,用户事件是在那台服务器产生的 startBackendTimer 配置域名会有问题,暂时使用IP写死
-- type 'boolean', mark the entrySpan include host/domain
metadata_buffer:set('includeHostInEntrySpan', false) ---#在span信息中包含主机信息
-- set randomseed
require("skywalking.util").set_randomseed()
require("skywalking.client"):startBackendTimer("http://192.168.182.61:12800")
-- Any time you want to stop reporting metrics, call `destroyBackendTimer`
-- require("skywalking.client"):destroyBackendTimer()
-- If there is a bug of this `tablepool` implementation, we can
-- disable it in this way
-- require("skywalking.util").disable_tablepool()
skywalking_tracer = require("skywalking.tracer")
}
server {
listen 80;
server_name www.myserver.com;
location / {
root html;
index index.html index.htm;
#手动配置的一个上游服务名称或DNS名称,在skywalking会显示此名称
rewrite_by_lua_block {
------------------------------------------------------
-- NOTICE, this should be changed manually
-- This variable represents the upstream logic address
-- Please set them as service logic name or DNS name
--
-- Currently, we can not have the upstream real network address
------------------------------------------------------
skywalking_tracer:start("www.myserver.com")
-- If you want correlation custom data to the downstream service
-- skywalking_tracer:start("upstream service", {custom = "custom_value"})
}
#用于修改响应内容(注入JS)
body_filter_by_lua_block {
if ngx.arg[2] then
skywalking_tracer:finish()
end
}
#记录日志
log_by_lua_block {
skywalking_tracer:prepareForReport()
}
}
location /myserver {
default_type text/html;
rewrite_by_lua_block {
------------------------------------------------------
-- NOTICE, this should be changed manually
-- This variable represents the upstream logic address
-- Please set them as service logic name or DNS name
--
-- Currently, we can not have the upstream real network address
------------------------------------------------------
skywalking_tracer:start("www.myserver.com")
-- If you want correlation custom data to the downstream service
-- skywalking_tracer:start("upstream service", {custom = "custom_value"})
}
# 62节点部署单机服务 apache
proxy_pass http://192.168.182.62;
body_filter_by_lua_block {
if ngx.arg[2] then
skywalking_tracer:finish()
end
}
log_by_lua_block {
skywalking_tracer:prepareForReport()
}
}
location /hello {
default_type text/html;
rewrite_by_lua_block {
------------------------------------------------------
-- NOTICE, this should be changed manually
-- This variable represents the upstream logic address
-- Please set them as service logic name or DNS name
--
-- Currently, we can not have the upstream real network address
------------------------------------------------------
skywalking_tracer:start("www.myserver.com")
-- If you want correlation custom data to the downstream service
-- skywalking_tracer:start("upstream service", {custom = "custom_value"})
}
# 稳定掌门在在62节点部署的微服务客户端
proxy_pass http://192.168.182.62:8080;
body_filter_by_lua_block {
if ngx.arg[2] then
skywalking_tracer:finish()
end
}
log_by_lua_block {
skywalking_tracer:prepareForReport()
}
}
}
# 62节点安装单机apache,用来测试上面配置文件中的路径/myserver
apt install apache2
systemctl restart apache2.service
# 同时需要创建myserver路径
/var/www/html/myserver/index.html
<h1> this is apache2 myserver page </h1>
root@dubbo-zk:/apps/openresty/nginx/conf/conf.d# /apps/openresty/nginx/sbin/nginx -t
nginx: the configuration file /apps/openresty/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/openresty/nginx/conf/nginx.conf test is successful
# 加载配置使生效
/apps/openresty/nginx/sbin/nginx -s reload
测试软件包下载地址:[gitee下载地址](https://gitee.com/my_zja/geek-edu-apps/tree/master/skywalking)
图片来源:skywalking链路追踪 ↩︎