前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >B站监控2.0架构升级:P90查询性能如何提升10倍?

B站监控2.0架构升级:P90查询性能如何提升10倍?

作者头像
TakinTalks稳定性社区
发布2024-10-21 09:53:26
1120
发布2024-10-21 09:53:26
举报
文章被收录于专栏:TakinTalks稳定性社区

背景

在2021年年底,B站基于Prometheus+Thanos方案,完成了统一监控平台的落地。但随着业务的快速发展,许多问题也逐步显现。

图 - B站监控系统现状

这里简单介绍一下B站监控系统的现状——

指标量级已经达到了一个相当高的水平(亿级),整个查询量大概在每秒48000+。支持的采集对象数量庞大,大约在170万+。

在B站,90%的数据采集是基于Pull进行的。当然,也有10%的场景是基于push进行,场景主要是job类型或者边缘上报的监控指标。

监控覆盖范围主要分为Paas层和Iaas层。Paas层主要包括通用的应用监控,以及一些中间件、组件的监控。iaas层则涵盖了主机监控、容器监控,以及网络监控。

业务场景除了基础的监控大盘,还包括一些告警计算等基础功能。随着指标在业务中扮演的角色越来越重要,包括上层的SLO平台、发布平台,都会依赖指标去做一些决策。

因此,近两年来,B站对查询指标的需求增长得非常迅猛,1.0监控系统渐渐无法满足这些需求,于是推动了我们对监控系统做更进一步的优化升级。

一、老版监控1.0系统存在哪些问题?

正如之前提到的,我们基于Prometheus+Thanos方案构建了整个监控系统,在每个Prometheus上部署一个agent,以拉取Prometheus所需的采集配置,通过Thanos进行统一查询。这样的架构存在几个突出的问题——

1.1 稳定性差

首先,我们面临的第一个问题是稳定性差。由于告警是基于Prometheus计算的,一个应用下的所有实例,必须调度到同一个Prometheus去采集。以B站为例,弹幕或直播这样的服务可能有几千个实例。每当这些实例发版时,元信息就会发生变化。因此,在重新构建时就会消耗大量的内存,进而导致Prometheus频繁OOM问题。这也是我们当时非常痛苦的一个点,我们经常收到这样的告警,需要临时去处理。

1.2 用户查询体验差

第二个问题是查询体验差。由于Prometheus+Thanos的查询性能非常有限,就会经常出现查询慢/超时,或者是因为查询不统一导致误告警,或者是open API查询失败等等,一些非常糟糕的查询体验。

1.3 云上监控数据质量差

第三个痛点是云上监控质量差。我们B站目前使用了非常多的云厂商的服务器。即使是同一个云厂商,它可能还有不同的账号或地域,网络拓扑非常复杂。经常因为网络不通,导致采集无数据或者断点等等,云上监控质量比较差。

二、监控2.0架构如何设计和落地?

2.1 设计目标和思路

基于以上1.0的痛点问题,我们开始着手监控2.0架构的设计。核心设计思路如下——

1)采集存储分离

第一个方面是实现采集和存储分离。在以往的架构中,Prometheus采集和存储是一体的,导致target实例调度分发时,很难快速弹性扩缩。我们希望通过分离采集和存储,能够更灵活地进行资源的扩展和调度。

2)存算分离

我们知道,指标和计算数据往往不是线性关系。例如,指标增长量可能不到一半,但计算需求可能达到3-4倍。如果仍然按照采集和存储一体的方式去采购资源,势必会造成浪费。我们希望能够在写入、存储和查询的过程中都能够进行弹性扩展。

3)时序数据库选型

经过调研,我们发现在写入和查询性能、分布式架构,VM运维效率都能够满足需求。VM的集群模式天然支持存算分离,因为它在写入、存储和查询时都可以弹性扩缩。

4)单元化容灾

