欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

阿里巴巴十年技术精华大公开:详解超大规模PB级数据传输系统技术细节

最编程 2024-02-05 17:03:33
...

本文为阿里云SLS徐可甲在 GIAC 2022 全球互联网架构大会 分享时的议题内容。

云原生场景下数据总线需求场景及挑战

数据总线简介

数据总线作为大数据架构下的流量中枢,在不同的大数据组件之间承载着数据桥梁的作用。通过数据总线,可以实时接入来自服务器、K8s、APP、Web、IoT/移动端等产生的各类异构数据,进行统一数据管理,进而实现与下游系统的解耦;之后可以异步实现数据清洗、数据分发、实时计算、离线计算等计算过程,进而将结构化后的数据投递到下游的分析、归档系统,进而达到构建清晰的数据流的目的。广义上,数据采集与接入、传输链路、存储队列、消费计算、投递等都属于数据总线的范畴,整体上可以分为采集接入层、管道层、计算层。

网络异常,图片无法展示
|

通过数据总线,可以轻松达到如下目的:

  • 解耦生产者与消费者:消费方完全可以不用感知写入方的任何细节,降低系统对接复杂性,提升系统可靠性。
  • 应对流量洪峰,使数据的生产异步于数据的消费,消峰填谷。
  • 定义统一格式与操作语义:接入多种异构数据,通过数据处理构建统一的格式。

举一个简单的例子,在计算广告检索系统中,广告的点展数据至关重要。一份点展数据往往会被多方订阅消费,且应用场景各异,有精度到秒级的实时计算业务,也有类似于Hadoop的小时级或天级的批处理任务。如果数据直接对接,就需要考虑各种异常场景,会让系统变得极其复杂。而通过数据总线,可以大大降低系统复杂度,提高系统可靠性,这样可以保证任意一个数据订阅系统即使经历了下线维护或者宕机,也可以在重新上线后从之前的断点处继续进行数据处理。

云原生场景下的技术挑战

面对每天几百亿次读写、近百PB数据流量、万级用户的场景时,构建高可用的数据总线将会是一件非常有挑战的事情。这里简单列举一些场景的流量场景:

  • 生产者:因业务促销等活动,流量在几分钟内上涨至原先十几倍或几百倍;
  • 消费者:对一种数据同时有几十个订阅者来同时消费;
  • 每天有几百个异构数据源接入,方式各不相同,需要大量适配。

网络异常,图片无法展示
|

经过几十年的飞速发展,整个开发模式、系统架构、部署模式、基础设施等也都经过了几次颠覆性的变革,这些变革带来了更快的开发和部署效率。但随之而来整个的系统与网络环境也更加的复杂、部署模式和运行环境也更加动态和不确定、接入的数据源与数据量大幅增加、流量波动等不确定因素变大、接入难度与原始结构差异化变大,这些都是云原生时代也给数据总线带来的新的要求。

网络异常,图片无法展示
|

总结下来,云原生时代数据总线的技术挑战可以从采集接入层、管道层、计算层三方面展开。采集接入层重点关注数据源的接入丰富度、接入易用性、资源开销与数据采集可靠性;管道层重点关注网络质量、带宽与水平扩展能力、安全与隔离性、生态丰富度等;计算层重点关注及计算语法能力、流量处理带宽与扩展性等。

开源方案的选择与对比

网络异常,图片无法展示
|

目前行业上主流的大数据架构,大概可以分为5个部分,其中前3部分构成了数据总线。

  • 采集端:承载可观测数据采集及一部分前置的数据处理功能。随着云原生的发展,采集端也需要适应时代潮流,提供对K8s采集的友好支持。常见的采集端有FilebeatFluentD/Fluent-bIt、Telegraf,以及我们开源的iLogtail
  • 消息队列:采集Agent往往不会直接将采集到的数据发送到存储系统,而是写入消息队列,起到削峰填谷的作用,避免流量洪峰导致存储系统宕机。常见消息队列为KafkaRabbitMQ等。
  • 计算:用于消费消息队列中的数据,经过处理、聚合后输出到存储系统。比较常见的为Flink、Logstash等。值得注意的是,也开始有公司将iLogtail开源版作为计算层部署在日志架构中。
  • 存储分析引擎:提供采集数据持久化存储能力,并提供查询分析能力。常见的存储分析引擎为ElasticsearchClickHouseLoki以及时序的Prometheus、influxdb等
  • 可视化:借助KibanaGrafana提供采集数据的可视化能力。

