更快更强,SLS 推出高性能 SPL 日志查询模式

news2024/11/26 8:43:13

作者:无哲

引言

随着数字化进程的持续深化,可观测性一直是近年来非常火热的话题,在可观测的三大支柱 Log/Trace/Metric 中,日志(Log)数据一般是最为常见的,企业迈向可观测性的第一步,也往往始于日志数据的采集上云。日志完成收集后,最直接的需求就是从海量日志数据中检索分析出有价值的信息。随着日志数据量的不断增长,数据种类不断增多并日益朝着非结构化、多场景、多模态等方向演进,传统的日志搜索方式已经越来越难以满足不同场景下多样化、个性化的分析需求。

日志数据的查询分析需求是多样化的

日志(Log)数据作为可观测场景中最基础的数据类型之一,具备以下特点 :

  • 不可变: 日志数据一旦产生就不会被再次修改,是对事件原始信息的忠实记录,往往结构不太固定。
  • 数据随机: 比如异常事件日志、用户行为日志,一般天然就是随机的、难以预测的。
  • 来源多样: 日志数据种类繁多,不同来源的数据难以具有统一的 Schema。
  • 业务复杂: 不同的业务参与方对数据的理解不同,写日志过程中难以预见到后期具体的分析需求。

这些因素导致日志数据在采集过程中往往并不存在一个理想的数据模型可以用来预处理日志数据,因此更常见的做法是直接采集存储原始的日志数据,这可以称为是一种 Schema-on-Read 的模式,或者是所谓的寿司原则(The Sushi Principle:Raw data is better than cooked, since you can cook it in as many different ways as you like)。

这种直接存储原始数据的做法,意味着在分析的时候往往需要动态实时的对数据进行处理(比如 json 处理、正则提取、数学计算等等);而且由于不同分析人员对数据特征缺乏先验知识,一般也需要对数据先进行一定的探索式分析。

也就是说,在日志查询分析的过程,既需要能够展现非结构化的文档结构,又需要丰富的算子进行实时处理,同时最好还能够便捷的支持级联式、探索式的分析方式。

理想的日志查询语法应该是什么样的

日志数据分析通常可以分为两大类场景:

一类是查询类场景,或者说是搜索场景、纯过滤场景,即按照特定的条件过滤掉不需要的日志,并针对符合条件的日志直接输出日志原文。

一类是分析类场景,主要包括聚合分析(比如 sum、sort)、关联分析(比如多个表 join),需要对数据进行更复杂的计算,输出结果一般是表格模式。

这里我们重点关注纯查询过滤的场景,在 SLS 中既可以用传统的搜索语法(如 Key:XXX ),也可以在标准 SQL 中使用 where 语句(如 * | select * where Key like ‘%XXX%’),两种方式各有优点,却也都有着各自的局限性。

对于查询语法来说,天然就是为过滤搜索场景而生的,但是可惜表达能力有限,只能支持关键词匹配,以及多个条件的 And/Not/Or 的逻辑组合,无法支持更为复杂的处理逻辑。

而对于 SQL 语法来说,优点是表达能力强,但 SQL 是表格模型,不便于查看原始日志结果(因为要将字段对齐,输出结果中对于不存在的列就会填充大量 null),而且对于 select * 这样的语句,也只能输出开启字段索引的字段。

详细对比如下:

纯查询场景的挑战搜索查询语法标准SQL语法
需要复杂的处理逻辑弱,主要就是支持关键词匹配强,具备丰富的处理函数和算子,如正则匹配、json提取
输出内容是非结构化的强,输出的是原文,便于查看弱,输出的是表格模式,不存在的字段全部要补空值,不利于查看
翻页逻辑简单,控制台可以直接点,API传递offset+lines即可较复杂,需要在SQL中通过limit x,y的方式,并且要指定排序方式
查看结果的时间分布简单,histogram柱状图直观展示出不同时间的分布较复杂,需要在SQL中按照时间分组求和,再按时间排序,然后再画线图查看
结果中输出所有原文字段输出的是原文,天然包含所有字段较麻烦,select * 只能输出建了字段索引的列
获取部分字段不支持select指定列即可
计算出新的列不支持select中可以计算新的列
多级级联处理能力无法表达可以通过with语句、SQL嵌套,但写起来较为复杂