针对现在故障场景频繁的情况,我们如何能够保证在zone维度下全链路实现单元化,这是一个重要的问题。我们希望通过这种zone维度的调度,实现全链路单元化容灾。

因此,通过采集存储分离,我们能明显提升稳定性。通过全局zone纬度调度采集,能大幅提升数据质量。

而原有查询体验差的问题,我们采取了三个阶段的解决方案——通过将Prometheus存储改为VM,已经能够大幅提升查询性能。但对于一些大的应用,比如B站的一些延时指标可能达到亿级,查询速度可能仍然不够快。因此,我们通常的做法是预聚合。但这可能会带来一个问题,即预聚合会生成新的指标。用户在配置或使用时可能需要额外的成本。因此,我们考虑是否可以在用户无感知的情况下,做一个promql透明查询,以解决用户重新配置的问题。通过这三个方式,我们相信能够显著降低产品的耗时。

2.2 功能架构概览

接下来我将详细介绍监控2.0架构整个功能架构概览。

2.2 图- 功能架构

首先,从最底层的数据来源开始,我们主要分为Paas和Iaas,当然Iaas也包括主机、容器以及网络相关的元素。这些构成了我们监控系统的数据基础。

紧随其上的是调度层,这一层主要是进行采集配置的调度分发。为了设计整个系统的故障半径,我们特别设计了一级调度和二级调度,以增强系统的健壮性。

再往上是引擎层,这里主要负责agent采集工作。我们基于VM技术进行封装,以提高采集效率。同时,我们还有拨测模块,它主要负责网络相关的监控任务。虽然理论上Prometheus我们已经可以不再使用,但在目前的云监控场景中,我们仍然保留了它,后文我将对此做出解释。

接下来是存储层。我们的存储主要采用vmstorage。在存储层引入了消息队列,主要用于流式计算的处理。

再往上是查询层,主要基于VM-select能力。为了确保稳定性,我们设计了一个查询网关,它主要负责认证、基本的限流和降采。

我们目前的指标应用场景非常丰富,除了常用的大盘和告警计算,还有许多发布平台、SLO平台,包括BI报表、赛事活动等,都会依赖平台的指标数据。

2.3 整体架构

通过这个技术架构图,大家可以看到,左右两边基本上是完全对称的,这意味着我们可以保证从采集、写入、存储到查询,都可以做到单元化,从而实现全链路的监控和分析。

2.3 图- 整体技术架构

首先,最底层是一个Master节点,它扮演着全局配置中心的角色,负责统筹管理所有的采集/调度配置。

紧接着是zone 1节点,它实际上是一个二级调度节点。这个节点通过版本号和集群名称的组合来获取本机房上所有的采集配置。

再往上是采集节点,这些节点会通过target定期上报心跳信息,以便二级调度节点能够及时分发相应的采集配置。

在我们的架构中,VM Agent有两个主要的链路:一条是写入Kafka,通过Flink Job执行流式计算;此外,还有一条链路是通过remote write写入VM集群。谈到VM集群,如果大家使用的是集群版,基本上都是按照这样的模式来构建的。为了提升负载均衡,通常会在前面挂一个LB。vmselect、vmstorage、vminsert都实现了弹性扩展,这种分布式架构,运维既简单又高效。

2.4 数据来源

前文有提到数据覆盖场景包含了Paas层和Saas层,在此就不赘述了。

改动一:发现方式从pull改为push

在之前的监控系统中,业务层面并不需要关心监控实例的具体位置。我们主要是与发布平台进行自动化对接。

业务需要接入的部分,主要是物理机上部署的一些自定义应用,需要将采集对象接入进来。我们之前是通过pull拉取的方式,比如业务提供接口,我们定时去拉取。

这种方式可能存在两个问题:第一个问题是,由于是通过同步接口的方式拉取,可能存在采集间隔,导致延时;第二个问题是,如果业务提供的接口出现问题,我们去拉取时可能无法及时发现,尤其是如果业务的监控覆盖不到位,他们可能无法发现问题。这导致我们监控这边经常需要主动发起运维事件,这样的工作量非常大。