用户可以利用上述的采集端、消息队列、计算三部分提供的开源组件搭建出一套数据总线。虽然基于开源组件搭建数据总线技术上时可行的,但是整体实施复杂度很高,需要维护多套系统进行协同。此外,也无法完全满足云原生上文提到的云原生场景下面临的技术挑战,例如网络质量与地域规划就是一道比较难以逾越的鸿沟。

数据总线整体架构

网络异常,图片无法展示
|

可观测平台不仅需要解决好数据如何获取、查询的问题,也应该提供具体业务场景的应用能力,帮助客户从碎片化、低信息的数据中挖掘更大的数据价值。一个典型的云原生可观测平台从下至上可以分为四个层面:数据总线、存储分析、工具、应用。其中,数据总线是整个可观测平台的数据基础,为数据分析及上层业务应用提供数据保障。正因为数据总线足够基础,所以在企业数字化过程中必须足够可靠、稳定、确保数据的通畅,并且能够弹性满足流量变化需求。接下来,我们将重点分享阿里云SLS数据总线的架构与实践。

网络异常,图片无法展示
|

在本文第一部分,我们介绍到一个典型的数据总线可以分为采集接入层、管道层、计算层三个层次,对应的SLS的数据总线的架构也可以类似划分。

  • 采集接入层:承载了数据总线所有数据(支持Log、Metric、Trace、Event等)的接入,并且与阿里云服务有深度的集成。接入手段以SDK/API为基础,扩展了端上可观测采集器 iLogtail、数据导入服务、开源标准协议等多种接入方式。
  • 管道层:以 LogHub 作为数据总线的核心流量中枢,功能可以完全替代 Kafka。通过 Restful API 对外提供接入服务,通过消费组的方式提供实时消费服务。
  • 计算层:作为 LogHub 的下游服务,基于实时消费组,提供了各类数据处理及投递服务;并且生态上支持主流开源流计算对接。

以上,我们对SLS数据总线有了一个整体的认识,接下来我们将从数据接入、流量中枢、数据处理三个维度进行详细介绍。

数据接入技术架构与实践

数据接入能力概览

LogHub 作为数据总线的核心流量中枢,默认提供 HTTP/HTTPS 协议的 API 写入能力,同时,也提供了众多语言的 SDK,用以简化接入场景、增强可靠性,SDK 覆盖从Java、Go、C++等服务端应用,到Android、IOS等移动端场景,甚至 JavaScript 等前端场景。

自研的开源可观测数据采集器 iLogtail承载了服务器场景、容器场景的可观测数据采集能力,覆盖Windows、Linux操作系统及X86、ARM架构。借助于阿里云的优势,无缝支持阿里云上各类主流云服务的日志、指标、安全审计类数据的采集。

对于通用协议等支持也比较丰富,兼容 Syslog,Kafka、Promethous、JDBC、OpenTelemertry 等开源协议;支持众多开源采集工具,例如 Logstash、Fluentd、Telegraf 等。

Producer Library

针对Java、Go等大数据、高并发场景下,我们在SDK基础上提供了Java ProducerGo Producer;针对IoT/嵌入式设备,推出了C Producer

网络异常,图片无法展示
|

使用 Producer 相对于直接通过 API 或 SDK 发送数据,提供了更上层的封装,性能、可靠性都有大幅提升。

  • 线程安全:Producer 内所有的方法以及暴露的接口都是线程安全的。
  • 异步发送:客户端计算与 I/O 逻辑分离。调用 Producer 的发送接口通常能够立即返回,Producer 内部会缓存并合并发送数据,然后批量发送以提高吞吐量。
  • 失败重试:对可重试的异常,Producer 会根据用户配置的最大重试次数和重试退避时间进行重试。
  • 优雅关闭:用户调用关闭方法进行关闭时,Producer 会将所有其缓存的数据进行发送,防止日志丢失。
  • 高性能:通过多线程、缓存策略、批量发送等手段,有效提升发送效率。

可观测数据采集器iLogtail

iLogtail是数据总线数据接入的重要流量来源,拥有的轻量级、高性能、自动化配置等诸多生产级别特性,可以署于物理机、虚拟机、Kubernetes等多种环境中来采集遥测数据。iLogtail的核心定位是可观测数据的采集器,帮助开发者构建统一的数据采集层,助力可观测平台打造各种上层的应用场景。通过iLogtail可以很好的解决数据总线数据接入的问题。

得益于阿里巴巴/蚂蚁集团与公有云场景的不断锤炼,iLogtail和开源Agent(例如FluentdLogstashBeats)相比,性能、资源消耗、可靠性、多租户隔离、K8s支持等硬指标上较为领先,可以满足多种业务场景下的苛刻要求。目前iLogtail已于2022年6月29日完整开源,吸引了众多开发者的关注,GitHub Star数也于2022年11月7日突破1K

