写点什么

如何打造一个云原生背景下的可观测平台?

  • 2021 年 12 月 31 日
  • 本文字数:4774 字

    阅读完需:约 16 分钟

本文旨在介绍我司在服务治理道路上可观测能力建设落地过程中的一些实践,一些思路。

背景知识

随着近年来云原生概念和云原生架构设计的流行,越来越多的开发团队开始使用 DevOps 模式进行系统开发,并把大型系统拆解成一个个微小的服务模块,以便系统能更好地进行容器化部署。基于 DevOps、微服务、容器化等云原生的能力,可以帮助业务团队快速、持续、可靠和规模化地交付系统,同时也使得系统的复杂度成倍提升,由此带来了前所未有的运维挑战,比如:

  • 模块之间的调用从进程内的函数调用变为进程间的调用,而网络总是不可靠的。

  • 服务的调用路径变长,使得流量的走向变得不可控,故障排查的难度增大。

  • 引入 Kubernetes、Docker、Service Mesh 等云原生系统,基础设施层对业务开发团队来说变得更加黑盒。

在传统的监控系统中,我们往往会关注物理机的 CPU、内存、网络、应用服务的接口请求量、资源使用率等指标,但在复杂的云原生系统中,仅仅关注单点或者单个维度的指标,并不足以帮助我们掌握系统的整体运行状况。在此背景下,对分布式系统的“可观测性”应运而生。通常,我们认为可观测性相对于过去监控,最大的变化就是,系统需要处理的数据从指标为主,扩展到了更广的领域。综合起来,大约有几类数据被看作是可观测性的支柱:

  • Log,通过收集日志,对系统和各个服务的运行状态进行监控

  • Metric,通过收集指标,对系统和各个服务的性能进行监控

  • Trace,通过分布式追踪,追踪服务请求是如何在各个分布的组件中进行处理的细节

简介

什么是观测平台?

观测平台是一款应用性能管理(Application Performance Management,简称 APM)类监控平台。借助该平台,业务方可快速分析和诊断分布式应用架构下的性能瓶颈,提高微服务时代下的开发诊断效率。

  • 基于 skywalking 二开追踪分布式架构中的上下游依赖关系,绘制拓扑图,为您提供服务、接口、实例、中间件等多维度调用观测,助您掌控系统关键指标,及时发现错误调用与性能瓶颈。

  • 基于 TDengine+prometheus+观测平台+grafana 做 metric 的存储与展示。

  • 基于 bigstore+观测平台做日志的存储与展示。

解决了什么问题?

互联网业务的高速发展带来了日益增长的流量压力,业务逻辑也日趋复杂,传统的单机应用已经无法满足需求。越来越多的网站逐渐采用了分布式部署架构。同时,随着 Spring Cloud/Dubbo 等基础开发框架的不断成熟,越来越多的企业开始对网站架构按照业务模块进行垂直拆分,形成了更适合团队协同开发、快速迭代的微服务架构(Microservice Architechture)。

分布式的微服务架构在开发效率上具备先进性,但给传统的监控、运维、诊断技术带来了巨大挑战。以单创践行分布式架构与微服务实践的过程为例,遇到的主要挑战有:

  • 定位问题难

客服人员接到用户反馈商品购买出现问题后,会交由技术人员排查解决。而微服务分布式架构中的一个网站请求通常要经过多个服务/节点后返回结果。一旦请求出现错误,往往要在多台机器上反复翻看日志才能初步定位问题,对简单问题的排查也常常涉及多个团队。

  • 发现瓶颈难

当用户反馈网站出现卡顿现象,很难快速发现瓶颈在哪里:是用户终端到服务端的网络问题,是服务端负载过高导致响应变慢,还是数据库压力过大?即使定位到了导致卡顿的环节,也很难快速定位到代码层面的根本原因。

  • 架构梳理难

在业务逻辑变得逐渐复杂以后,很难从代码层面去梳理某个应用依赖了哪些下游服务(数据库、HTTP API、缓存),以及被哪些外部调用所依赖。业务逻辑的梳理、架构的治理和容量的规划(例如“双十一”促销活动的准备过程中,需要为每个应用准备多少台机器)也变得更加困难。

