一、前言
1、微服务关联复杂性
在当前云原生与DevOps、PaaS技术应用背景下,微服务化是一个显著的特征。所谓微服务,简单来说就是将过去的大型单体应用按照功能职能,划定交互边界,拆分为一个个小型的微服务汇总而成最终的产品交付。
微服务带来的好处自不必多说,例如敏捷性、灵活扩展、轻松部署等。但是当整个云服务愈发复杂、架构愈发繁琐时,我们发现微服务的模式也存在一些缺陷,其中之一就是海量微服务的交互与关联问题。
以笔者的实践为例,一些普通的单体工具服务,其分拆的微服务可能有30-50个之多,而对于综合交互的工具平台服务,最终的微服务数量可能会达到上千个!这其中微服务之间彼此关联、相互依赖,形成一种繁杂的网状交织结构。发现、分析具体微服务的关联关系迫在眉睫。
2、告警信息获取与展示
除了复杂的微服务关联关系外,海量的微服务所涉及的故障与告警也愈发难以观测和处理。
诚然,随着技术的进步,各种监控工具、观测维度愈发成熟,但同样带来了数据越来越多、越来越分散负责的问题。例如,对于一个微服务而言:
- 基础设施层可能有对应的CPU、内存、数据库等指标监控;
- 中间件层可能会有对应的Kafka队列、Redis等监控与告警;
- 应用层可能会有调用链、接口异常调用状态码、日志关键字等监控告警;
- 业务层可能会有诸如URL拨测、健康巡检等类型的监控与告警;
- 各个环节还存在服务自定义的相关监控与告警(例如Prometheus监控与定义告警);
以笔者的实践看来,即使有告警智能汇聚于压缩的帮助,服务每天依旧要面对着成百上千、来自各个监控告警平台的告警提示,如何能直观的观测告警的来源、分布以及具体影响(爆炸半径),同样是一个需要重视和解决的问题。
二、服务拓扑构造
基于上述的论点,首先需要做的,就是尝试找出繁杂的微服务之间的关联关系。这里,我们主要通过以下几个维度做判断与构造,并最终做数据层面的融合。
1、基于架构设计
首先,服务的关联关系应该在最初的产品定义与设计时就应该有相应的规划与确定,这里主要是 “4+1视图”:分别为逻辑视图、物理视图、处理流程视图、开发视图,以及最后的场景视图。
-
逻辑视图
- 用于描述系统的功能需求,即系统给用户提供哪些服务;以及描述系统软件功能拆解后的组件关系、组件约束和边界,反映系统整体组成与系统如何构建的过程。在UML中由类图来表示。
-
物理视图
- 物理视图,也成为部署视图,开发出的软件系统,最终是要运行在物理或软件环境上。物理环境可能是服务器、PC机、移动终端等物理设备;软件环境可以是虚拟机、容器、进程或线程。部署视图就是对这个部署信息进行描述。在UML中通常由部署图表示。
-
处理视图
- 处理视图,又称过程视图、运行视图、行为视图。用于描述系统软件组件之间的通信时序,数据的输入输出。在UML中通常由时序图和流程图表示。
- 运行视图的设计,最常见的是逻辑架构元素之间的交互关系,比如消息交互、服务调用或API调用。
-
开发视图
- 开发视图关注软件开发环境下实际模块的组织,反映系统开发实施过程。一个设计良好的开发视图,应该能够满足以下要求:通过逻辑架构元素,能够找到它所有代码和所有的二进制交付件 每一个代码源文件,都能够找到它所属的逻辑架构元素 每一个二进制交付件,都能够找到它集成了哪些逻辑架构元素。
-
场景视图
- 场景视图,也成为用例视图,即4+1中的1。从前面的图可以看到,4+1中的4个视图都是围绕着场景视图为核心的。它用于描述系统的参与者与功能用例间的关系,反映系统的最终需求和交互设计。在UML中通常由用例图表示。
- 系统边界:有了边界,才能够确定系统的设计范围;同时,通过边界能够识别出系统需要与用户或其它系统进行交互;
- 系统用户:明确的用户定义是系统需求分析的先决条件;
- 功能和场景:通过识别出系统与用户或其它系统的交互,可以分析出系统需要提供哪些功能,以及这些功能存在哪些应用场景;
- 场景视图,也成为用例视图,即4+1中的1。从前面的图可以看到,4+1中的4个视图都是围绕着场景视图为核心的。它用于描述系统的参与者与功能用例间的关系,反映系统的最终需求和交互设计。在UML中通常由用例图表示。
在完成上述4+1视图的设计过程中,其中的关键点之一就是确定系统功能与边界、并定义不同系统间的交互形式:API、数据流等。
因此,在设计态我们能够完成服务间依赖关系的基本确定。
2、基于接口调用
除了设计态的关联关系外,我们还会从运行态的视角、以接口调用来判断。一般而言,设计态是较为理想的情况,实际使用时会根据现实情况做很多新接口的开放与使用,因此运行态的关联一般是更贴合实际的。
这里,假若服务A通过接口b调用了服务B,那么我们人为服务A和B是存在关联关系的,并且服务A依赖于服务B。
-
接口网关注册
- 在云的背景下,服务之间的接口对外暴露提供原则上均需要通过APIG网关来实现;
- 对于服务A,假如其希望使用服务B的开放接口b,那么需要在APIG平台申请该接口的授权;
- 当服务B的接口b开放给服务A时,这些均在APIG平台操作与记录,逻辑抽象上看一条接口依赖就完成了;
- 因此,基于整个网关的接口开放暴露于接口授权访问信息,就能够形成完整的服务依赖关系网;
-
接口实际调用
- 除了基于网关调用与授权的模式外,还存在不少直接调用接口的访问形式,这些信息通过调用链数据记录;
- 对于服务A与服务B,若服务完成APM探针的配置,那么A与B之间所有的后台调用均在APM平台完成汇总与统计;
- 这里,由于接口调用数据是海量的,因此通常会用到一些大数据分析工具,以完成单条调用到聚合调用的整理;
- 聚合分析后,可以得到以服务视角的接口调用与被调用者,还能知悉接口本身调用量等信息;
- 完成服务间的接口调用关系提取后,与网关注册信息做并集,即可得到更为正确与完成的关联关系网;
- 这里还有一些质量改进专项:本身跨服务的接口访问是需要走网关的,直接调用存在很多安全、过载流控等风险;
- 因此,对于这类接口,我们还可以反向推动服务去完成开放接口的规范授权与使用。
3、关联重要等级
通过架构设计与接口调用的方法,我们虽然能获取较为全面的服务间依赖关系网络,但是对于一个服务而言可能会有十几个关联依赖服务、上百条依赖关系,如何找出其中具体重要的依赖于被依赖关系?
- 服务A与服务B在设计时考虑了某种依赖关系,但实际应用落地时却发现该依赖属细枝末节,并不重要;
- 服务B虽然给服务A授权了接口b,但可能出现两种情况:
- 服务A调用量非常低,近乎为0;
- 服务A调用量比较高,但接口b对于A而言并不重要(例如普通的健康检查接口),即使挂了对A的核心特性并无影响;
- 服务A和B均依赖于服务C,但服务A是普通内部服务,服务B是核心对外服务;
上述的问题旨在说明:服务之间的关联关系是有权重之分的,识别判断这种权重也非常重要。对于权重等级的判断,我们一般通过如下几种方法:
-
服务重要程度
- 对于服务而言,一般会根据重要程度不同从高到低分级为T0-T4,依赖等级同样可以按照T0-T4进行划分;
- 假如服务A通过接口b依赖于服务B:
- 如果A的重要程度较高,接口b挂了对A会造成影响,那么此时的依赖b我们会认为是重要依赖;
- 如果服务A只是一个低级别服务,即使整个服务A挂了也无妨,那么依赖b我们只会认为是一般依赖;
-
接口重要程度
-
核心接口定义
- 对于接口而言,本身在做需求分解、API设计时,就会对接口的一系列形式、参数、属性与功能做完整定义;
- 根据接口职能的不同,API本身也会按照T0-T4的等级进行划分;
- 对于类似鉴权、核心数据查询等类型接口,如果失效了会造成非常严重的影响,对于这类接口我们会认为是核心依赖;
- 对于类似健康度巡检类型的接口,即使挂了对调用方而言也不会影响核心功能,此时我们会认为是一般依赖;
-
调用次数判断
- 通过调用次数的多少,我们在某种程度上也可以判断接口的重要程度;
- 调用次数多,一般而言就越重要;调用次数少,则不是很重要;
- 当然,这里也一定存在例外,例如上面的健康检查类接口,可能1分钟就要调用多次,但本身重要程度并不高,因此这里还需要具体问题、具体分析,做进一步的人为标定;
-
核心接口定义
-
人为标定
- 除了上述自动定义服务关联依赖等级外,我们一般也会从设计态做人为的依赖创建于等级标定;
- 通常是一些非接口类依赖(例如数据面依赖),以及一些调用次数少、但重要程度较高接口等;
在完成了关联关系重要等级的确定后,对于繁杂的服务关联关系,我们在做展示与渲染是就可以很方便地突出重点,将其中的强依赖加粗、换用其他颜色进行呈现。
三、告警关联展示
在完成服务关联关系的识别、构造与重要依赖标定后,我们对繁杂的微服务网便有了一个较为清晰的观测视角,也对整体的架构有了较为明确的认知。
除了上述的优势外,告警在服务关联关系图上的拓扑映射,能够很好地解决我们“海量的微服务所涉及的故障与告警也愈发难以观测和处理”问题,同时进阶的一些辅助定界与影响分析的手段也是提升质量看护的。
由于整体服务关联关系图本质上是一种有向图,因此对于图中的边与节点,其故障发生的告警映射分别对应“接口级别故障”以及“服务级别故障”。
同时,面对服务外部依赖可能失效的问题,我们需要有相应的依赖降级措施,避免故障进一步严重化、降低影响范围。
最后,除了故障告警的直接渲染展示外,我们还需要有一些故障定界与影响分析的手段,二者是很大的课题,这里仅做简单介绍。
1、接口级故障展示
- 故障告警来源:日志、调用链状态码、拨测;
- 主要用来快速展示服务之间的连接故障情况;
- 渲染要点:
- 根据告警发生与恢复情况,动态进行告警展示;
- 根据告警等级,选择不同的颜色做提示标记;
- 点击正在告警的有向边,能够进行数据下钻、展示具体告警内容(故障接口详情、状态码情况、返回值等)
2、服务级故障展示
- 服务级故障本质上是接口级故障的父集,因为接口本身也一定属于该服务;
- 故障告警来源:涉及服务问题的所有类型——基础监控、应用层监控、接口级故障等等;
- 主要从来标记当前拓扑关系网中的所有故障点;
- 渲染要点:
- 根据告警发生与恢复情况,动态进行告警展示;
- 根据告警等级,选择不同的颜色做提示标记;
- 点击正在告警的服务节点,能够进行数据下钻、展示当前服务相关信息(OnCall责任人、架构部署形式、所有故障告警详情等)
3、依赖降级
顾名思义,服务间依赖不可避免,但是对于某些核心业务的强依赖而言,并不能假定下游依赖是100%可靠的,在依赖发生时如何降低故障对自身服务的影响、避免故障持续升级,是需要关注的核心问题之一。
这里,我们以鉴权故障为例。
在笔者的实践中,曾亲历过由于中央鉴权服务的故障、导致上百个服务同时故障的现网事故发生,其中故障等级随着影响面的扩大、故障等级最终被定在了P1。
在分析复盘后,相关核心服务均要求对于鉴权认证服务须具备依赖降级能力:
- 所谓鉴权服务,本质上就是根据用户角色、服务应用APPID等信息,提供机机场景或人机场景下对于资源访问的权限校验所需的Token;
- 当鉴权服务故障时,在没有依赖降级的情况下,所有涉及到鉴权的服务请求均会报错、造成连锁反应;
- 引入依赖降级后,服务会即使发现依赖的鉴权接口产生故障,此时:
- 服务本身会对已有机机和人机鉴权token保留一段时间在缓存,维持访问的可用性;
- 对于新增访问请求,在无鉴权token缓存的情况下,会做访问请求限流拦截、并做提示与用户安抚,避免报障激增升级;
- 需要注意的是,此降级非彼降级,主要是一种“去依赖”、避免故障持续升级的手段;
4、定界与影响分析
在服务发生故障、产生告警时,除了及时通知到服务外,我们还有对故障的定界与具体影响做相关分析的诉求。
对于故障定界而言:
- 所谓故障定界,即在故障发生时,尝试找到故障发生的根源服务与根源点所在;
- 通过告警信息渲染的服务关联拓扑图,以及服务的上下游关系,我们能够直观识别故障的具体产生点;
- 借助调用链的数据分析也能为定界提供信息参考;
- 需要注意的是,故障定界是一个业界难题,拓扑渲染仅能作为参考,很多情况下故障根因未必是拓扑故障根节点;
对于影响分析而言:文章来源:https://www.toymoban.com/news/detail-834058.html
- 所谓影响分析,即在故障产生时,具体影响面情况(影响服务与影响用户等),方便控制爆炸半径、及时故障降级;
- 通过服务接口故障传播调用链数据、接口被调用情况,来确定机机场景下故障影响的服务数;
- 通过故障产生时接口错误日志中对应的用户信息,来确定人机场景下故障具体影响的用户数;
- 通过全局服务关联与故障拓扑图,直观呈现故障影响面范围;
四、小结
云原生背景下的海量微服务带来的不仅是基于,更多的还有挑战。通过设计态与运行态的不同视角,对服务间关联关系进行挖掘发现,有利于化繁为简、识别真正重要的问题与潜在风险。同时,将各层级告警映射到服务关联拓扑之中,能够让我们快速发现与处理海量的微服务所涉及的故障与告警。文章来源地址https://www.toymoban.com/news/detail-834058.html
到了这里,关于海量微服务关联关系挖掘与告警拓扑展示的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!