网络异常,图片无法展示
|

采集高性能、低开销是iLogtail的核心优势之一。iLogtail在Linux下使用inotify作为文件监控的主要手段,提供了毫秒级延时的数据发现能力,同时为了兼顾不同操作系统以及支持各类特殊采集场景,iLogtail同时使用了轮询作为的数据的发现方式。通过使用轮询与事件并存的混合方式,iLogtail打造了一套兼具性能优势同时不失鲁棒性的文件发现机制。此外,iLogtail 采用了无锁化事件处理模型。与业界其他开源Agent为每个配置分配独立线程/Goroutine读取数据不同,iLogtail数据的读取只配置了一个线程。由于数据读取的瓶颈并不在于计算而是磁盘,单线程足以完成所有配置的事件处理以及数据读取。使用单线程使得iLogtail的事件处理和数据读取都可以在无锁环境下运行,数据结构更加轻量化,从而取得了相对多线程处理更优的性价比。

在生产环境中,一台服务存在数百个采集配置属于常态,每个配置的优先级、日志产生速度、处理方式、上传目的地址等都有可能不同,因此必须有效解决如何隔离各种自定义配置,保证采集配置QoS不因部分配置异常而受到影响的问题。iLogtail采用基于时间片的采集调度、多级高低水位反馈队列、事件非阻塞处理、流控/停采策略以及配置动态更新等多项关键技术,融合实现了兼具隔离性、公平性、可靠性、可控性、性价比五大特性的多租户隔离方案。经历了多年双11流量高峰期的考验,这套方案已经被证明相比其他开源具备较大的稳定性和性价比优势。

数据源的多样性毫不夸张的说可以是数据总线的生命线,否则就是巧妇难为无米之炊。iLogtail通过插件化的设计,突破了单纯文件采集的范畴,有效扩展了上下游生态,使得iLogtail成为真正的可观测采集器。目前iLogtail已经支持了众多数据源的接入,数据源类型覆盖Log、Metric、Trace,数据源除了文件的采集,还包括了标准协议的支持,例如HTTP、Mysql Binlog、Prometheus、Skywalking、Syslog等;iLogtail也通过eBPF支持,实现了无侵入的网路数据采集能力。数据输出生态也从SLS逐步扩展到Kafka、gPRC等,未来通过开源社区共建也会支持ClickHouse、ElasticSearch等。

面对众多异构数据的接入,数据总线一项职责就是通过数据处理构建统一的数据格式。iLogtail也提供了强大的数据处理能力,可以前置完成数据格式规整、数据过滤、上下文关联等。iLogtail整体采用PipeLine的设计,首先通过Input插件采集到数据,会经过采集配置中设定的Processor处理,之后经过Aggregator插件打包,最终通过Flusher发送到存储系统。数据处理环境包含数据切分、字段提取、过滤、数据增强等环节,所有插件可以*组合。

随着云原生落地,Logtail已全面支持Kubernetes,目前支持Docker、Containerd两种主流的容器运行时。iLogtail通过实时监控容器列表并维护容器和日志采集路径映射,结合高效的文件采集能力提供了极致的容器数据采集体验。iLogtail支持使用容器标签、环境变量、K8s标签、Pod名称、命名空间等多种方式进行容器筛选,为用户提供了便利的采集源配置能力。支持DaemonSet、Sidecar、CRD等多种部署方式,为应对不同使用场景提供了灵活的部署能力。此外,对于CICD自动化部署和运维程度要求较高的用户,iLogtail还提供了K8s原生支持,支持通过CRD的方式进行采集配置管理。该方案中,iLogtail K8s新增了一个CustomResourceDefinition扩展,名为AliyunLogConfig。同时开发了alibaba-log-controller用于监听AliyunLogConfig事件并自动创建iLogtail的采集配置,进而完成日志采集工作。

流量中枢技术架构与实践

LogHub作为SLS数据总线的流量中枢,是一个高吞吐的数据通道,支持海量可观测数据的实时接入与消费能力。在可观测数据场景下完全可以Kafka等消息队列产品,并且在性能、易用性和稳定性上更佳。

LogHub可以理解为 append-only 的 log 队列结构,通过多个 shard 组合实现 IO 和存储的水平扩展。并且在队列基础上创建多层索引,可快速定位到每一条数据在队列中的位置,赋予队列模型随机查询能力。

  • 弹性: 支持1~512个分区(shard),毫秒级扩容、缩容。
  • 高吞吐:单shard支持5MB/sec写入,10MB/sec读取。
  • 高容错:单机failover不影响正常写入。
  • 去重:支持ExtractlyOnce去重写入。
  • 随机查询:1%额外存储的开销,支持任意数据随机查询(1次IO)。