既然两种方式各有所长,那么我们是否可以结合这两种方式的优点,支持一种新的查询语法,既能遵从文档模型(直接输出日志原文、不按表格模式、不要求所有输出列有索引),又能支持各种好用的 SQL 算子,同时还能够支持一种更便捷的级联处理(而不需要复杂的多层嵌套)呢?

SPL 管道式查询语言

SPL(详见 SPL 概览 [ 1] ),即 SLS Processing Language,是 SLS 对日志查询、流式消费、数据加工、Logtail 采集、以及数据 Ingestion 等需要数据处理的场景,提供的统一的数据处理语法。

SPL 基本语法如下:

Status:200 | extend urlParam=split_part(Uri, '/', 3)

其中 是数据源,对于日志查询的场景,指的就是索引查询语句。 是 SPL 指令,支持正则取值、字段分裂、字段投影、数值计算等多种丰富的操作,具体参考 SPL 指令介绍 [ 2]

从语法定义上可以看到,SPL 是支持多个 SPL 指令组成管道级联的。对于日志查询的场景来说,在索引查询语句之后,可以根据需要通过管道符不断追加 SPL 指令,从而获得类似 Unix 管道处理文本数据的体验,对日志进行灵活的探索式分析。

SPL 能做什么?

筛选字段获得更精确的视图

在查询日志的时候,往往是带着某个目的去检索,这个时候一般是只关心其中的部分字段。这时就可以使用 SPL 中的 project 指令,只保留自己关心的字段。(或者使用 project-away 指令,移除不需要看到的字段)

实时计算出新的字段

使用 Extend 指令,可以基于已有字段加工提取出新的字段,可以使用丰富的函数(这些大部分是和 SQL 语法通用的)进行标量处理。

Status:200 | extend urlParam=split_part(Uri, '/', 3)

同时也可以根据多个字段计算出新的字段,比如计算两个数字字段的差值。(注意字段默认是被视为 varchar,进行数字类型计算的时候要先通过 cast 转换类型)

Status:200 | extend timeRange = cast(BeginTime as bigint) - cast(EndTime as bigint)

并且也可以在后续管道中,再对这个计算后的值进行 where 判断过滤:

Status:200 
| where UserAgent like '%Chrome%'
| extend timeRange = cast(BeginTime as bigint) - cast(EndTime as bigint)
| where timeRange > 86400
自由的展开半结构化数据

SPL 提供了 parse-json、parse-csv 这样的指令,可以将 json、csv 类型的字段,直接完全展开出为独立的字段,之后就可以直接对这些字段进行操作。省去了书写字段提取函数的开销,在交互式查询场景中这种写法是更为便捷的。

SPL 之前已经在扫描查询模式上全地域支持,详见扫描查询 [ 3] 。扫描查询可以不依赖索引,直接扫描原始日志数据计算。下图中这个例子,就是在原始日志数据上,通过 SPL 管道完成了模糊过滤、json 展开、字段提取等多种操作。

当前扫描模式 SPL 难以处理大规模数据

扫描模式具备很好的灵活性,但最大的问题是性能不足,特别是面对大规模数据时难以在有限时间内处理完。现有的扫描查询限制单次最多扫描 10 万行,超出限制后需要控制台手动点击触发下一次扫描(或者 SDK 触发下一次调用)。

由于性能受限,导致现有的 SPL 查询在使用上存在以下问题:

  • 对于过滤结果较为稀疏的查询,由于单次扫描的原始数据量太少,很难在有限时间内扫描到结果。
  • 查询界面的直方图展示的是索引过滤后的结果(以及扫描进度),而无法展示出 SPL 条件过滤后的最终结果分布。
  • 无法支持针对最终过滤后的结果随机翻页,只能按照已经扫描的原文的 offset 进行连续翻页扫描。

这些约束,导致扫描模式下的 SPL,面对具备较大规模的日志数据,使用体验较差,也就很难发挥出实际用处。