观测平台提供的应用监控的功能,基于开源框架 skywlking 二次开发,可以在不修改任何现有代码的情况下帮助开发人员和运维人员解决上述问题。

  • 调用拓扑图

您可以在观测平台中看到应用的调用关系拓扑图,例如应用被哪些服务依赖、依赖了哪些下游服务等。如下图所示,我们可以清楚地看到图中 pay-core 服务依赖了 Redis、RabbitMQ 和外部的一些 HTTP 服务。

  • 慢接口

进入该应用的接口监控,可以清楚的定位到具体的慢接口


  • 分布式调用链查询

点击慢接口的接口 Url,可以找到一条包含该接口调用的链路,并能看到调用耗时的地方会被标红(如下图 16ms、23ms),从而定位到调用链路瓶颈所在。

架构

概览


模块

日志

日志包括应用日志、网关访问日志、公网 ELB 日志。我们采用华为云 LTS 云日志服务将日志转储至云上 Kafka 集群(集群规模 9 台 1.5T 高速 ssd,900 分区上限),然后通过 log-parser 服务进行日志解析并存储至我司自研 bigstore 存储引擎。

日志解析存储流程

指标

指标包括 Jvm 指标、服务 SLA 指标、容器指标、业务自定义指标、中间件指标。我们通过探针的方式采集上报监控指标数据最终存储到 TDEngine 中,无须业务方修改一行代码。

指标数据采集上报流程


  1. 通过 Javaagent 技术在运行时修改目标类的字节码文件代理目标类的目标方法,从而采集相应的指标,并在应用进程内进行秒级聚合最终以 Json 的格式输出到日志文件中;

  2. 通过华为云 LTS 云日志服务转储日志至云上 Kafka 集群中;

  3. gather-server 服务消费指标日志流,写入 TDEngine(数据有效期为一年)。

指标读取流程

链路

我们通过二开 Skywalking 实现分布式追踪。

什么是分布式追踪

谷歌在 2010 年 4 月发表了一篇论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》,介绍了分布式追踪的概念。

对于分布式追踪,主要有以下几个概念:

  • 追踪 Trace

事务在分布式系统中移动时的描述。一个追踪,包含该事务提供服务的各个服务请求。

  • 跨度 Span

Span 是事务中的一个工作流,一个 Span 包含了时间戳,日志和标签信息。Span 之间包含父子关系,或者主从(Followup)关系。

  • 跨度上下文 Span Context

跨度上下文是支撑分布式追踪的关键,它可以在调用的服务之间传递,上下文的内容包括诸如:从一个服务传递到另一个服务的时间,追踪的 ID,Span 的 ID 还有其它需要从上游服务传递到下游服务的信息。

什么是 Span?

Span 是链路中的一个工作流,每个 Span 包含以下对象:

  • Operation name:操作名,标识该操作是什么

  • Start timestamp:起始时间。

  • Finish timestamp:结束时间。

  • Span tag:一组键值对构成的 Span 标签集合,用户可以加入任何对追踪有意义的信息。

  • Span log:一组 Span 的日志集合。用于捕获调试信息,或者相关 Span 的相关信息。

  • SpanContext:Span 上下文,SpanContext 负责向子微服务系统边界传递数据。它主要包含两个部分:

  • Trace ID,Span ID。需要跨进程传输。

  • 行李项 (Baggage Item)。如果把微服务调用比做从一个城市到另一个城市的飞行, 那么 SpanContext 就可以看成是飞机运载的内容。Trace ID 和 Span ID 就像是航班号,而行李项就像是运送的行李。每次服务调用,用户都可以决定发送不同的行李,也需要跨进程传输。

  • References(Span 间关系):相关的零个或者多个 Span(Span 间通过 SpanContext 建立这种关系)。

什么是调用链(Trace)?

