编辑推荐: |
本文来自于infoq,本文主要描述了精简模式的架构,精简模式的主要特点在于部署简单,容易维护 。 |
当监控遇上微服务
在过去数年里,微服务的落地一直都是业界重点关注的问题,其始终面临着部署、监控、配置和治理等方面的挑战。轻舟微服务平台是网易云为企业提供的一套微服务解决方案,其中微服务监控是其关注的重点问题之一。与传统监控相比,微服务监控面临着更多难点,包括:
1.监控对象动态可变,无法进行预先配置;
2.监控范围非常繁杂,各类监控难以互相融合;
3.微服务实例间的调用关系非常复杂,故障排查会很困难;
4.微服务架构仍在快速发展,难以抽象出稳定的通用监控模型。
在工程角度也面临着不少考验,如:
1.在微服务架构里,软件系统通常会被拆分为数十甚至数百个微服务,这种拆分会使得监控数据爆炸增长,监控系统必须具备处理和展示这些数据的能力;
2.监控系统必须要保证可靠性,具体而言:保证不会因为单点故障而全局失效,监控数据有备份机制,系统各服务的实例均可通过备份数据得到恢复;
3.监控系统必须支持云上部署及快速水平扩容,这既是云原生的基本要求,也符合企业系统微服务化演进的实际情况。
微服务监控的技术选型
微服务监控的诸多挑战使得我们不得不慎重地进行技术选型。选择开源还是再造轮子,这个问题在项目初期一直困扰着我们,经过一段时间的调研和论证,开源项目 Prometheus 成了最终的答案。
Prometheus 是 CNCF 旗下的项目,该项目是一个用于系统和应用服务监控的软件,它能够以给定的时间间隔从给定目标中收集监控指标,并能够通过特定查询表达式获取查询结果。
选择 Prometheus 的主要原因是:
灵活的数据模型:在 Prometheus 里,监控数据是由值、时间戳和标签表组成的,其中监控数据的源信息是完全记录在标签表里的;同时 Prometheus 支持在监控数据采集阶段对监控数据的标签表进行修改,这使其具备强大的扩展能力;
强大的查询能力:Prometheus 提供有数据查询语言 PromQL。从表现上来看,PromQL 提供了大量的数据计算函数,大部分情况下用户都可以直接通过 PromQL 从 Prometheus 里查询到需要的聚合数据;
健全的生态: Prometheus 能够直接对常见操作系统、中间件、数据库、硬件及编程语言进行监控;同时社区提供有 Java/Golang/Ruby 语言客户端 SDK,用户能够快速实现自定义监控项及监控逻辑;
良好的性能:在性能方面来看,Prometheus 提供了 PromBench 基准测试,从最新测试结果来看,在硬件资源满足的情况下,Prometheus 单实例在每秒采集 10w 条监控数据的情况下,在数据处理和查询方面依然有着不错的性能表现;
更契合的架构:采用推模型的监控系统,客户端需要负责在服务端上进行注册及监控数据推送;而在 Prometheus 采用的拉模型架构里,具体的数据拉取行为是完全由服务端来决定的。服务端是可以基于某种服务发现机制来自动发现监控对象,多个服务端之间能够通过集群机制来实现数据分片。推模型想要实现相同的功能,通常需要客户端进行配合,这在微服务架构里是比较困难的;
成熟的社区:Prometheus 是 CNCF 组织第二个毕业的开源项目,拥有活跃的社区;成立至今,社区已经发布了一百多个 P 版本,项目在 GitHub 上获得的 star 数超过了 2 万。
Prometheus 虽然在上述六方面拥有优势,但其仍然难以满足微服务监控的所有需求,具体而言:
1.仅适用于维度监控,不能用于日志监控、分布式追踪等范围;
2.告警规则和告警联系人仅支持通过静态文件配置;
3.原生支持的数据聚合函数有限且不支持扩展;
这些不足都说明了一个事实,Prometheus 社区版并非微服务监控的最终答案。
我们的答案 - 轻舟微服务监控系统的设计
从大的方面来看,我们将微服务监控划分为维度监控、日志监控、分布式追踪等三部分。其中维度监控在整个微服务监控里最为重要,所占比例也最大,此类监控的层级有如下划分:
基础设施监控: 主要对各个微服务实例所在的基础设施进行监控,具体包括这些设施的运行状态、资源使用情况及系统日志进行监控,一般而言微服务应用实例会运行在容器里,因此这个维度的监控对象也通常包含有容器编排系统、持续构建系统、镜像仓库等,这些对象的具体监控指标的范围包括对象的健康状态、运行状态、资源使用情况等;
微服务通用监控:主要针对微服务通用指标进行监控,包括服务实例处理请求的情况及实例调用其它服务的情况,具体而言包括请求总数、请求处理时延(中位数,包括有 90、95 和 99 值)、请求结果(成功、失败、熔断、限流、超时和拒绝)统计、调用其它服务的结果(成功、失败、熔断、限流、超时和拒绝)统计及时延(中位数,包括有 90、95 和 99 值);
应用监控:主要对具体的微服务实例进行性能监控,通过数据自动化收集、数据可视化展示,使用户能够及时、全面地掌控各个实例的性能情况,定位性能瓶颈。这一维度重点在于提供丰富的应用性能展示及性能问题定位功能,包括应用响应时间、吞吐量和状态的展示,慢响应和错误明细的查询。
通用中间件:我们没有预置这个维度的监控到系统里,不过得益于 Prometheus 完善的生态,系统保留有对常用数据库、消息队列及缓存进行监控的能力,具体包括 MySQL、Redis、Memcached、Consul、RabbitMQ 及 Kafka 等。
在工程实现方面,我们进行了如下设计:
1.用 Prometheus 原生的联邦集群部署模式,使得全部监控数据分片处理;分片处理机制使得只需要增加实例个数就能够应对海量监控数据问题;
2.多 Prometheus 实例作用于同一监控对象,使得单一实例失效也不会影响到此对象的监控,满足高可用的要求;
3.监控系统所有组件及配置均实现容器化并由 Kubernetes 编排;理论上,在任意 Kubernetes 集群里都能够一键部署;系统需要变更时,仅需修改相关编排文件,即可完成改变。
对上文提到的几个 Prometheus 不足之处,我们进行了如下设计:
1.引入 ELK 实现日志监控,Logstash 负责采集日志,日志数据被保存到 Elasticsearch 里,用户则可以通过 Kibana 查询到具体应用的日志;
2.基于 OpenTracing 实现分布式追踪,最终完成了应用拓扑关系展示,调用链查询等功能;
3.对 Netflix Turbine 进行了二次开发,将微服务框架的秒级监控纳入到系统能力集里。
多场景多维度 - 轻舟监控系统的实现细节
从架构上来讲,轻舟微服务监控系统在设计时考虑到有多种用户场景,并为此设计了多种模式,包括精简模式、读写优化模式及多环境模式。
从整体上来看,我们使用了 Prometheus 经典的联邦集群部署方案,处于叶子节点的 Prometheus 分片采集处理监控数据;处于根节点的 Prometheus 则直接从各个叶子节点上拉取处理后的监控数据并负责处理外部的查询请求;告警服务则定期从位于根节点的 Prometheus 里查询监控数据,在发现数据达到阈值时发送告警通知至对应联系人。这个模式基本上解决了微服务监控的数据分片处理、多维度及系统可靠性问题,同时 ELK 系统及轻舟 APM 服务在日志监控和分布式追踪方面进行功能补充,在规模不大的时候是能够满足用户需求的。
在精简模式下,所有的维度监控数据都保存在本地磁盘里面,当本地磁盘发生问题时,数据会有丢失的风险;同时精简模式的可靠性主要靠多个 Prometheus 实例执行相同的监控任务来保证,多个实例之间实际上是没有数据同步的,这使得数据有不一致的风险。为了解决上述问题,我们在读写优化模式里加入了网易自研的分布式时序数据库 NTSDB,利用 Prometheus 的 Remote Write/Read 机制将监控数据存取操作实际交由 NTSDB 来处理。由于 NTSDB 自带数据同步机制,所以采用这种模式的数据安全性要高于第一种。
对于规模较大的用户而言,还会存在多个物理隔离的机房。这些机房之间通常仅能够通过网络专线通信。针对这种情况,我们设计了多环境模式,在这个模式里,每个环境的监控数据都保存在对应环境的 NTSDB 集群里,仅当需要进行数据查询时才会跨环境通信。这个模式在前两个模式之外,解决了微服务监控的多数据中心及多 AZ 问题。
维度监控是轻舟微服务监控系统的主要部分,其实现细节如下所述:
基础设施监控:就轻舟微服务平台的具体情况来看,主要指的是容器监控。轻舟微服务的容器编排系统是 Kubernetes,Prometheus 则原生支持 Kubernetes 服务发现机制,这使得我们解决了监控对象发现问题;同时 Kubernetes 各组件原生支持 Prometheus,开源社区也提供了 Node exporter、kube-state-metrics exporter 及 Ceph Exporter,这些组件已经能够满足全部功能需求,所以在基础设施监控上,系统完全采用了开源方案。
微服务框架监控:图 4 显示了这一维度监控的实现。在这一维度里,我们自研了两个组件,nsf-agent 和 nsf-turbine。nsf-agent 主要负责从服务实例里收集并上报原始监控数据;nsf-turbine 则主要负责接收 nsf-agnet 推送的监控数据,同时对原始监控数据进行聚合及通过暴露这些监控数据给 Prometheus;Prometheus 定期拉取 nsf-turbine 暴露的监控数据并为这些数据提供持久化及数据查询能力。另外,nsf-turbine 也提供了相对简单的监控数据查询接口,用户能够通过这个接口查询到当日的实时统计数据及秒级监控数据。
应用监控:从总的结构上来讲,应用监控分为客户端、Collector 及 WEB 服务端部分;其中客户端收集并上报应用的监控数据,这部分支持使用网易云自研的 APM 客户端或者开源的 Zipkin 及 Jaeger 客户端,自研的 APM 客户端能够以无代码侵入的方式进行数据采集,采集到的数据是满足 OpenTracing 规范的,各个客户端采集的监控数据将被上报到 Collector 里进行处理,处理后的数据将被保存到 MySQL、ElasticSearch 或 Redis 里;WEB 服务端部分则负责提供标准接口给 Prometheus 拉取数据。
当然,在基于 Prometheus 实现轻舟微服务监控系统的过程里,我们也踩了一些坑,如:
Prometheus 的各种计算函数都会对结果进行一定预估处理,其返回值通常都不是精确值。例如当聚合规则为获取过去一小时的监控值之和,但实际只收集到十五分钟监控数据时,这时候聚合出来的数据就是预估的值。如果需求非常精确的结果,需要通过客户端来聚合计算。
Prometheus 不支持定时整点进行聚合计算,只能计算过去一段时间的值 ; 无法获取到诸如当天零点到次日零点这种规则的聚合数据。如有类似于这种的需求,需要通过客户端直接聚合。
Prometheus 预定义的计算规则、查询表达式是非常多的,而且会根据具体需求进行变动,如果不采用版本管理工具来维护,是非常容易出错的。
新的起点 - 我们的进展以及未来
目前轻舟微服务监控系统已经具备了下面的特性:
高可用:在精简模式里,同一份监控数据至少由两个 Prometheus 实例来采集;在读写优化和多环境模式里,监控数据保存在分布式时序数据库 NTSDB 里;任意一个 Prometheus 失效都不会影响到系统的整体功能。
全局立体化:系统已经集成了基础设施、微服务及应用等三个维度的监控告警;在日志监控和分布式追踪等方面也提供了相应的日志及调用链查询审计功能;这些已经基本上涵盖了微服务监控的全部功能需求。
可动态调整:在前文提到的各种部署模式里,我们对监控数据的采集和处理进行了分片。目前系统支持通过调整数据分片配置及 Prometheus 实例数,来满足各种规模的微服务系统的监控需求。
另外,在不远的将来,我们还会在下面几个方面持续改进轻舟微服务监控系统:
1.系统自监控、智能监控及分布式追踪能力强化;
2.结合 Thanos、Druid 等组件,扩充部署模式及增强聚合能力;
3.增强监控及告警响应速度。
通过这些优化,轻舟微服务监控系统能够更好地为企业的微服务系统保驾护航。