极致优化,高性能 SPL 模式

为了从根本上改善 SPL 查询的执行性能,真正发挥出 SPL 灵活计算的优势。我们从计算架构、执行引擎、IO 效率等多个方面对 SPL 查询进行了重大优化。

计算下推,并行化加速

首先要在架构上解决水平扩展的问题。原有的架构下,因为存储节点不具备复杂表达式的计算能力,只能将原始数据全量拉取到计算节点处理,大数据量的读取、传输、序列化是很大的瓶颈。

在查询场景下,实际单次请求每次需要的最终结果行数是比较少的(一般单次请求 100 行以内,超出后通过翻页请求获取),关键在于当 SPL 语句中包含 where 条件的时候,就存在从大量数据中计算 where 条件过滤的过程。为了能够处理大规模数据并减少传输开销,我们就需要将 where 条件的计算下推到各个 shard 所在的存储节点上处理。相应的,也就必须要求存储节点具备对 SPL 中丰富算子的高效处理能力。

为此我们在存储节点上,引入 C++ 向量化计算引擎,在存储节点上读取了原始的数据后,直接原地就可以进行高效的过滤计算。只有对满足 where 条件的日志,才需要进行剩余的 SPL 计算并输出最终结果。

计算下推之后,整个的处理能力就可以随着 shard 数目水平扩展,同时也大幅减少了存储节点和计算节点之间的数据传输、网络序列化开销。

向量化计算,多级火箭加速

计算下推解决了按 shard 水平扩展的问题,接下来我们还要进一步的大幅提升每个 shard 上的处理能力。

扫描模式的 SPL,最大性能瓶颈还是在于直接扫描读取原始的行数据。这样读放大会比较严重,IO 效率很低。正如使用 SQL 分析能力时需要开启字段索引(并开启统计),这些字段的数据就可以被高效的读取和计算,那 SPL 同样也可以基于字段索引来进行高性能的数据 IO,然后再基于 SIMD 向量化技术进行高性能计算,同时在过程中尽可能减少额外计算量。

以图中的 SPL 为例,在下推到存储节点后,会经过“多级火箭”进行层层加速:

  • 按照查询时间范围过滤(当数据量非常大时,建议选择必要的时间范围进行分析)。
  • 处理第一级管道 Status:200 ,关键词索引条件过滤(这个是最快的,有索引过滤条件尽量写上过滤条件)。
  • 处理 SPL 中的 where 过滤条件,基于字段索引(并开启统计),高效读取对应的数据。
  • 向量化高性能计算,获得过滤结果,然后再计算剩余的 SPL 部分,得到最终结果
  • 同时在计算过程中,如果发现过滤结果行数已经满足要求,则尽量提前终止(特别对于高命中率的情形,可以尽量减少不必要的计算)。

经过这些优化之后,高性能 SPL 的执行性能相比扫描模式,得到了质的飞跃。

高性能 SPL 的性能表现

我们以单个 shard 处理 1 亿行数据为例,来评估高性能 SPL 的性能表现。在线上真实环境创建一个 Logstore,10 个 shard,查询时间范围内有 10 亿数据。(服务访问日志数据)

选取如下几个典型的场景:

场景 1:通过字符串函数处理后过滤