在广义上,一个调用链代表一个事务或者流程在(分布式)系统中的执行过程。在OpenTracing标准中,调用链是多个 Span 组成的一个有向无环图,每一个 Span 代表调用链中被命名并计时的连续性执行片段。

下图是一个分布式调用的例子:客户端发起请求,请求首先到达负载均衡器,接着经过认证服务、计费服务,然后请求资源,最后返回结果。



数据被采集存储后,分布式追踪系统一般会选择使用包含时间轴的时序图来呈现这个调用链。


OpenTracing中的调用链(Trace)通过归属于此调用链的 Span 来隐性地定义。一条调用链可以视为一个由多个 Span 组成的有向无环图(DAG 图)。例如下面的示例调用链就是由 8 个 Span 组成的。

一个Trace中Span间的因果关系

[Span A] ←←←(The root span) | +------+------+ | | [Span B] [Span C] ←←←(Span C是Span A的子节点,ChildOf) | | [Span D] +---+-------+ | | [Span E] [Span F] >>> [Span G] >>> [Span H] (Span G在Span F后被调用, FollowsFrom)
复制代码

有些情况下,使用下面这种基于时间轴的时序图可以更好地展现调用链。


一个Trace中Span间的时间关系

––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–> time
[Span A···················································] [Span B··············································] [Span D··········································] [Span C········································] [Span E·······] [Span F··] [Span G··] [Span H··]
复制代码


数据透传

透传数据分为两步,其中相同进程内还涉及到跨线程透传。

  1. 从请求中解析出 SpanContext。

inbound_request = ...
# We'll again use the (builtin) HTTP_HEADERS carrier format. Per the# HTTP_HEADERS documentation, we can use a map that has extraneous data# in it and let the OpenTracing implementation look for the subset# of key:value pairs it needs.## As such, we directly use the key:value `inbound_request.headers`# map as the carrier.carrier = inbound_request.headersspan_context = tracer.extract(opentracing.Format.HTTP_HEADERS, carrier)# Continue the trace given span_context. E.g.,span = tracer.start_span("...", child_of=span_context)
# (If `carrier` held trace data, `span` will now be ready to use.)
复制代码
  1. 将 SpanContext 注入到请求中。

span_context = ...outbound_request = ...
# We'll use the (builtin) HTTP_HEADERS carrier format. We# start by using an empty map as the carrier prior to the# call to `tracer.inject`.carrier = {}tracer.inject(span_context, opentracing.Format.HTTP_HEADERS, carrier)
# `carrier` now contains (opaque) key:value pairs which we pass# along over whatever wire protocol we already use.for key, value in carrier: outbound_request.headers[key] = escape(value)
复制代码

链路数据是如何上报的?

还有很多细节这里没有展开,比如说实现探针如何避免污染应用环境?SpanContext 如何跨线程透传?这篇文章就不一一展开了,感兴趣的读者可以查看

告警

有了指标数据,那么我们就可以基于这些指标数据进行告警。通过创建告警规则,可以制定针对特定监控场景的告警规则。当告警规则被触发时,系统会以用户指定的通知方式向告警联系人或飞书发送告警消息,以提醒用户采取必要的解决措施。

告警流程

我们将后台用户配置的告警规则存储到 Redis 队列中,由 Telemetry 服务的告警分析引擎实时拉取告警规则进行计算告警。由于告警规则都对应了具体的指标信息,所以我们拿到告警规则以后,就可以解析告警规则的语义,通过查询指标数据进而判断是否告警。当出现告警之后,我们也有很多选择,是选择发送告警?还是屏蔽告警?又或是告警需要被收敛?这些都可以通过相应的规则来控制。接下来我们看看告警分析引擎是如何工作的?

告警分析引擎

告警分析引擎负责分析具体的告警规则,最终决定是否产生告警以及产生告警之后告警位于的状态。

告警分析流程

告警规则模版

通过配置告警规则模版,可以减小业务方配置告警规则的复杂度。

告警规则

引用

发布于: 3 小时前
用户头像

还未添加个人签名 2021.01.27 加入

还未添加个人简介

评论

发布
暂无评论
如何打造一个云原生背景下的可观测平台?