乐趣区

关于后端:微服务架构之服务监控与追踪

与单体利用相比,在微服务架构下,一次用户调用会因为服务化拆分后,变成多个不同服务之间的互相调用,每个服务可能是由不同的团队开发,应用了不同的编程语言,还有可能部署在不同的机器上,散布在不同的数据中心,这也就须要对拆分后的每个服务做监控并追踪服务调用。

如何做服务监控?

实现服务监控,咱们须要搞清楚三个问题:监控的对象是什么?具体监控哪些指标?从哪些维度进行监控?

监控对象

对于微服务零碎来说,监控对象能够分为四个档次,由上到下可演绎为:

  • 用户端监控。通常是指业务间接对用户提供的性能的监控。以微博首页 Feed 为例,它向用户提供了聚合关注的所有人的微博并依照工夫程序浏览的性能,对首页 Feed 性能的监控就属于用户端的监控。
  • 接口监控。通常是指业务提供的性能所依赖的具体 RPC 接口的监控。持续以微博首页 Feed 为例,这个性能依赖于用户关注了哪些人的关系服务,每个人发过哪些微博的微博列表服务,以及每条微博具体内容是什么的内容服务,对这几个服务的调用状况的监控就属于接口监控。
  • 资源监控。通常是指某个接口依赖的资源的监控。比方用户关注了哪些人的关系服务应用的是 Redis 来存储关注列表,对 Redis 的监控就属于资源监控。
  • 根底监控。通常是指对服务器自身的健康状况的监控。次要包含 CPU 利用率、内存使用量、I/ O 读写量、网卡带宽等。对服务器的根本监控也是必不可少的,因为服务器自身的健康状况也是影响服务自身的一个重要因素,比方服务器自身连贯的网络交换机上联带宽被打满,会影响所有部署在这台服务器上的业务。

监控指标

通常有以下几个业务指标须要重点监控:

  • 申请量。申请量监控分为两个维度,一个是实时申请量,一个是统计申请量。实时申请量用 QPS(Queries Per Second)即每秒查问次数来掂量,它反映了服务调用的实时变动状况。统计申请量个别用 PV(Page View)即一段时间内用户的访问量来掂量,比方一天的 PV 代表了服务一天的申请量,通常用来统计报表。
  • 响应工夫。大多数状况下,能够用一段时间内所有调用的均匀耗时来反映申请的响应工夫。但它只代表了申请的均匀快慢状况,有时候咱们更关怀慢申请的数量。为此须要把响应工夫划分为多个区间,比方 0~10ms、10ms~50ms、50ms~100ms、100ms~500ms、500ms 以上这五个区间,其中 500ms 以上这个区间内的申请数就代表了慢申请量,失常状况下,这个区间内的申请数应该靠近于 0;在呈现问题时,这个区间内的申请数会大幅减少,可能均匀耗时并不能反映出这一变动。除此之外,还能够从 P90、P95、P99、P999 角度来监控申请的响应工夫,比方 P99 = 500ms,意思是 99% 的申请响应工夫在 500ms 以内,它代表了申请的服务质量,即 SLA。
  • 错误率。错误率的监控通常用一段时间内调用失败的次数占调用总次数的比率来掂量,比方对于接口的错误率个别用接口返回错误码为 503 的比率来示意。

监控维度

一般来说,要从多个维度来对业务进行监控,具体来讲能够包含上面几个维度:

  • 全局维度。从整体角度监控对象的的申请量、均匀耗时以及错误率,全局维度的监控个别是为了让你对监控对象的调用状况有个整体理解。
  • 分机房维度。个别为了业务的高可用性,服务通常部署在不止一个机房,因为不同机房地区的不同,同一个监控对象的各种指标可能会相差很大,所以须要深刻到机房外部去理解。
  • 单机维度。即使是在同一个机房外部,可能因为洽购年份和批次的不同,位于不同机器上的同一个监控对象的各种指标也会有很大差别。一般来说,新洽购的机器通常因为老本更低,配置也更高,在等同申请量的状况下,可能体现出较大的性能差别,因而也须要从单机维度去监控同一个对象。
  • 工夫维度。同一个监控对象,在每天的同一时刻各种指标通常也不会一样,这种差别要么是由业务变更导致,要么是经营流动导致。为了理解监控对象各种指标的变动,通常须要与一天前、一周前、一个月前,甚至三个月前做比拟。
  • 外围维度。依据我的教训,业务上个别会根据重要性水平对监控对象进行分级,最简略的是分成外围业务和非核心业务。外围业务和非核心业务在部署上必须隔离,离开监控,这样能力对外围业务做重点保障。