后来我们改为Push的方式,通过暴露接口,让业务自己去Push他们相关的采集对象,这样实时性得到了保证,而且如果有问题,他们一般也会第一时间感知到。这是我们的第一个改动。

改动二:接入方式改为集成任务

第二个改动是关于监控接入的问题。我们当时也思考了很久,监控接入主要是为了解决用户接入系统后如何确认监控已经开始采集的问题。所以我们在监控接入这块做了可视化方面的一些设计。

首先,我们目前是通过集成任务的方式接入的,接入后我们能看到每个实例的采集状态,比如每个target上报了多少个time series,以及每个target的采集耗时。此外,我们还有一个应用,它会显示总共有多少个实例,有多少个实例已经成功上报,让用户第一时间感知到当前的接入状态。

2.5 数据采集

在成功接入数据之后,我们需要解决的第二个问题是数据采集问题。在数据采集这一块,我们主要分为两个部分:调度层和采集器。

1)调度层

目标:解决数据质量差

功能:

1.负责采集job配置的生成和target监控实例的分发

2.为了实现单元内链路全闭环,通过zone维度调度分发

2)采集器

目标:解决prometheus oom

功能:

1.基于VM Agent采集数据。

2.定时向调度层上报心跳

下面,我将详细介绍具体的实践细节。

2.5.1 调度层

2.5.1 图 - 调度层分为一级调度和二级调度

一级调度(Master):

1、根据采集调度配置(zone维度调度),在内存中构建各个二级调度所需的采集配置。

2、内存快照数据保护策略。一级调度管理着所有的采集配置,为了保护这些重要的数据,我们会采取措施保护。例如,如果用户误删除,一次性尝试删除超过5000个实例的采集调度,我们会要求用户进行确认,并通过白名单方式进行操作,然后才执行真正的删除操作。

3、调度耗时优化:50s->10s。在刚开始上线时,可能需要50秒才能完成所有的采集配置和target的调度分发。但目前,通过一些优化手段,包括内存优化和异步处理方式,我们已将全局调度完成时间缩短到大约10秒。

二级调度(Contractor):

1、设计多套二级调度,为了防止故障爆炸半径。比如某个zone 1 ,可能有几十万个实例,如果是单一的二级调度,一旦出问题,它的故障半径会非常大。因此,在二级调度设计中,我们实现了多套二级调度,可以对应用、组件等进行二次切分,这样就防止了故障半径的扩大。

2、调度时机:第一,采集配置有变化时,我们通过版本号发现变化;第二,采集节点有更新,包括采集量的扩缩容等;

3、调度策略:我们目前主要根据两个维度进行调度,一个是target的实例数,第二个是基于容量维度。

2.5.2 采集器

采集器我们主要利用原生的VM Agent的能力,实际上没有做太多改动。这里有两点经验供参考。

1、开启流式采集。

我们之前没有开启流式采集,但在拓扑时发现,它的内存消耗有点高。后来我们发现,每次抓取target数据时,会占用较高的内存。通过采用流式采集的方式,我们能够将内存消耗降低到大约20%左右。

2、采集断点的问题。

VM Agent自身会有随机(采集间隔时间)平滑load机制。新target加入时并不会立即开始采集,在目前的开源代码中,这个机制会根据采集间隔来随机延迟采集的开始时间。例如,如果我们的采集间隔设定为30秒,那么新target可能在最慢30秒后才会开始采集。当Collector扩/缩容时,target调度到其他采集节点,会出现指标断点。

为了解决这个问题,我们采取了一种策略:当采集器接收到退出信号时,我们不会让它立即退出,而是让它停止上报心跳。同时,我们让采集器继续完成一个采集周期的数据采集后才退出。这样,我们就能够保证这个指标无断点。

2.6 数据查询-慢查询解决思路

