大规模日志全局分析的需求
数据大规模与时效性
基于时间的数据(日志、指标)在日积月累后的数量是惊人的。以 SLB 七层访问日志为例,每一个HTTP/HTTPS 访问请求会记录一条 access log,假设每天产生1000万条数据,则一年为36亿条数据。一方面,长时间的数据存储需要巨大的存储空间,而通过减少存储周期的方式降低存储空间,虽然控制了存储成本,但也丢失了有价值的历史数据。另一方面,大量的数据将造成分析上的性能压力。
大部分时序数据具有时效性特征。历史数据可以接受分钟或小时级别的精度,而新产生的数据需要更高的精度(例如监控、线上问题调查)。数据运营、分析师需要存储全量的数据以备分析,历史数据直接 TTL 删除是可能最差的选择。
例如 Elasticsearch rollup、时序数据库的降精度用于解决这部分问题。
一份数据在多种场景使用
对于同一份日志,可能被多种用户角色在多种场景下使用到:
- 实时的数据,需要支持关键词告警、时序数据 ML 巡检、日志上下文查询。
- 亚秒级延迟粒度上,有全文关键词的查询、交互式 SQL 统计分析的需求。
- 以天为单位,需要对日志做运营分析,计算转化率、设计运营策略。
- 一周前的产生的数据,大部分时候不再会被触碰到,在支持偶尔的历史指标查看以外,审计场景下对全量日志的存储也是必须项。
一份数据,多处使用,既要满足业务需求,成本也是需要关心的。
自定义业务分析
云上日志设施面对的客户群呈现多样化,自定义的业务需求举例如下:
- 电商:计算七日留存率,业务访问 SQL 审计日志对用户信息脱敏,等等。
- 在线教育:多平台终端(android、ios、PC)埋点数据的规整,直播课堂生命周期内的异常诊断,等等。
- 游戏:按游戏的数据分发存储,全文搜索支持工单调查,等等。
阿里云 SLS 是云原生观测分析平台,为Log/Metric/Trace等数据提供大规模、低成本、实时平台化服务,一站式提供数据采集、加工、分析、告警可视化与投递功能。我们将以业务为目标的数据处理归纳为两类需求:
- ETL:将非结构化的日志做预处理,为日志信息添加业务字段,数据脱敏与分发等。
- 分析:全局数据大表上的查询和 SQL 分析,支持布尔搜索、window、aggregate 操作等。
SLS 上的典型分析方案
对于 ETL、分析这两类计算任务,除了交互式分析以外,还需要常驻作业模式来处理结果落盘。
根据不同的业务需求,这里总结了几种常见的 SLS 数据分析方案。
数仓 "T+1"
对于结果实时性不敏感的业务,有较多采用数仓方案:
- 数据通过 SLS 实时入库,集中化存储。
- 全托管数据投递到 MaxCompute。
- 业务规划小时级或天级的计算任务,生成下游表,产出业务报表等结果。
流计算
以 Flink、Spark Streaming(continuous mode)、Kafka Streams 为代表的实时计算系统,在数据处理语义(exactly-once)、计算结果修正上的能力强大。该方案会用到 SLS 百 ms 秒级端到端延迟的 pub/sub 能力:
- 数据实时推送到 SLS 日志库。
- 启动流计算任务,从多个 shard 实时消费数据。
- 流计算任务根据算子组合情况(stateless、statefull、groupby 等)切分多个拓扑执行,可能涉及到数据 shuffle、watermark、state store 等机制。
这个方案在算子丰富度、实时能力、性能上综合表现全面,是一把牛刀,例如在电商实时大屏场景上是非常好的选择。
如果抱着挑刺的眼光来看:
- 计算引擎层面做得均衡,但缺乏存储层的优化。例如:一个 logstore 上运行 10 个流计算作业,无论实际需要纳入计算范围的数据有多少,最终需要 10 遍全部数据流量的订阅,从业务角度上看存在网络、计算资源上的浪费。
- 对于日志用户来说,在参数配置、性能调优、问题 Debug 有复杂性(复杂常常是通用、强大的另一面)。在复杂场景下,DevOps-er 理解业务需求后,需要设置好高级参数、选择好 state store 等。
- 计算集群部署方式,尤其对于自建集群、数据稀疏的应用,其成本上有影响,例如 JobManager/TaskManager 等角色资源需要摊销。
自建程序做流式消费
还是围绕 SLS 的 pub/sub 能力,以 SLS SDK 方式调用 PullData API,例如:
- 通过 Logstash/Flume 等开源软件,加载 SLS source connector。
- 通过函数计算(SLS 提供 FC 触发器),好处是 Serverless 的 runtime,极致弹性计费。
- 通过 SLS 的 consumer group library 处理数据,自动负载均衡、failover。
以上对于行处理场景是适用的,适用面上则需要关注:
- 该方案在绝大部分情况下都不涉及全局计算(窗口、聚集),即使能实现也很复杂。
- 自建程序、开源软件需要运维人力以及固定机器投入的成本。
自建程序做查询、分析
在 SLS 的流式存储之上,开启了索引分析功能,带来了全文索引、列式下推、SQL 计算能力加持。
该方案调用 SLS GetLogs API,部署一个常驻程序,设置定时触发器,周期调度任务执行:
- 调用 API 读取 SLS 索引并计算数据。
- 读取计算结果写出到目标做存储。
用户除了需要运维程序,还需要考虑以下需求:
- SQL 运行可能因计算量巨大而超时,失败时需调度层的重试支持。
- 执行延迟时告警支持。
- 调度元信息(schedule_time 等)持久化。
- web console 管理的需求。
- 如何将 SQL 计算结果 exactly-once 入库。
本文后续重点介绍的 Scheduled SQL,从本质上来讲,是对该方案的服务化,对以上问题有更全面的考虑。
SLS 告警
对,你没看错。有少数用户用 SLS 告警曲线救国,图的是一个全托管、免运维。
SLS 告警功能支持设置定时策略,执行多个 SQL 获取结果,并将结果编排后发送到内置 logstore(internal-alert-history)或自定义的网关/webhook。
需要说明的是,告警的主要设计场景是面向小的计算结果,按触发策略、值班表,将事件传达给接收者。对于严苛的业务,不推荐这种做法(可以关注 Scheduled SQL 功能做迁移):
- 告警的结果写出可能出现写出数据大小截断(1 MB 内)、 exactly-once 等问题。
- 告警 1.0 是串行调度,某一次计算发生延迟后,多次执行实例的 SQL 时间窗口会出现空洞。
SLS 原生数据处理方案
用一张图描述 SLS 原生数据处理功能如下,接下来分别按存储模型展开介绍:
stream 模型
例如通过 Flink、自建消费组程序进行 SLS 数据分析,都基于 stream 模型。这是 SLS 最基础的存储形式(也称 LogHub),可以理解为 append-only 的 log 结构,通过 多个 shard 组合实现 IO 和存储的水平扩展。
LogHub 与开源软件 Kafka 是类似的功能形态,SLS 底层是共享分布式存储(盘古),这避免了 Kafka 在机器磁盘空间 re-balance、机器替换、存储规模的一些缺陷。
stream 存储模型在机器数据场景下有多重优势:
- 写入模型简单,不需要 commit 机制,天生支持流式写入,客户端(移动端设备、Agent)友好。
- append-only 保证了写入吞吐的设计上限,满足业务高并发、高吞吐需求。
- FIFO 的 changelog 模式,满足大多数日志、指标类数据的生成与使用场景。
针对流式数据 ETL 场景,SLS 支持数据加工功能,可以实现按量付费、全托管的行处理需求,本文不多介绍,可以参考SLS 数据加工的设计与实践。
table 模型
当 stream 数据写入后,对于 shard 内的数据,可以同时构建一份包括倒排、列存、bitmap 等信息的索引数据。shard 内 stream 数据相当于是正文,索引到今天有两种形式:
- Logstore (with index):适用于日志模型,形式上是表结构,一条数据由多组 key-value pair 组成。
- Metricstore:对于指标类型数据有针对性优化,有序排列存储支持快速指标计算,高压缩率低存储成本。
例如 Logstore,在计算时称为 append-only Table 模型。在 SLS 场景下有以下优势:
- 计算效率高,时间(一级索引)过滤、计算下推都可以直接利用 index 进行,节省网络、计算的性能开销与计算成本。当然,index 会有构建费用,SLS 的一份 index 数据可以服务于多个业务场景(告警、仪表盘、全文搜索、监控)来摊销成本。
- OLAP 解决确定性问题,按照条件过滤取到数据后,直接进行计算即可,不需要考虑流计算中 watermark、trigger 与 window 配合、state store 数据膨胀(特定场景)等复杂问题。
Scheduled SQL 让 SQL 可调度
SLS 的每一次 SQL 计算针对预定的一片数据做处理,因此,对全部时间区间(从现在开始一直到未来)数据的 SQL 分析依赖于上层调度,也就是将要介绍的新功能 Scheduled SQL,它支持标准SQL、SLS 查询和分析语句,按照调度规则周期性执行,并将运行结果写入到目标库中。可用于以下场景:
- 定时分析数据:根据业务需求设置分析语句,定时执行,并将分析结果存储到目标库中。
- 全局聚合:对全量、细粒度的数据进行聚合存储,汇总为存储大小、精度适合的数据,相当于一定程度的有损压缩数据。例如按照秒级别对 36 亿条数据进行聚合存储,存储结果为 3150 万条数据,存储大小为全量数据的0.875%。
- 投影与过滤:对原始数据的字段进行筛选,按照一定条件过滤数据并存储到目标Logstore中。该功能还可以通过数据加工实现,数据加工的DSL语法比SQL语法具备更强的ETL表达能力,更多信息请参见加工原理。
Scheduled SQL 相比于自建程序调用 SLS API 而言,有以下优势:
- SQL 运行 timeout 提升至 600 秒,单次最大处理百亿级数据。
- 计算资源池可选:免费(project 级 15 并发)、付费(弹性扩展,参考SQL 独享实例)。
- 最小 1 分钟周期执行,支持常驻或固定时间区间内调度运行。
- 支持灵活的查询时间窗口参数配置,满足多样化需求。
- exactly-once 写入目标库。
- 完善的作业实例查看、重试支持(控制台、API)。
- 全托管运行,自动处理多种异常,调度不收费。
- 实例执行失败集成 SLS 告警通知。
Scheduled SQL 功能介绍
工作机制
Scheduled SQL 涉及以下几个重要概念:
- 作业:一个 Scheduled SQL 任务对应一个作业,包括调度策略、计算规则等信息。
- 实例:一个 Scheduled SQL 作业按照调度配置按时生成执行实例。每一个实例对原始数据进行 SQL 计算并将计算结果写入目标库。实例ID 是其唯一标识。
- 创建时间:实例的创建时间。一般是按照您配置的调度规则生成,在补运行或追赶延迟时会立即生成实例。
- 调度时间:由调度规则生成,不会受到上一个实例执行超时、延迟、补运行等情况的影响。大部分场景下,连续生成的实例的调度时间是连续的,可处理完整的数据集。
流计算里有大量篇幅用于处理数据计算的一致性、完整性问题,Scheduled SQL 则是一种以 small-batch 模拟常驻计算的方案,针对这两个问题的设计是:
- 计算一致性
- SQL 每次执行会对应到确定的时间窗口,由此得到确定数据集再调度 SQL 计算。Scheduled SQL 实例运行时,SQL 查询的时间窗口是基于调度时间渲染得到,左闭右开格式,与实例的创建时间、执行时间无关。例如调度时间为
2021/01/01 10:00:00
,SQL时间窗口的表达式为[@m - 10m, @m)
,则实际的SQL时间窗口为[2021/01/01 09:50:00, 2021/01/01 10:00:00)
。
- SQL 计算的结果在插入目标时,需要考虑数据重复可能带来的业务影响。对于 append 模式写,例如 Scheduled SQL 结果写 Logstore,写入客户端与 SLS 服务端实现了 exactly-once 协议。对于 overwrite 模式写,更容易做到原子性,未来会规划 Scheduled SQL 写数据库的支持。
- SQL 每次执行会对应到确定的时间窗口,由此得到确定数据集再调度 SQL 计算。Scheduled SQL 实例运行时,SQL 查询的时间窗口是基于调度时间渲染得到,左闭右开格式,与实例的创建时间、执行时间无关。例如调度时间为
- 数据的完整性
- 作业上设置延迟执行参数从业务上给与指导,在实例的调度时间点上,往后延迟 N 秒才真正开始触发实例运行,而实例查询的时间范围不受延迟参数影响。例如设置调度间隔为每小时、延迟执行为30秒,那么一天生成24个实例,其中某实例的调度时间为
2021/4/6 12:00:00
,执行时间为2021/4/6 12:00:30
。这个设计在大部分场景下可以解决数据迟到问题,但对于写 logstore 存储(数据写入后将无法更新)来说,完全避免延迟问题是难以实现的。极端情况下,数据迟到问题可通过事后的实例重试来补结果。
- 将 SQL 查询的时间窗口按分钟对齐(例如整分钟),以保证在 SLS 索引模型优化(batch log-group 组成倒排 doc)时依然能保证绝对的计算准确。
- 作业上设置延迟执行参数从业务上给与指导,在实例的调度时间点上,往后延迟 N 秒才真正开始触发实例运行,而实例查询的时间范围不受延迟参数影响。例如设置调度间隔为每小时、延迟执行为30秒,那么一天生成24个实例,其中某实例的调度时间为
调度场景
Scheduled SQL 作业依次调度多个实例执行,无论是正常被调度还是被动异常实例重试的情况,同时只有一个实例处于运行中,不存在多个实例并发执行的情况。
在 SLS 数据场景下,主要的几种调度场景如下:
- 场景一:实例延迟执行
无论实例是否延迟执行,实例的调度时间都是根据调度规则预先生成的。虽然前面的实例发生延迟时,可能导致后面的实例也延迟执行,但通过追赶执行进度,可逐渐减少延迟,直到恢复准时运行。
- 场景二:从某个历史时间点开始执行Scheduled SQL作业
在当前时间点创建Scheduled SQL作业后,按照调度规则对历史数据进行处理,从调度的开始时间创建补运行的实例,补运行的实例依次执行直到追上数据处理进度后,再按照预定计划执行新实例。
- 场景三:固定时间内执行Scheduled SQL作业
如果需要对指定时间段的日志做调度,则可设置调度的时间范围。如果设置了调度的结束时间,则最后一个实例(调度时间小于调度结束时间)执行完成后,不再产生新的实例。
- 场景四:修改调度配置对生成实例的影响
修改调度配置后,下一个实例按照新配置生成。一般建议同步修改SQL时间窗口、调度频率等配置,使得实例之间的SQL时间范围可以连续。
- 场景五:重试失败的实例
正常情况下,一个Scheduled SQL作业按照调度时间的递增顺序生成执行实例。如果实例执行失败(例如权限不足、源库不存在、目标库不存在、SQL语法不合法),系统支持自动重试,当重试次数超过您配置的最大重试次数或重试时间超过您配置的最大运行时间时,重试结束,该实例状态被置为失败,然后系统继续执行下一个实例。
您可以对失败的实例设置告警通知并进行手动重试。您可以对最近7天内创建的实例进行查看、重试操作。调度执行完成后,系统会根据实际执行情况变更实例状态为成功或失败。
Scheduled SQL 在访问日志上的应用
场景需求
在阿里云上,SLB/OSS 的被用到很多的基础计算、存储服务。在使用过程中如果要得到细粒度可观察性,都绕不过访问日志,在深度使用后您可能会有体感:
- 访问日志与 request 数一比一关系,数据量很大,造成存储成本增加并拖慢计算。
- 访问日志有时效性,近 15 天日志需要交互式查询分析支持,历史数据需要具备降精度的指标查询能力。
- 访问日志有留存的需求,需要长期存储以备审计。
整体方案
以 SLB 七层访问日志为例,这里介绍一种实践:
- 基于 Scheduled SQL 功能,将历史原文数据压缩为低精度数据,支持长期的索引存储并大大提升分析效率。
- 根据业务需要,原文数据支持全局搜索和无损的 SQL 分析,可以设置存储周期为 15天。
- 历史数据原文投递到 OSS,支持极低成本存储,低频的审计捞数据操作也是方便的。
整体方案图如下:
OSS投递操作步骤参考将日志服务数据投递到OSS。
Scheduled SQL 配置使用增强型资源池,默认 STS 角色授权,最终计算结果写同区域 Logstore:
使用Scheduled SQL时,建议根据业务情况,同时兼顾数据实时性和准确性。
- 考虑数据上传日志服务存在延迟情况,您可以结合数据采集延迟以及业务能够容忍的最大结果可见延迟,设置执行延迟和SQL时间窗口(结束时间往前一点),避免实例执行时SQL时间窗口内的数据未全部到达。
- 建议SQL时间窗口按分钟对齐(例如整分钟、整小时),以保证上传局部乱序数据时的数据准确度。
在这里每分钟调度一次 SQL 计算最近一分钟窗口的数据,并设置延迟执行(如果对于实时性要求不高,建议这个值设置大一些):
Scheduled SQL 写出到目标 Logstore 数据的结果如下图,其中 tag 字段是系统默认添加的信息,用于数据的搠源。
Scheduled SQL 调度生成的实例信息在任务管理页面可以查看,对于失败的任务可以做重试。
方案效果
- 功能体验上:
- 热、温数据存储、分析,支持交互式查询、分析的能力,保留了灵活性。
- 冷数据分析,支持分钟粒度的自定义指标查询(例如本文是 host、method、status 维度统计),可以快速实现问题分析,同样查询范围延迟降低两个数量级。
- 冷数据存储,以压缩格式投递到 OSS 存储,保留了审计能力。
- 热、温数据存储、分析,支持交互式查询、分析的能力,保留了灵活性。
- 存储成本上:在永久存储的背景下,存储量降低到之前的 1/1000,OSS 上的压缩格式存储且做到极低的单价。
注:目前 Scheduled SQL 已发布部分区域(参考快速开始使用 Scheduled SQL),其它区域正在逐个开放中,如有问题或需求可以工单或钉钉群联系 SLS 团队。