Serverless可观测性

 

整体解决方案

 

指标

确定指标

对于使用函数计算的用户而言,更关心的是业务逻辑,因此,常用的用户侧函数监控指标会包括以下几种:

函数的总执行次数;

函数的平均执行耗时;

关键错误类型的发生次数(超时、并发超限、5xx 系统故障等);

函数执行的资源使用情况;

而对于平台侧来说,往往更加关注的是函数计算的服务体系是否在正常工作以及涉及到的底层集群资源是否健康。因此,平台侧的系统监控通常会关注以下几个方面:

服务处理的总请求数量;

服务处理的失败请求数量;

单次扩缩容成功/失败的实例数量;

集群节点总数的整体变化趋势;

集群节点的资源使用情况;

服务节点的资源使用情况;

指标的收集与上报

基本工作原理是不断地向 Exporter(指标上报器)获取数据,而像 CPU、Disk、Memory 这类资源指标类型,可以利用 Promethues 官方提供的 node-exporter 进行采集。另外,对于集群和单节点的部署,也有了比较成熟的高可用解决方案。

这类具有时序关系的指标数据通常采用时序数据库 TSDB 进行存储。这类存储专门用来解决像监控指标这类产生频率快、种类繁多且强依赖于时间顺序的数据持久化的问题。

需要让 Prometheus 的收集工作更加稳定,也可以在每次请求处理完后,将指标存入消息队列,并通过消费的方式提前汇总一轮指标。汇总完成后,再将指标上报给 Prometheus 进行二次汇聚。加上上面提到的持久化方案,一个轻量级的、函数计算下的监控体系架构就搭建好了,示意图如下。

 

其中的 Scheduler 就是扩缩容中提到的流量调度模块。在请求的返回路径上,它会将函数指标上报到 kafka,之后通过 Function Exporter 进行数据消费,并对不同节点产生的数据进行一次汇聚,完成之后,再交由 Prometheus 二次汇聚,最终再通过 TSDB 完成数据落盘。可以看到,图中 Prometheus 不光需要从 FunctionExporter 获取指标,还可能从每个节点的 Node-Exporter 获取资源信息指标,这就是我前面提到的“指标数据一旦增多就会加大汇聚服务的压力”的原因。最后,在集群规模不大时,这的确是一个比较轻便的解决方案,但在集群节点数量比较多的情况下,建议针对业务指标和资源指标分别配置 Promethues。另外,如果是基于Knative 来作为 Serverless 引擎,由于 Knative 内部采用的 OpenCensus 协议会暴露 trace 和 metrics 数据,采集也会更方便。可以配置 istio-ingressgateway、Knative Activator 和 queue-proxy 来上传,对于用户容器实例,如果是 java 代码,还可以无侵入地通过 Opentelemetry 的 Java 客户端 otel-javaagent 来上报。

监控大盘的展示 grafana

 

日志

在采集数据时,由于 Fluent-Bit 在 Kubernetes 集群等容器化环境中的运行比较出色,所以通常会使用轻量的 Fluent-Bit 对日志数据进行整体的上报,如果是集群的日志信息,则会以 DaemonSet 的形式部署。

因为 Logstash 过滤功能强大,但资源耗费多,所以并不能像 Fluent-Bit 那样以 DaemonSet 的形式部署在整个集群,只需部署少量虚机实例,并利用 Logstash 进行整体的数据清洗即可。如果考虑到峰值问题,比如前面提到的某一时刻存在请求高峰导致日志量显著增大,也可以利用 kafka 缓冲一轮。最后,再由 Logstash 将过滤后的数据交由相应的存储服务。

链路

链路信息

对用户而言,更关心的是端到端的整体耗时,而除了代码本身的执行,其余耗时主要发生在冷启动的准备阶段。因此,平台可以默认提供给用户函数总耗时以及冷启动过程的耗时,其中也可以包括准备代码、运行时初始化等步骤的耗时。

而在复杂的业务场景中,往往会涉及到函数与函数或者函数与其他云服务之间的调用。这时,我们可以为开发者提供自定义的链路支持,将链路信息记录在相应的结构体中(如 Header),就可以完整地串联起整个外部的调用链路。而内部的调用链路,也可以通过上下文的形式用 SDK 去处理。

通过这种与内置链路结合的方式,平台可以有效地帮助用户定位出超时、性能瓶颈以及涉及多个云服务关联等类似的故障问题。

在平台层面,则可以根据模块之间的关系以及系统架构的实际情况来构建链路,整体思路和用户侧的链路构建差不多。不过需要注意的是,并不是链路信息越详细越好,因为链路追踪本身也需要耗费一定资源,所以最好根据实际的运维需求来构建。

链路拓扑的可视化

常用的解决方案,一般是基于标准的 OpenTelemetry 协议,利用其提供的 SDK 和 Otel Agent 完成对链路 Span 的生成、传播和上报,最终通过分布式追踪系统(如 Jaeger)进行收集,形成链路拓扑的可视化。从图中可以看出,OpenTelemetry 可以通过三种方式来上报链路信息,包括直接使用 SDK、Agent Sidecar 和 Agent DaemonSet,你可以根据自己的业务情况选择一种,或者多种组合方式。

 