通过以上操作,文章开始提到的三个痛点问题,我们已经解决了两个——稳定性差、数据质量差。但还有一个问题需要我们关注,那就是长期存在的查询慢问题,相信这也是大家经常遇到的问题。

对于慢查询问题的解决策略,一般会经历三个阶段。

1)阶段一:prometheus->VM。从prometheus架构迁移到VM架构,这一步确实大幅提升了查询性能,使得查询处理更加迅速。

2)阶段二:指标预聚合。通过指标预聚合这种降维方式。无论是通过PE聚合还是其他数据存储方式,我们的目标都是降低数据的复杂性,以此来提高查询效率。

3)阶段三:透明查询,promql自动转化。这也是最关键的部分。降维操作可能会生成新的指标,这可能会给用户带来额外的负担,因为他们需要理解这些新指标的含义。为了解决这个问题,我们引入了透明查询的概念,确保在不改变用户原有查询习惯的前提下,系统能够自动进行必要的转换。

我们是如何实现这种自动转换的呢?我们一起看个例子。

2.6.1 promql自动转化增强

场景说明:

这个例子是关于计算某个APP的grpc接口的P99耗时。在实际操作中,我们会从底层向上逐层执行。

首先,在最底层,我们通过APP和标签从VM storage中获取匹配的series。以B站的弹幕服务为例,它有几千个实例,每个实例的grpc接口有几十个,再加上五六个分桶、其他元信息标签……一个指标可能达到亿级。这样的查询对storage层来说压力巨大。

接下来,客户端在获取数据后,会进行rate计算,比如计算30秒一个点的速率。例如,之前提到的例子,第一步可能拿到4000万数据,第二步剩下1000万数据,这一步同样压力巨大,会占用大量资源和耗时。

第三步,基于第二步的结果,我们会根据分桶和method进行聚合。比如有5个分桶和20个method,最终可能只得到100个指标。

我们思考的是,如果我们能够将第一步和第二步这种千万级的耗时,直接转化为查询百级别指标,那么查询耗时是不是可以大幅度降低?

解决方案:

因此,我们采取了预聚合的方法,提前计算好这些数据。这样,下次查询时,我们只需要查预聚合。从之前需要查询亿级指标,一下就可以减少到查询几百个指标,查询效率的提升是非常明显的。

我们在查询层实现了这样的自动转化。如果发现查询完全匹配,我们会自动转化,比如我们提前计算好并生成一个新的名称,比如加上test API,当发现匹配到这个模式时,我们自动在查询时帮用户转换。这样,从之前查询上亿指标或千万级指标,一下就可以减少到查询几百个指标。目前,我们主要在一些大应用场景或计算耗时较长的情况下使用这种技术,加速效果是非常明显的。

2.6.2 数据查询—查询网关-query proxy

之前提到了查询网关具备拦截能力,但在实际向用户开放Open API时,如果没有一些限制功能,问题排查将变得极为困难。因此,查询网关在这里扮演着至关重要的角色。

查询网关的主要功能是兼容prometheus query/query_range的接口,它还提供了认证、账号封禁、限流、降采等关键能力,这些都是确保服务稳定性和安全性的基础。

我们还提供了一个监控界面,可以实时查看每个账号的查询情况。基于账号的QPS可以被清晰地展示出来,包括认证成功、认证失败或是查询超限的统计信息。

2.7 数据可视化

在B站的数据可视化项目中,我们遇到了一些挑战,特别是与Grafana版本相关的一些问题。以下是我们面临的挑战以及采取的具体行动和预期的收益。

历史债务:
  1. Grafana版本问题:我们使用的Grafana版本(v6.x.x)过于陈旧,限制了我们的功能和性能。
  2. 升级挑战:升级到新版本存在多个break change,可能导致现有功能出现问题。
  3. 部署成本:当前的部署架构包括nginx、proxy和Grafana,使得部署成本较高。
具体行动:

