1.什么是全链路监控?
在分布式微服务架构中,系统为了接收并处理一个前端用户请求,需要让多个微服务应用协同工作,其中的每一个微服务应用都可以用不同的编程语言构建,由不同的团队开发,并可以通过多个对等的应用实例实现水平扩展,甚至分布在横跨多个数据中心的数千台服务器上。单个用户请求会引发不同应用之间产生一串顺序性的调用关系,如果要对这些调用关系进行监控,了解每个应用如何调用,这就产生了全链路监控。
2.为什么要进行全链路监控?
在微服务架构中,服务会被拆分成多个模块,这些模块可能由不同的开发团队开发、维护,也可能使用不同的编程语言来实现、也有可能分布在多台服务器上,由于服务的拆分,单个用户的请求会经过多个微服务,相互之间形成复杂的调用关系,传统的监控手段已经不能实现如此复杂的链路之间的监控了,因此,就需要一些可以帮助理解系统行为、用于分析性能问题的工具,以便发生故障的时候,能够快速定位和解决问题。
3.全链路监控能解决哪些问题?
1. 请求链路追踪,故障快速定位:可以通过调用链结合业务日志快速定位错误信息。
2. 可视化: 各个阶段耗时,进行性能分析。
3. 依赖优化:各个调用环节的可用性、梳理服务依赖关系以及优化。
4. 数据分析,优化链路:可以得到用户的行为路径,汇总分析应用在很多业务场景。
4.常见的全链路监控工具
4.1 zipkin
github:
https://github.com/openzipkin/zipkin
zipkin是一个分布式的追踪系统,它能够帮助你收集服务架构中解决问题需要的时间数据,功能包括收集和查找这些数据。如果日志文件中有跟踪ID,可以直接跳转到它。否则,可以根据服务、操作名称、标记和持续时间等属性进行查询。例如在服务中花费的时间百分比,以及哪些环节操作失败。特点是轻量,使用部署简单。
zipkin还提供了一个UI界面,它能够显示通过每个应用程序的跟踪请求数。这有助于识别聚合行为,包括错误路径或对不推荐使用的服务的调用。
应用程序需要“检测”才能向Zipkin报告跟踪数据。这通常意味着需要配置一个用于追踪和检测的库。最流行的向Zipkin报告数据的方法是通过http或Kafka,尽管还有许多其他选项,如apache,activemq、gRPC和RabbitMQ。提供给UI存储数据的方法很多,如存储在内存中,或者使用受支持的后端(如apachecassandra或Elasticsearch)持久存储。
4.2 skywalking
github:
https://github.com/apache/incubator-skywalking
skywalking是本土开源的调用链追踪系统,包括监控、跟踪、诊断功能,目前已加入Apache孵化器,专门为微服务、云本地和基于容器(Docker、Kubernetes、Mesos)架构设计。
主要功能如下:
1)服务、服务实例、端点指标数据分析
2)根本原因分析,在运行时评测代码
3)服务拓扑图分析
4)服务、服务实例和端点依赖性分析
5)检测到慢速服务和终结点
6)性能优化
7)分布式跟踪和上下文传播
8)数据库访问度量。检测慢速数据库访问语句(包括SQL语句)。
9)报警
10)浏览器性能监视
4.3 pinpoint
github:
https://github.com/naver/pinpoint
pinpoint是韩国人开源的基于字节码注入的调用链分析,以及应用监控分析工具。Pinpoint提供了一个解决方案,可以帮助分析系统的整体结构,以及通过跟踪分布式应用程序中的事务来分析其中的组件是如何相互连接的。
功能如下:
1)一目了然地了解应用程序拓扑
2)实时监视应用程序
3)获得每个事务的代码级可见性
4)安装APM代理程序,无需更改一行代码
5)对性能的影响最小(资源使用量增加约3%)
Pinpoint的可视化UI界面:
4.4 jaeger
Jaeger 是受 Dapper 和 OpenZipkin 的启发,由 Uber Technologies 创建的分布式追踪平台,现已捐赠给云原生计算基金会。它可用于监视基于微服务的分布式系统:
- 分布式上下文传播
- 分布式交易监控
- 根本原因分析
- 服务依赖分析
- 性能/延迟优化
Jaeger为何物?
Jaeger 是Uber推出的一款开源分布式追踪系统,兼容OpenTracing API。分布式追踪系统用于记录请求范围内的信息。例如,一次远程方法调用的执行过程和耗时。是我们排查系统问题和系统性能的利器。
分布式追踪系统种类繁多,但是核心步骤有三个:代码埋点,数据存储和查询展示。
以上几句描述都是我copy的,所以大家想要对Jaeger有更加深入的了解,可以参阅这篇文章Jaeger 分布式追踪系统模块分析,能让你对Jaeger有一个简单的认识。
当然我们还要记得APM的三大模块分别是集中式日志系统,集中式度量系统和分布式全链接追踪系统。
而Jaeger
属于的就是追踪系统,度量系统我们则会使用prometheus
,日志系统一般则是elk
。
选用Jaeger的原因
一个是它兼容OpenTracing API,写起来简单方便,一个是UI相较于Zipkin的更加直观和丰富,还有一个则是sdk比较丰富,go语言编写,上传采用的是udp传输,效率高速度快。
相比Pinpoint的缺点,当然是UI差距了,基本上现在流行的追踪系统UI上都远远逊于它
5.全链路监控工具对比分析
市面上的全链路监控理论模型大多都是借鉴Google Dapper论文,本文重点关注以下三种APM组件:
APM = ApplicationPerformance Management,中文即应用性能管理
APM三大模块:集中式日志系统,集中式度量系统和分布式全链接追踪系统
1)Zipkin:由Twitter公司开源,开放源代码分布式的跟踪系统,用于收集服务的定时数据,以解决微服务架构中的延迟问题,包括:数据的收集、存储、查找和展现。
2)Pinpoint:一款对Java编写的大规模分布式系统的APM工具,由韩国人开源的分布式跟踪组件。
3)Skywalking:国产的优秀APM组件,是一个对JAVA分布式应用程序集群的业务运行情况进行追踪、告警和分析的系统。
4)Jaeger: uber开发的受Zipkin与docker启发,ui方面对比zipkin更加完善。
5.1 全面的调用链路数据分析
全面的调用链路数据分析,提供代码级别的可见性以便轻松定位失败点和瓶颈。
1.zipkin
zipkin的链路监控粒度相对没有那么细,调用链中具体到接口级别,再进一步的调用信息并未涉及。
2.skywalking
skywalking 支持20+的中间件、框架、类库,比如:主流的dubbo、Okhttp,还有DB和消息中间件。skywalking链路调用分析截取的比较简单,网关调用user服务,由于支持众多的中间件,所以skywalking链路调用分析比zipkin完备些。
3.pinpoint
pinpoint应该是这三种APM组件中,数据分析最为完备的组件。提供代码级别的可见性以便轻松定位失败点和瓶颈,上图可以看到对于执行的sql语句,都进行了记录。还可以配置报警规则等,设置每个应用对应的负责人,根据配置的规则报警,支持的中间件和框架也比较完备。
5.2 Pinpoint与Zipkin细化比较
5.2.1 pinpoint与zipkin差异性
1. Pinpoint 是一个完整的性能监控解决方案,有从探针、收集器、存储到 Web 界面等全套体系,而Zipkin只侧重收集器和存储服务,虽然也有用户界面,但其功能与Pinpoint不可同日而语。反而Zipkin提供有Query接口,更强大的用户界面和系统集成能力,可以基于该接口二次开发实现。
2. Zipkin 官方提供有基于 Finagle 框架(Scala 语言)的接口,而其他框架的接口由社区贡献,目前可以支持 Java、Scala、Node、Go、Python、Ruby 和 C# 等主流开发语言和框架;但是 Pinpoint 目前只有官方提供的 Java Agent 探针,其他的都在请求社区支援中。
3. Pinpoint 提供有 Java Agent 探针,通过字节码注入的方式实现调用拦截和数据收集,可以做到真正的代码无侵入,只需要在启动服务器的时候添加一些参数,就可以完成探针的部署,而 Zipkin的Java接口实现 Brave,只提供了基本的操作 API,如果需要与框架或者项目集成的话,就需要手动添加配置文件或增加代码。
4. Pinpoint 的后端存储基于 Hbase,而 Zipkin 基于 Cassandra。
5.2.2 pinpoint与zipkin相似性
pinpoint与zipkin都是基于Google Dapper的那篇论文,因此理论基础大致相同。两者都是将服务调用拆分成若干有级联关系的Span,通过SpanId和ParentSpanId来进行调用关系的级联,最后再将整个调用链流经的所有的Span汇聚成一个 Trace,报告给服务端的collector进行收集和存储。
即便在这一点上,Pinpoint 所采用的概念也不完全与那篇论文一致。比如他采用 TransactionId 来取代 TraceId,而真正的 TraceId 是一个结构,里面包含了 TransactionId, SpanId 和 ParentSpanId。而且 Pinpoint 在 Span 下面又增加了一个 SpanEvent 结构,用来记录一个 Span 内部的调用细节(比如具体的方法调用等等),因此 Pinpoint 默认会比 Zipkin 记录更多的跟踪数据。但是理论上并没有限定 Span 的粒度大小,所以一个服务调用可以是一个 Span,那么每个服务中的方法调用也可以是个 Span,这样的话,其实 Brave 也可以跟踪到方法调用级别,只是具体实现并没有这样做而已。
互动:
1.span是什么?
基本工作单元,一次链路调用(可以是RPC,DB等没有特定的限制)创建一个span,通过一个64位ID标识它,uuid较为方便,span中还有其他的数据,例如描述信息,时间戳,key-value对的(Annotation)tag信息,parent_id等,其中parent-id可以表示span调用链路来源。
上图说明了span在一次大的跟踪过程中是什么样的。Dapper记录了span名称,以及每个span的ID和父ID,以重建在一次追踪过程中不同span之间的关系。如果一个span没有父ID被称为root span。所有span都挂在一个特定的跟踪上,也共用一个跟踪id。
Span数据结构: type Span struct { TraceID int64 #用于标示一次完整的请求id Name string ID int64 #当前这次调用span_id ParentID int64 #上层服务的调用span_id 最上层服务parent_id为null Annotation []Annotation #用于标记的时间戳 Debug bool
2. Trace是什么?
类似于 树结构的Span集合,表示一次完整的跟踪,从请求到服务器开始,服务器返回response结束,跟踪每次rpc调用的耗时,存在唯一标识trace_id。比如:你运行的分布式大数据存储一次Trace就由你的一次请求组成。
每种颜色的note标注了一个span,一条链路通过TraceId唯一标识,Span标识发起的请求信息。树节点是整个架构的基本单元,而每一个节点又是对span的引用。节点之间的连线表示的span和它的父span直接的关系。虽然span在日志文件中只是简单的代表span的开始和结束时间,他们在整个树形结构中却是相对独立的。
部署pinpoint服务
安装docker: yum install -y docker-ce-19.03.7-3.el7 systemctl enable docker && systemctl start docker #查看docker状态,如果状态是active(running),说明docker是正常运行状态 systemctl status docker 修改docker配置文件 cat > /etc/docker/daemon.json <<EOF { "registry-mirrors":["https://rsbud4vc.mirror.aliyuncs.com","https://registry.docker-cn.com","https://docker.mirrors.ustc.edu.cn","https://dockerhub.azk8s.cn","http://hub-mirror.c.163.com","http://qtid6917.mirror.aliyuncs.com"], "exec-opts":["native.cgroupdriver=systemd"], "log-driver":"json-file", "log-opts": { "max-size": "100m" }, "storage-driver":"overlay2", "storage-opts": [ "overlay2.override_kernel_check=true" ] } EOF 注: "registry-mirrors":["https://rsbud4vc.mirror.aliyuncs.com","https://registry.docker-cn.com","https://docker.mirrors.ustc.edu.cn","https://dockerhub.azk8s.cn","http://hub-mirror.c.163.com","http://qtid6917.mirror.aliyuncs.com"] 上面配置的是镜像加速器 cat > /etc/docker/daemon.json <<EOF { "insecure-registries":["192.168.0.56"], "registry-mirrors":["https://rsbud4vc.mirror.aliyuncs.com","https://registry.docker-cn.com","https://docker.mirrors.ustc.edu.cn","https://dockerhub.azk8s.cn","http://hub-mirror.c.163.com","http://qtid6917.mirror.aliyuncs.com"], "exec-opts":["native.cgroupdriver=systemd"], "log-driver":"json-file", "log-opts": { "max-size": "100m" }, "storage-driver":"overlay2", "storage-opts": [ "overlay2.override_kernel_check=true" ] } EOF "insecure-registries":["192.168.40.132"] #配置的是harbor私有镜像仓库地址 重启docker使配置生效 systemctl daemon-reload && systemctl restart docker && systemctl status docker 开启机器的bridge模式 #临时生效 echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables echo 1 >/proc/sys/net/bridge/bridge-nf-call-ip6tables #永久生效 echo """ vm.swappiness = 0 net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 net.bridge.bridge-nf-call-ip6tables = 1 """ > /etc/sysctl.conf sysctl -p
pinpoint service部署
github地址:
ttps://github.com/pinpoint-apm/pinpoint-docker.git
unzip pinpoint-docker-2.0.1.zip cd pinpoint-docker-2.0.1 修改docker-compose.yml文件的version版本,如2.2,变成自己支持的版本 version: "3.6" 变成 version: "2.2" #拉取镜像 yum install docker-compose -y docker-compose pull #启动服务 docker-compose up -d #查看对应的服务是否启动 docker ps | grep pinpoint #找到pinpoint-web,可看到在宿主机绑定的端口是8079, 在浏览器访问ip:8079即可访问pinpoint的web ui界面
部署pinpoint agent
把microservic-test-dev1.zip上传到k8s的master1节点,解压:
unzip microservic-test-dev1.zip
下载地址:https://github.com/pinpoint-apm/pinpoint/releases/download/1.8.5/pinpoint-agent-1.8.5.tar.gz
将agent包一并传入镜像中 jar包启动 通过agent代理
例如:
FROM java:8-jdk-alpine RUN apk add -U tzdata && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime COPY ./target/eureka-service.jar ./ COPY pinpoint /pinpoint EXPOSE 8888 CMD java -jar -javaagent:/pinpoint/pinpoint-bootstrap-1.8.5.jar -Dpinpoint.agentId=${HOSTNAME} -Dpinpoint.applicationName=ms-eureka -Deureka.instance.hostname=${MY_POD_NAME}.eureka.ms /eureka-service.jar