服务心跳机制主要用于确认服务的存活状态,UAVStack的心跳数据还负责上报节点的容器及进程监控数据,支持在前端实时查看应用容器和进程的运行状态,并根据这些数据对容器和进程做出预警。
一、背景
在微服务架构中,服务心跳是一个简单但非常重要的机制,用于确认微服务的存活状态。UAVStack中的心跳是一个Http请求,MonitorAgent(以下简称MA)通过定时向HealthManager(以下简称HM)发送一个带有特定报文格式的Http请求完成一次心跳的发送过程。心跳报文含有发送时的时间戳,用于更新HM端的数据状态。
与普通的心跳不同,UAVStack中的心跳还负责上送MA端的应用容器和进程监控数据。每次发送心跳的时候,在MA端会有定时任务去收集MA所在的应用容器心跳的基本信息,及应用容器上的进程数据,随着心跳数据包一起上送。
本文将首先介绍UAVStack的基础心跳机制,之后对应用容器、进程的数据采集做详细说明。
二、基本架构
心跳的实现有很多种方式,心跳的发起可以由客户端发起也可以由服务端发起,只需完成确认存活这一基本功能即可。但是在一般的实现中,我们更倾向于客户端主动向服务端进行报告,因为当客户端逐渐增加,单纯通过服务端的轮询会导致服务端的压力,影响性能。
在UAVStack的实现中,我们也采用了这样的方式,通过客户端(MA)主动向服务端(HM)发送心跳信息,告知HM自身的存活情况。
一次心跳由UAV的MA和HM共同完成:
- MA定时生成心跳数据,携带MA节点的应用容器信息、进程信息以及服务信息,通过Http请求上报给HM;
- HM负责将接收到的心跳数据存入Redis缓存,并定时扫描心跳数据,确认节点的存活状态。对于随同的应用容器等监控信息,会在Redis进行暂存,后续随着HM的定时任务最终存入OpenTSDB进行落盘。整体的架构如下所示:
三、基础心跳机制
心跳服务主要流程如上图所示,其逻辑有以下几步:
1)MA的定时心跳任务生成一个空心跳数据,将心跳数据交给MA端的容器、进程数据采集任务。
2)MA端的容器、进程数据采集任务负责产生心跳数据的时间戳、采集节点的应用容器、进程监控数据、节点的基本信息、节点的可用服务信息等。经过以上过程之后,心跳数据将包含以下内容:
- 心跳时间戳:节点发送心跳时的时间戳,方便HM后续比对判定节点的存活状态。
- 应用容器的基本信息:包括节点ID、名称、主机名、IP等。
- 应用容器的简单监控数据:包括CPU负载、内存使用、硬盘使用等。
- 应用容器上的进程信息:包括每个进程的pid、资源占用等。
- 节点的能力信息:包括该节点上启用的Feature功能。
- 节点的服务信息:包括该节点上可提供的服务及其访问接口,用以实现服务发现。
- 可选)子节点的节点信息:如果MA和HM部署在不同的网段,则MA无法通过直接Http的方式推送数据给HM,此时需要MA将数据上送给自己网段内的HM,再由该HM的心跳客户端发送给总的HM。这种情况下,上报的数据中会携带子节点的节点信息。每个节点信息均会包含上述几种数据。
最后将心跳数据发送给HM。
3)HM端在接收到心跳数据之后,将其存入自身的Redis缓存。使用上报数据中的服务信息更新Redis中的服务状态,用于服务发现请求。
4)HM端在启动心跳接收服务时,会同时启动心跳检查任务。这个任务会定时扫描Redis中的心跳数据,根据当前系统时间与心跳时间戳的差,判断心跳节点的存活状态,更新节点的状态,并对于过期的节点做删除处理。
四、应用容器、进程数据采集
UAV的心跳数据除了完成心跳功能之外,还要上报节点的应用容器及进程的监控数据。
将应用容器与进程数据通过Http方式上报是为了保证应用容器监控数据与应用监控数据的隔离,通过不同方式的上送可以保证在MQ服务不能使用时不影响容器与进程数据的采集。
本节将集中说明这些数据的采集细节。
4.1 应用容器数据采集
应用容器的数据分为两部分:
其一是容器的基本信息,即节点的ID,主机名,系统信息和JVM信息等;
另一部分是一些简单的实时监控采集数据,包括CPU的负载、内存占用情况和磁盘占用情况等。这些数据在每次上报心跳数据的时候会分别从以下数据源实时采集:
- 应用启动后的System.getProperty:这部分数据主要包括操作系统的基本信息,JVM信息等。
- Java提供的工具类:这部分主要包括网卡信息。
- 通过JMX获取的信息:包括CPU占用、内存占用等。
- 系统本身记录的信息:这部分包括可提供的服务信息、启动的Feature信息、节点ID等。
- 通过执行系统命令得到的信息:包括磁盘占用情况。
- 通过直接读取/proc目录下的文件获取的信息:包括CPU占用、内存占用等。
4.2 进程数据采集
不同于应用容器数据采集,进程的数据并不是在心跳进程中进行采集的,而是由专门的Feature负责。在Feature中将进程数据采集进一步分解成进程端口流量数据采集以及其他数据采集。这两者均由定时任务完成,互相协作,最终由进程探测的定时任务更新心跳客户端的进程数据。
这种使用多个采集任务分别采集的方式可以针对不同的数据进行不同频度的采集。如对于网络端口流量的采集,就可以以更长的周期进行,以减低数据采集带来的性能损耗。同时,不同的任务也可以使用不同的线程执行,提升执行的效率。
进程数据采集流程大致如下图所示:
进程端口流量探测定时任务每隔一定时间读取本地变量端口列表,获取要采集的端口号。
之后对于Windows环境,采用JPcap获取网卡对象,并在网卡上设置tcp过滤器来统计一段时间内的端口流量。对于Linux环境则是直接通过调用Python脚本打开socket,分析流过的数据包获得。
获得全部端口上的流量数据后,任务会将采集数据交给进程数据采集任务,更新其本地变量,同时设置本次采集的时间戳。
进程探测定时任务由一系列子任务构成,在任务开始的时候,会先准备好一个Map结构的数据容器,用于存放采集到的进程信息,每个进程由pid区分,作为Map的key。
任务会先扫描所有的进程,获取pid和进程的端口。扫描到的进程会经过一个过滤器排除不需要采集数据的进程,之后正式采集每个进程上的数据。
对于每一个进程,会通过运行系统命令采集连接数、CPU、内存占用,磁盘读写数据以及网络端口流量数据。其中网络端口流量数据是由端口流量探测任务采集并更新的本地变量,而进程探测任务也会将扫描到的最新的端口列表更新到端口流量探测任务的本地变量。
如果应用是部署在容器上的,则还会有对应的容器信息采集。最后进程探测任务会将采集到的进程数据更新到心跳客户端的本地变量,随着每次心跳数据的生成被一起采集并上报。
进程数据的采集分别来自以下数据源:
- 系统命令:包括CPU、内存、连接数等(top等命令)
- /proc目录下各进程子目录:包括CPU、内存等信息、磁盘读写等信息
- 执行脚本:包括Linux环境下的端口流量数据采集
- 第三方工具包:包括win环境下的端口流量数据采集(JPcap)
五、HM处理
心跳数据和容器数据在通过Http上送到HM端之后,会由HM端对应的服务进行处理。
HM在启动时会启动自己的心跳客户端,负责发送本机的心跳数据和采集HM所在容器的监控数据。同时还会启动一个心跳服务,负责接收处理所有上送的心跳和容器数据信息。
心跳服务在收到心跳数据请求后,会根据HM的配置,判定当前的HM是不是Master节点。如果HM是Master节点,心跳服务会从Http携带的报文中拿出上报的数据,取得上报节点中的可用服务用于更新服务发现信息,之后将数据存入后端的Redis缓存中;如果不是Master节点,则会将数据移交至本机的心跳客户端,由其下次发送心跳时一起上送。
这样的设计是考虑到大规模监控时会有跨机房的情况存在,此时各监控节点往往不在同一个网段内,通过将同一个网段内的机器上交到边界的“网关”统一上交可解决这一问题。此时的HM即充当着“网关”这一角色。
HM在启动的时候同时还会启动一个定时任务,这个任务负责处理各节点的存活状况。任务定时从Redis中读取全部心跳数据,依次检查上送心跳数据中的客户端时间戳与当前系统时间戳的差值。
当时间超过一定的上送时间间隔之后,更改对应的节点存活状态。当超过一倍上送时间间隔,意味节点可能死亡,处于dying状态。当超过两倍时间间隔时,意味着节点已经死亡。当超过三倍时间间隔时,心跳服务会删除该节点的缓存记录。
随心跳一起上报的容器和进程数据会随着心跳数据一同被存入Redis中,后续由HM的其他定时任务读取并发送给预警中心进行处理,最终监控指标被格式化成特定的结构存入OpenTSDB。
同时采集的容器数据和进程数据会提供前端AppHub查看界面,如图所示:
点击页面上的每一个节点,可以查看详细的节点信息,包括节点的操作系统信息、JVM信息、提供的服务和安装的Feture等等。这些也就是前文所说的随心跳数据上报的那部分信息。如图所示:
六、总结
心跳是微服务架构基础但重要的机制,通过定时发送心跳数据,MA节点报告了自身的存活状态,使得HM能够知晓当前系统的运行状态。
同时,UAVStack的心跳数据还同时负责上报节点的容器及进程监控数据,随着这些数据的上报,HM可以对监控的容器和进程做出预警,也能够在前端实时看到应用容器和进程的运行状态。
官方网站:https://uavorg.github.io/main/
开源地址:https://github.com/uavorg
拓展阅读:宜信开源|UAVStack的慢SQL数据库监控功能及其实现
作者:张明明
来源:宜信技术学院
原文地址:https://blog.51cto.com/14159827/2415857