为了解决这些问题,我们采取了以下措施:

  1. 数据兼容性修复:通过编写脚本修复因break change造成数据不兼容的问题。
  2. 版本控制:使用Git来管理整个Grafana部署编译脚本,确保每次版本变更都是透明的。
  3. 容器化部署:将Grafana构建成all-in-one镜像,实现容器化部署,简化部署流程。
收益:

通过这些行动,我们获得了以下收益:

  1. 性能提升:Prometheus数据源版本升级至v2.37.x以上,变量获取方式从series api改为label values api,查询性能提升10倍(从2秒减少到200毫秒)。
  2. 支持PromQL Builder:新版本支持PromQL Builder,提高了查询的灵活性和便利性。
  3. 用户满意度提升:通过这些改进,我们用户满意度得到了显著提升。

2.8 整体收益

1、从Prometheus全部切到VM架构后,p90查询耗时降低10倍以上 ;

2、目前支持了170w+采集对象,全部按照zone维度调度、采集,实现单元容灾;

3、仅增加磁盘资源情况下,应用监控全量采集间隔从60s调整到30s,实现1-5-10中的1分钟发现;

4、指标断流、oom告警等异常,降低90%以上;

5、目前写入吞吐44M/s,查询吞吐48k/s,通过查询优化,查询再加速,p90查询耗时降低到ms级(300ms);

三、云&边缘架构数据源如何统一?

3.1 云监控新架构

3.1.1 当前痛点

我们面临的两个主要痛点分别是网络复杂性和多云环境的难题。网络拓扑的复杂性经常导致采集失败,而多个云服务提供商的存在使得用户在选择数据源时感到困惑,因为不确定应该选择哪一个。

3.1.2 云监控新架构

为了应对这些挑战,我们在2.0版本中对架构进行了优化。

首先,针对采集不通的问题,我们采用了IDC的方案,通过zone统一调度,确保同zone之间的采集是通畅的。

其次,为了解决数据融合的问题,我们考虑到云上环境可能存在公网访问,而回源到IDC可能会带来一些风险。因此,我们引入了VM-auth组件,它主要做租户认证和流量调度。

3.2 云监控方案

那为什么我们选择继续采用Prometheus方案,而不是转向VM Agent?

1、改造成本低。我们之前的云监控采集基本上都是基于Prometheus,而且在设计collector时,采集是可插拔的。所以使用prometheus的运营成本非常低,包括恢复成本也是如此。

2、Prometheus本地数据。Prometheus通过公网进行回源,可能会遇到异常或延时的问题,Prometheus可以来数据兜底或备份。目前,我们的做法是prometheus本地数据存储一天,然后回源到IDC进行统一存储,目前我们保留的数据是15天。通过remote write到vm-auth实现数据的统一管理。

3.2 图 - 引入vm-auth组件对回源流量做租户认证和流量调度

3.3 收益

1、云上监控全部按照zone调度后,云上数据质量大幅提升。云上监控无数据等On-call降低90%以上;

2、统一数据源查询,20+云上数据源收敛到1个;

四、未来规划

我们未来的规划:

1、支持更长时间Metrics指标数据存储。

2、支持更细粒度的指标埋点:目前应用监控默认是30s一个点,希望后面提供更细粒度的埋点,覆盖更多的场景,为业务可观测、排障助力。

3、指标平台迭代:未来规划增加写入/查询封禁、白名单等能力,同时希望后面可以借助大模型的能力,实现text2promql(自然语言翻译成PromQL,以及自动生成PromQL注释)。(全文完)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-10-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 TakinTalks稳定性社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 2.5.1 调度层
  • 2.5.2 采集器
  • 2.6.1 promql自动转化增强
  • 2.6.2 数据查询—查询网关-query proxy
    • 历史债务:
      • 具体行动:
        • 收益:
        • 3.1.1 当前痛点
        • 3.1.2 云监控新架构
        相关产品与服务
        对象存储
        对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档