Logstore/Metricstore是SLS可观测数据的采集、存储和查询单元,LogHub作为Logstore/Metricstore的队列模型,提供了数据实时写入和流式消费的能力。同时在此基础上,进行了模型扩展,进而构建出了统一的可观测分析引擎。

  • 索引模型:通过创建索引,提供数据Filter能力。查询时,可以根据索引快速定位命中数据后,从队列模型高效选择所需的数据。
  • 原始列存模型:针对特定字段列式存储,提供大数据统计分析能力。
  • PK(时序)列存模型:针对时序数据的特点,提供了主键排序后再字段列存的模型,有效提升时序数据读取效率。

全球化支持与智能加速

LogHub 是阿里云上的基础设施,借助阿里云等全球化部署优先,与阿里云Region保持同步,这也是其他开源数据总线无法比拟的优势。可以确保全球化业务就近选择Region,也可以满足一些国家或组织相关的法律约束数据不能出境的要求。

LogHub 联合 CDN 推出了全球自动上传加速方案,基于阿里云CDN硬件资源(覆盖2800+节点,70+国家),全球数据就近接入边缘节点,通过内部高速通道路由至LogHub,大大降低网络延迟和抖动。

弹性与保序处理

在生产中我们往往会面临流量峰值和低值的情况,也会遇到因业务层映射不均衡,导致某一个分区(shard)有非常大流量的场景,弹性伸缩(Merge/Split)就是解决该问题的机制。

Shard分裂的原理

Shard分裂操作,是流量扩容的一个重要手段,是把一个readwrite的Shard分裂成两个readwrite的Shard;同时原Shard变成readonly状态,之上的数据可继续被消费读取。

合并操作和分裂操作相反,是把两个相邻的readwrite的Shard合并成一个readwrite Shard,同时原来的两个Shard变成readonly状态。

负载均衡:根据峰值、底值弹性扩容,控制成本。

下图最早只有Shard0提供服务;后随着晚间流量高峰单Shard不足以支撑业务流量,Shard0拆分为了Shard1、Shard2提供服务;等流量再次稳定,出于成本考虑,合并成一个新的Shard3提供服务。

日志保序处理:将不同实例映射到不同分区,调整分区处理能力。

对于一些业务场景有保序的需求,数据写入时往往通过Hash规则,将不同业务的数据映射到固定的Shard上。

下图中的业务场景,Shard1承载了3个DB的流量不堪重负,此时可以通过进行Shard拆分的方式,实现流量的均衡。拆分后,原来的Shard1变成只读,数据仍可被消费,但是不再接收新的数据写入,该由新拆分出的Shard3、Shard4对外提供服务。

那对于Shard调整前后的边界数据,如何保序?Loghub提供了Shard顺序消费的能力,即Shard分裂后,先消费原Shard数据(即Shard1的数据),然后同时消费由该Shard分裂的Shard数据(Hash策略保证同一业务落到一个Shard上)。同理,Shard合并场景,也是先消费原Shard数据,然后消费由原Shard合并后的新Shard数据。当然,对于不严格保序的场景,为了提升消费速率,可以关闭Shard顺序消费功能,以达到所有Shard可以同时消费的目的。

稳定性建设

粗粒度流控:Project级别

Project全局流控最主要的目的是限制用户整体资源用量,在前端就拒绝掉请求,防止流量穿透后端把整个集群打爆。

  • 每秒上千个Nginx前端,将各种接收到的Project的流量、请求次数进行汇总,发送至QuotaServer。
  • QuotaServer汇总所有来自Nginx的Project统计信息,判断是否超过Quota上限,进而决定是否需要采取限流措施。之后,将超过Quota的Project列表通知到所有的Nginx前端。
  • Nginx前端获取禁用Project列表之后,立刻做出反应,拒绝这些Project的请求。

细粒度流控:Shard级别

Shard级别流控则更加精细、语义(错误码)更加明确、可控性更强。

  • 每个Shard明确定义处理能力, 如5MB/sec写入,10MB/sec的读取。
  • 当Shard队列出现堵塞,根据Shard流量是否超过quota,返回用户是限流还是系统错误(返回的Http错误码是403还是500),同时将Shard限流信息通知QuotaServer。
  • QuotaServer接收到限流信息后,可瞬时将限流信息同步至所有的Nginx。
  • Nginx端获得Shard的流控信息之后,对Shard进行精确的流控。