以 Jaeger 为例,节点服务可以使用 Opentelemetry 的 SDK 或者 Agent 上报链路信息,通过 Jaeger Collector 统一收集,并由 ElasticSearch 进行存储,最终由 Jaeger-Query 负责展示数据查找。

可观测功能的构建

明确收集的数据:无论是指标、链路还是日志,都应该明确我们需要什么样的数据,而不是毫无目的地将所有数据收集上来,每一种类型都应该从平台运维和用户关心两个维度去考虑。比如指标应该包含用户关心的调用次数、执行时长,还要包括各个实例的资源使用情况等。

组件的选型:组件的引入最好是从一些成熟的产品中选择,建议使用一些 CNCF 推荐且较为成熟的产品,比如 Prometheus、fluent-bit 等。除此之外,也需要考虑到组件引入时的学习成本和后期的运维工作,一些可观测组件尽管功能丰富,但熟悉和部署的过程就需要花费上大量的时间。

资源成本:可观测的组件也需要占用一部分资源,像 Logstash 这种强大的日志清洗组件,可能单个实例就需要消耗几个 G 的内存,而可观测的数据落盘还需要用到较大的存储空间。这些都需要结合具体的资源预算进行评估。如果预算足够,完全可以使用公有云上的服务,免去后期的组件维护工作。

适配问题:像金融、电信等企业,为了提高系统的安全性,操作系统往往是 Kylin 这一类国产操作系统,并且有自己的一套 PaaS 底座,因此为了适配 PaaS 底座,可能还需要对这些可观测组件进行二次开发,这也是在选型阶段需要考虑到的问题。

后期的扩展能力:可观测组件的扩展能力也需要在设计之初就考虑进来,这需要对整个平台后期的使用量有一个长期的判断。比如 Prometheus 就可以考虑采用联邦集群的部署方式,毕竟如果后期有明显的增长,单点部署就会遇到瓶颈。

指标

首先明确收集的指标数据。从平台与用户两个视角提出了调用次数、执行时长、资源使用情况等具体的细项,而 Knative 引擎已经提供了部分指标收集的支持,包括业务指标和模块指标。

其中业务指标会由 queue-proxy 提供,包括 revision_request_count、revision_request_latencies、revision_app_request_count 等 5 种与业务紧密相关的指标数据。

在模块指标方面,可以收集 Activator、Autoscaler、Controller 等上报的指标数据,这其中包括与整体冷启动并发相关的 Activator 级别的并发量统计,以及和当前资源使用情况相关的函数 pod 数量等。

采用 Prometheus搜集。

原因有两点:

第一,Knative 官方推荐Prometheus作为指标的收集工具,并且前面提到的模块都有各自的 exporter 用于上报,使用非常方便,

第二,Prometheus 属于 CNCF 可观测系列中比较成熟的一款指标采集工具,社区也非常活跃,对于后期的维护工作非常有帮助。

指标的收集工具确定为 Prometheus 后,可视化工具推荐配套的 Grafana,这二者几乎是默认关联在一起使用的,也是 Knative 官网的推荐。

链路

链路信息提供的是关键过程的耗时情况。对于 Serverless 平台来说,最关键的两个阶段就是冷启动与业务代码整体的执行时长。回到 Knative,冷启动耗时包括从 Activator 接受到请求开始,直到用户容器和环境准备完成的过程,而业务代码的执行时长则为函数运行的整个时长。在采集的过程中,往往通过 span 的 duration 相减的方式来计算链路耗时。比如冷启动耗时通过 Activator Service 的 Duration 减去 User Container 执行完成的 Duration 就可以得到。另外,除了经过 Activator 和 User Pod 这两个节点,还需要考虑到对用户自定义链路的支持,即允许用户通过 SDK 的方式在函数内的关键路径上进行链路标记并上报。

链路的相关工具,采用 Knative 推荐的Opentelemetry和Jaeger 。其中 Opentelemetry 组件用于链路信息的收集与上报,Jaeger 用于链路信息的可视化。上图中,采用了 DaemonSet 部署 Otel-agent(也可以通过 Sidecar 或者 SDK 注入的方式进行部署),用于上报函数的 tracing 信息,然后通过 Otel-collector 进行采集,最后通过 Jaeger-Query 访问 collector 中的数据就可以查看了。这样就形成了一个完整的链路信息闭环。

日志

关于日志部分,Knative 官方推荐使用fluent-bit,主要是因为 fluent-bit 超快速、轻量级、高度可扩展,是容器化日志收集和处理的首选工具,同时可以对接 ElasticSearch、Kafka 等多种日志存储下游。图上的整体日志处理流程采用的是 fluent-bit,由 ElasticSearch 负责存储,再由 kibana 进行可视化。

 

posted @ 2023-01-17 11:08  muzinan110  阅读(106)  评论(0编辑  收藏  举报