对于一个微服务来说,必须明确要监控哪些对象、哪些指标,并且还要从不同的维度进行监控,能力把握微服务的调用状况 。明确了这几个要害的问题后,那么该如何搭建一个监控零碎,来实现下面这些监控性能呢?

监控零碎原理

显然,咱们要对服务调用进行监控,首先要能收集到每一次调用的详细信息,包含调用的响应工夫、调用是否胜利、调用的发起者和接收者别离是谁,这个过程叫作数据采集。采集到数据之后,要把数据通过肯定的形式传输给数据处理核心进行解决,这个过程叫作数据传输。数据传输过去后,数据处理核心再依照服务的维度进行聚合,计算出不同服务的申请量、响应工夫以及错误率等信息并存储起来,这个过程叫作数据处理。最初再通过接口或者 Dashboard 的模式对外展现服务的调用状况,这个过程叫作数据展现。

可见, 监控零碎次要包含四个环节:数据采集、数据传输、数据处理和数据展现

1. 数据采集

通常有两种数据收集形式:

  • 服务被动上报,这种解决形式通过在业务代码或者服务框架里退出数据收集代码逻辑,在每一次服务调用实现后,被动上报服务的调用信息。
  • 代理收集,这种解决形式通过服务调用后把调用的详细信息记录到本地日志文件中,而后再通过代理去解析本地日志文件,而后再上报服务的调用信息。

无论哪种数据采集形式,首先要思考的问题就是采样率,也就是采集数据的频率。采样率决定了监控的实时性与精确度,一般来说,采样率越高,监控的实时性就越高,精确度也越高。但采样对系统自身的性能也会有肯定的影响,尤其是采集后的数据须要写到本地磁盘的时候,过高的采样率会导致系统写入磁盘的 I / O 过高,进而会影响到失常的服务调用。所以设置正当的采用率是数据采集的要害,最好是能够动态控制采样率,在零碎比拟闲暇的时候加大采样率,谋求监控的实时性与精确度;在零碎负载比拟高的时候减小采样率,谋求监控的可用性与零碎的稳定性。

2. 数据传输

数据传输最罕用的形式有两种:

  • UDP 传输,这种解决形式是数据处理单元提供服务器的申请地址,数据采集后通过 UDP 协定与服务器建设连贯,而后把数据发送过来。
  • Kafka 传输,这种解决形式是数据采集后发送到指定的 Topic,而后数据处理单元再订阅对应的 Topic,就能够从 Kafka 音讯队列中读取到对应的数据。

无论采纳哪种传输方式,数据格式都非常重要,尤其是对带宽敏感以及解析性能要求比拟高的场景,个别数据传输时采纳的数据格式有两种:

  • 二进制协定,最罕用的就是 PB 对象,它的长处是高压缩比和高性能,能够缩小传输带宽并且序列化和反序列化效率特地高。
  • 文本协定,最罕用的就是 JSON 字符串,它的长处是可读性好,但相比于 PB 对象,传输占用带宽高,并且解析性能也要差一些。

3. 数据处理

数据处理是对收集来的原始数据进行聚合并存储。数据聚合通常有两个维度:

  • 接口维度聚合,这个维度是把实时收到的数据依照接口名维度实时聚合在一起,这样就能够失去每个接口的实时申请量、均匀耗时等信息。
  • 机器维度聚合,这个维度是把实时收到的数据依照调用的节点维度聚合在一起,这样就能够从单机维度去查看每个接口的实时申请量、均匀耗时等信息。

聚合后的数据须要长久化到数据库中存储,所选用的数据库个别分为两种:

  • 索引数据库,比方 Elasticsearch,以倒排索引的数据结构存储,须要查问的时候,依据索引来查问。
  • 时序数据库,比方 OpenTSDB,以时序序列数据的形式存储,查问的时候依照时序如 1min、5min 等维度来查问。

4. 数据展现

数据展现是把解决后的数据以 Dashboard 的形式展现给用户。数据展现有多种形式,比方曲线图、饼状图、格子图展现等。

  • 曲线图。个别是用来监控变化趋势的,比方上面的曲线图展现了监控对象随着时间推移的变化趋势,能够看进去这段时间内变动比拟小,曲线也比拟安稳。
  • 饼状图。个别是用来监控占比散布的,比方上面这张饼图展现了应用不同的手机网络占比状况,可见 Wi-Fi 和 4G 的占比显著要高于 3G 和 2G。
  • 格子图。次要做一些细粒度的监控,比方上面这张格子图代表了不同的机器的接口调用申请量和耗时状况,展现后果高深莫测。

如何追踪微服务调用?