SPL 语句:* | where split_part(Uri, ‘#’, 2) = ‘XXX’

场景 2:短语查询、模糊查询

SPL 语句:* | where Content like ‘%XXX%’

场景 3:json提取子字段,然后再过滤

SPL 语句: * | where json_extract_scalar(Params, ‘Schema’) = ‘XXX’

在上述语句中选择不同的比较参数,构造出不同的命中率的场景(比如命中率 1%,指的是原始 10 亿条数据中,有 1000 万条满足 where 条件的结果数据),并请求前 20 条满足条件数据(对应 GetLogs 接口的 API 参数是 offset=0, lines=20),测试平均耗时。

命中率场景1 耗时场景2 耗时场景3 耗时
1%52 ms73 ms89 ms
0.1%65 ms94 ms126 ms
0.01%160 ms206 ms586 ms
0.001%1301 ms2185 ms3074 ms
0.0001%2826 ms3963 ms6783 ms

可以看出:

  • 当命中率较高时,不同场景下都有很好的性能表现,甚至可以接近关键词索引查询。
  • 当命中率很低时,由于要实时计算大量数据,需要更长一些的执行时间,具体实际性能表现和数据字段的长度、语句中算子复杂度、命中结果在原始数据的分布位置等因素都有关。
  • 整体来看,高性能 SPL 对于数十亿级别的日志量级,可以在数秒内完成计算。

控制台交互升级,展示过滤后结果的直方图

高性能模式 SPL,由于计算性能有了大幅提升,因此控制台展示 histogram,直接展示的是整个 SPL 语句过滤后的结果分布。(意味着整个范围内的数据也进行了全量的计算)

举个例子,原始日志有 1000 万条,SPL 语句是 Status:200 | where Category like ‘%xx%’,符合 Status:200 条件的日志是 10 万条,这其中再符合 where Category like ‘%xx%’ 条件的日志是 1000 条,则查询界面上 histogram 柱状图展示的是这最终的 1000 条日志随时间的分布情况。

相应的,和纯索引查询模式下的交互完全相同,高性能模式 SPL 支持随机翻页,也支持点击柱状图直接跳转到对应区间的查询结果。

API 调用简化,统一的 offset 语义

在高性能 SPL 模式下,调用 GetLogs 通过 SPL 语句查询日志时,offset 直接表示的就是过滤后的结果偏移量,从而大大简化了 API 调用方式。也就是说,使用上,和纯索引查询完全统一。直接按照过滤后最终结果的 offset 来翻页即可。

使用说明

如何开启高性能 SPL?

无须显式指定运行模式。当 SPL 语句中所有参与 where 条件计算的列,全都已经创建了字段索引(并开启了统计),则自动按照高性能模式执行;否则以扫描模式执行。

是否计费?

高性能 SPL 模式,查询本身不产生任何额外费用。

🔔 注意: 如果没有完全命中索引列导致走的是扫描模式 SPL(并且当前 Logstore 是按功能计费模式),则按照查询过程中的扫描原始日志数据量计费。

最佳实践

尽可能增加索引查询语句预过滤

如果有关键词索引过滤条件,尽可能使用,放在多级 SPL 管道的第一级。索引查询的效率总是最高的。

复杂过滤场景,建议使用 SPL 代替 SQL

特别是对于模糊匹配、短语匹配、正则匹配、json 提取以及更复杂的各种纯过滤场景,以前只能使用 SQL 语法(* | select * where XXX),现在建议替换为 SPL 语法(* | where XXX)。可以能更好的输出日志原文(而不是表格模式),更便捷的看到过滤后的结果柱状图分布,以及更简洁的输入体验。

更多功能,敬请期待

SPL 也能支持聚合操作

目前 SPL 仅支持纯查询过滤场景下的使用,接下来在日志查询场景下,SPL 语法会进一步支持排序、聚合等操作(聚合后按照表格模式输出),从而使得 SPL 的多级管道级联处理能力更强大、更完善,能够更好的对日志进行更灵活的查询分析。

总结

企业的日志数据上云后,从海量日志中搜索出想要的信息,是一项最基本的需求。SLS 推出 SPL 查询语法,支持类似 Unix 管道的级联语法,并支持 SQL 的各种丰富的函数。同时,基于计算下推、向量化计算等优化,支持高性能模式 SPL 查询,可以在数秒内处理亿级数据,并且支持 SPL 过滤后最终结果的分布直方图、随机翻页等特性,具备和纯索引查询模式类似的体验。对于模糊、短语、正则、json 提取以及各种复杂过滤场景,推荐使用 SPL 语句来进行查询。

高性能模式 SPL 目前正在按区域逐步发布中,有任何使用上的问题或者需求,可以通过工单或者直接在 SLS 的钉钉群咨询。SLS 会一直持续不断的优化,提供更强大、更好用的可观测存储分析引擎。

相关链接:

[1] SPL 概览

https://help.aliyun.com/zh/sls/user-guide/spl-overview

[2] SPL 指令介绍

https://help.aliyun.com/zh/sls/user-guide/spl-instruction

[3] 扫描查询

https://help.aliyun.com/zh/sls/user-guide/scan-based-query-overview

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2060845.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《黑神话:悟空》总销量已破 450 万份,总销售额超过15亿元,对于单机游戏来说,这一成绩意味着什么?

《黑神话:悟空》总销量突破450万份,总销售额超过15亿元,意味着几个关键点: 市场认可度高:这样的销量和销售额表明游戏受到了广泛的玩家欢迎,市场认可度极高。对于单机游戏而言,这代表了其在游戏…

深入浅出:你需要了解的用户数据报协议(UDP)

文章目录 **UDP概述****1. 无连接性****2. 尽最大努力交付****3. 面向报文****4. 多种交互通信支持****5. 较少的首部开销** **UDP报文的首部格式****详细解释每个字段** **UDP的多路分用模型****多路分用的实际应用** **检验和的计算方法****伪首部的详细内容****检验和计算步…

算法4:前缀和(下)

文章目录 和为K的子数组和可被k整除的子数组连续数组矩阵区域和 一定要看懂算法原理之后写代码,博主大概率因注意力不够,看了好多遍,才看懂原理细节。 切记,不彻底懂原理,千万别看代码 和为K的子数组 class Solution …

K8s部署安装

目录 一.K8s简介 1.Kubernetes 的关键概念 2.Kubernetes 的功能优势 3.节点(Node) 4.组件(Component) 二.Kubernetes集群架构 三.安装部署环境 1.初始化系统环境 2.安装容器引擎 3. 安装containerd 4.安装crictl工具 5…

鸿蒙(API 12 Beta3版)【DRM会话管理(C/C++)】数字版权保护开发

DRM会话管理(MediaKeySession)支持媒体密钥管理及媒体解密等,MediaKeySession实例由系统管理里的MediaKeySystem实例创建和销毁。 开发步骤 导入NDK接口,接口中提供了DRM相关的属性和方法,导入方法如下。 #include &…

YoloV8训练单通道数据方法+单通道Onnx模型转换

1. ultralytics/cfg/models/v8/yolov8-xxx.yaml 添加ch: 1 2. ultralytics/utils/checks.py 注释assert amp_allclose(YOLO("yolov8n.pt"), im) 3. ultralytics/nn/tasks.py 添加:batch[img] batch[img][:,:1,:,:] 4. ultralytics/nn/autobacken…

文件存储系统的总结

仪表试验报告整理技巧和反思 仪表调试报告技巧 目的:签字更顺利。报告依据、减少页数、正确率、工作量 表1/2 序号 目的 原因方法 降低签字页数 减少报告页数,增加回路测试类报告的每页信息容量 单元格高度:0.7cm;可以正…

ASP.NET Core 6.0 ServiceCollection 实现依赖注入

ASP.NET Core6 lOC容器 控制反转(Inversion of Control, IoC)是一种软件设计模式,其目的是降低代码之间的耦合度。在C#中,可以使用依赖注入(Dependency Injection, DI)来实现控制反转。 一般系统分为 UI …

将iso格式的镜像文件转化成云平台能安装的镜像格式(raw/vhd/QCOW2/VMDK )亲测--图文详解

1.首先,你将你的iso的文件按照正常的流程和需求安装到你的虚拟机中,我这里使用的是vmware,安装完成之后,关机。再次点开你安装好的那台虚拟机的窗口,如下图 选中要导出的镜像,镜像需要关机 2.点击工具栏的文件------选择 导出 整个工程到 ovf 格式—这里你可以选择你要导…

LearnOpenGL——SSAO学习笔记

LearnOpenGL——SSAO学习笔记 SSAO一、基本概念二、样本缓冲三、法向半球四、随机核心转动五、SSAO着色器六、环境遮蔽模糊七、应用SSAO遮蔽因子 SSAO 一、基本概念 环境光照是我们加入场景总体光照中的一个固定光照常量,它被用来模拟光的散射(Scattering)。散射应…

数字图像处理【14】特征检测——Harris角点检测

在上一篇文章已经介绍了opencv特征检测中的一些必要的概念,介绍了什么是特征,什么是角点,这些角点特征可以做什么。今天来看看对于我们人来说很容易就识别到角点特征,对于计算机来说是如何识别的,具体的步嘴原理是怎样…

78.内存对齐

目录 一.什么是内存对齐 二.为什么要内存对齐 三.视频教程 一.什么是内存对齐 有下面例子 #include <stdio.h>struct TEST {char a;int b; };int main(void) {struct TEST test;test.a A;test.b 1;printf("sizeof %ld\n",sizeof(test));return 0;} …

JVM指令重排序

文章目录 什么是指令重排序编译器优化JIT 编译优化处理器优化重排序数据依赖性 硬件层的内存屏障指令重排的代码验证好处减少管道阻塞提高缓存利用率利用并行执行单元性能提升更好地利用硬件资源 问题内存可见性问题编程复杂性增加调试困难 解决方案&#xff1a;Java内存模型&a…

AICon 全球人工智能与机器学习技术大会参会有感

目录 引言 大会背景 大会议程 参会体验 会后感想 结束语 引言 在数字化浪潮席卷全球的今天&#xff0c;人工智能和机器学习技术已成为推动社会进步和产业升级的关键力量。作为一名对AI技术非常感兴趣的开发者&#xff0c;在 8 月 18 日至 19 日这两天&#xff0c;我有幸参…

代码随想录算法训练营43期 | Day 15——110.平衡二叉树、 257. 二叉树的所有路径、404. 左叶子之和、222. 完全二叉树的节点个数

代码随想录算法训练营 代码随想录算法训练营43期 | Day 15110.平衡二叉树257. 二叉树的所有路径404. 左叶子之和222. 完全二叉树的节点个数 代码随想录算法训练营43期 | Day 15 110.平衡二叉树 /*** Definition for a binary tree node.* struct TreeNode {* int val;* …

【读点论文】Adaptive degraded document image binarization,真难复现,流程有点复杂

Adaptive degraded document image binarization Abstract 本文介绍了一种新的自适应方法&#xff0c;用于对退化文档进行二值化和增强。所提出的方法不需要用户进行任何参数调整&#xff0c;并且可以处理由于阴影、不均匀照明、低对比度、大信号相关噪声、污点和应变而发生的…

Spring 的 Aop 支持

Spring 的 Aop 支持 一、AOP基本概念1_AOP基本术语2_通知类型回顾3_AOP基于代理4_SpringBoot整合AOP 二、整体流程剖析1_AspectJAutoProxyRegistrar2_AnnotationAwareAspectJAutoProxyCreator1_继承结构2_初始化时机3_AnnotationAwareAspectJAutoProxyCreator的作用时机 3_收集…

【C++】_string类字符串详细解析(1)

假如没有给你生命&#xff0c;你连失败的机会都没有。你已经得到了最珍贵的&#xff0c;还需要抱怨什么!&#x1f493;&#x1f493;&#x1f493; 目录 ✨说在前面 &#x1f34b;知识点一&#xff1a;什么是string&#xff1f; •&#x1f330;1.string类的概念 •&#x1…

嘉立创PCB4层板

视频&#xff1a; 四层板PCB设计保姆级教程&#xff08;1&#xff09;&#xff1a;3.0HUB设计概述_哔哩哔哩_bilibili&#xff08;虽然是四层板实际这个还是两层板&#xff01;&#xff09; 不太建议看这个。 四层PCB 最简单终教学 高校培训课程 深入浅出 不会电路也能学会 设…

Nginx的核心!!! 负载均衡、反向代理

目录 负载均衡 1.轮询 2.最少连接数 3.IP哈希 4.加权轮询 5.最少时间 6.一致性哈希 反向代理 测试 之前讲过Nginx 的简介和正则表达式&#xff0c;那些都是Nginx较为基础的操作&#xff0c;Nginx 最重要的最核心的功能&#xff0c;当属反向代理和负载均衡了。 负载均…