在微服务架构下,因为进行了服务拆分,一次申请往往须要波及多个服务,你能够设想如果这次申请失败了,要想查分明到底是哪个利用导致,会是如许简单的一件事件。如果有一个零碎,能够跟踪记录一次用户申请都发动了哪些调用,通过哪些服务解决,并且记录每一次调用所波及的服务的详细信息,这时候如果产生调用失败,你就能够通过这个日志疾速定位是在哪个环节出了问题,解说如何实现服务追踪之前咱们先来理解服务追踪的作用

服务追踪的作用

  • 优化零碎瓶颈

通过记录调用通过的每一条链路上的耗时,咱们能疾速定位整个零碎的瓶颈点在哪里。比方你拜访微博首页发现很慢,必定是因为某种原因造成的,有可能是运营商网络提早,有可能是网关零碎异样,有可能是某个服务异样,还有可能是缓存或者数据库异样。通过服务追踪,能够从全局视角下来察看,找出整个零碎的瓶颈点所在,而后做出针对性的优化。

  • 优化链路调用

通过服务追踪能够剖析调用所通过的门路,而后评估是否正当。比方一个服务调用上游依赖了多个服务,通过调用链分析,能够评估是否每个依赖都是必要的,是否能够通过业务优化来缩小服务依赖。

还有就是,个别业务都会在多个数据中心都部署服务,以实现异地容灾,这个时候常常会呈现一种情况就是服务 A 调用了另外一个数据中心的服务 B,而没有调用同处于一个数据中心的服务 B。

依据我的教训,跨数据中心的调用视间隔远近都会有肯定的网络提早,像北京和广州这种几千公里间隔的网络提早可能达到 30ms 以上,这对于有些业务简直是不可承受的。通过对调用链路进行剖析,能够找出跨数据中心的服务调用,从而进行优化,尽量躲避这种状况呈现。

  • 生成网络拓扑

通过服务追踪零碎中记录的链路信息,能够生成一张零碎的网络调用拓扑图,它能够反映零碎都依赖了哪些服务,以及服务之间的调用关系是什么样的,能够高深莫测。除此之外,在网络拓扑图上还能够把服务调用的详细信息也标出来,也能起到服务监控的作用。

  • 通明传输数据

除了服务追踪,业务上常常有一种需要,冀望能把一些用户数据,从调用的开始始终往下传递,以便零碎中的各个服务都能获取到这个信息。比方业务想做一些 A / B 测试,这时候就想通过服务追踪零碎,把 A / B 测试的开关逻辑始终往下传递,通过的每一层服务都能获取到这个开关值,就可能对立进行 A / B 测试。

服务追踪零碎原理

Google 公布的一篇的论文 Dapper, a Large-Scale Distributed Systems Tracing Infrastructure,外面具体解说了服务追踪零碎的实现原理。它的核心理念就是 调用链 :通过一个全局惟一的 ID 将散布在各个服务节点上的同一次申请串联起来,从而还原原有的调用关系,能够追踪零碎问题、剖析调用数据并统计各种零碎指标。

能够说前面的诞生各种服务追踪零碎都是基于 Dapper 衍生进去的,比拟有名的有 Twitter 的 Zipkin、阿里的 鹰眼、美团的 MTrace 等。

要了解服务追踪的原理,首先必须搞懂一些基本概念:traceId、spanId、annonation 等。Dapper 这篇论文讲得比较清楚,但对初学者来说了解起来可能有点艰难,美团的 MTrace 的原理介绍了解起来绝对容易一些,上面我就以 MTrace 为例,给你具体讲述服务追踪零碎的实现原理。尽管原理有些艰涩,但却是你必须把握的,只有了解了服务追踪的基本概念,能力更好地将其实现进去。

首先看上面这张图,我来给你解说下服务追踪零碎中几个最基本概念。

  • traceId,用于标识某一次具体的申请 ID。当用户的申请进入零碎后,会在 RPC 调用网络的第一层生成一个全局惟一的 traceId,并且会随着每一层的 RPC 调用,一直往后传递,这样的话通过 traceId 就能够把一次用户申请在零碎中调用的门路串联起来。
  • spanId,用于标识一次 RPC 调用在分布式申请中的地位。当用户的申请进入零碎后,处在 RPC 调用网络的第一层 A 时 spanId 初始值是 0,进入下一层 RPC 调用 B 的时候 spanId 是 0.1,持续进入下一层 RPC 调用 C 时 spanId 是 0.1.1,而与 B 处在同一层的 RPC 调用 E 的 spanId 是 0.2,这样的话通过 spanId 就能够定位某一次 RPC 申请在零碎调用中所处的地位,以及它的上下游依赖别离是谁。
  • annotation,用于业务自定义埋点数据,能够是业务感兴趣的想上传到后端的数据,比方一次申请的用户 UID。

下面这三段内容我用艰深语言再给你小结一下,traceId 是用于串联某一次申请在零碎中通过的所有门路,spanId 是用于辨别零碎不同服务之间调用的先后关系,而 annotation 是用于业务自定义一些本人感兴趣的数据,在上传 traceId 和 spanId 这些根本信息之外,增加一些本人感兴趣的信息。

服务追踪零碎实现

讲到这里,你应该曾经了解服务追踪零碎里最重要的概念和原理了,咱们先来看看服务追踪零碎的架构,让你理解一下零碎全貌。

下面是服务追踪零碎架构图,你能够看到一个服务追踪零碎能够分为三层。

  • 数据采集层,负责数据埋点并上报。
  • 数据处理层,负责数据的存储与计算。
  • 数据展现层,负责数据的图形化展现。

上面来看看具体每一层的实现形式是什么样的。

1. 数据采集层

数据采集层的作用就是在零碎的各个不同模块中进行埋点,采集数据并上报给数据处理层进行解决。

那么该如何进行数据埋点呢?联合上面这张图来理解一下数据埋点的流程。

以红色方框里圈出的 A 调用 B 的过程为例,一次 RPC 申请能够分为四个阶段。

  • CS(Client Send)阶段 : 客户端发动申请,并生成调用的上下文。
  • SR(Server Recieve)阶段 : 服务端接管申请,并生成上下文。
  • SS(Server Send)阶段 : 服务端返回申请,这个阶段会将服务端上下文数据上报,上面这张图能够阐明上报的数据有:traceId=123456,spanId=0.1,appKey=B,method=B.method,start=103,duration=38。
  • CR(Client Recieve)阶段 : 客户端接管返回后果,这个阶段会将客户端上下文数据上报,上报的数据有:traceid=123456,spanId=0.1,appKey=A,method=B.method,start=103,duration=38。

2. 数据处理层

数据处理层的作用就是把数据采集层上报的数据按需计算,而后落地存储供查问应用。

据我所知,数据处理的需要个别分为两类,一类是实时计算需要,一类是离线计算需要。

实时计算需要对计算效率要求比拟高,个别要求对收集的链路数据可能在秒级别实现聚合计算,以供实时查问。而离线计算需要对计算效率要求就没那么高了,个别能在小时级别实现链路数据的聚合计算即可,个别用作数据汇总统计。针对这两类不同的数据处理需要,采纳的计算方法和存储也不雷同。

  • 实时数据处理

针对实时数据处理,个别采纳 Storm 或者 Spark Streaming 来对链路数据进行实时聚合加工,存储个别应用 OLTP 数据仓库,比方 HBase,应用 traceId 作为 RowKey,能人造地把一整条调用链聚合在一起,进步查问效率。

  • 离线数据处理

针对离线数据处理,个别通过运行 MapReduce 或者 Spark 批处理程序来对链路数据进行离线计算,存储个别应用 Hive。

3. 数据展现层

数据展现层的作用就是将解决后的链路信息以图形化的形式展现给用户。

依据我的教训,理论我的项目中次要用到两种图形展现,一种是调用链路图,一种是调用拓扑图。

  • 调用链路图

上面以一张 Zipkin 的调用链路图为例,通过这张图能够看出上面几个信息。

服务整体状况 :服务总耗时、服务调用的网络深度、每一层通过的零碎,以及多少次调用。下图展现的一次调用,总共耗时 209.323ms,通过了 5 个不同的零碎模块,调用深度为 7 层,共产生了 24 次零碎调用。

每一层的状况 :每一层产生了几次调用,以及每一层调用的耗时。

依据我的教训,调用链路图在理论我的项目中,次要是被用来做故障定位,比方某一次用户调用失败了,能够通过调用链路图查问这次用户调用通过了哪些环节,到底是哪一层的调用失败所导致。

  • 调用拓扑图

上面是一张 Pinpoint 的调用拓扑图,通过这张图能够看出零碎内都蕴含哪些利用,它们之间是什么关系,以及依赖调用的 QPS、均匀耗时状况。

调用拓扑图是一种全局视线图,在理论我的项目中,次要用作全局监控,用于发现零碎中异样的点,从而疾速做出决策。比方,某一个服务忽然出现异常,那么在调用链路拓扑图中能够看出对这个服务的调用耗时都变高了,能够用红色的图样标出来,用作监控报警。

总结

服务监控在微服务革新过程中的重要性显而易见,没有弱小的监控能力,革新成微服务架构后,就无奈掌控各个不同服务的状况,在遇到调用失败时,如果不能疾速发现零碎的问题,对于业务来说就是一场劫难,服务追踪也是分布式系统中必不可少的性能,它可能帮忙咱们查问一次用户申请在零碎中的具体执行门路,以及每一条门路的上下游的详细情况,对于追究问题非常有用。

本文由 mdnice 多平台公布

退出移动版