OpenSearch Service优化引擎:用SQL/PPL查询原始日志
DataHot 速览
本文介绍如何用PPL和SQL在Amazon OpenSearch Service优化引擎上直接对原始日志和追踪数据运行快速分析查询。该引擎以Parquet列式存储配合DataFusion向量化执行,可对数十亿事件进行聚合、过滤和扫描,无需预先移动或重塑数据。文章通过一次事件调查,逐步演示多维分解、延迟分布、错误率和集群规模等分析。
为什么值得关注:该优化引擎展示了直接在原始日志数据上进行交互式分析的能力,对日志分析、可观测性与实时分析场景有实践参考价值。
本文目录 9 节
译文
AI 逐段翻译在这篇文章中,您将学习如何使用PPL和SQL直接对Amazon OpenSearch Service中的原始日志和跟踪数据运行快速分析查询。
Amazon OpenSearch Service 是一项完全托管的服务,帮助您在AWS云中部署、扩展和运行 OpenSearch,这是用于搜索、分析和可观测性的开源套件。OpenSearch Service支持搜索和实时分析工作负载,从词汇和混合搜索到日志分析和可观测性。本文重点介绍日志分析,以及一个实际问题:在不移动或重塑数据的情况下,您可以对原始日志和跟踪数据直接进行多少分析工作?
OpenSearch Service中的新优化引擎回答了这个问题:您可以将Piped Processing Language (PPL) 和Structured Query Language (SQL) 查询直接指向原始日志和跟踪数据。该引擎对您摄取的数据(完全按照您摄取的方式)返回数十亿事件的聚合、过滤和扫描。在本文中,您将逐步遵循一个单一事件调查,一次一个查询。您将看到引擎如何回答每个新问题,从多维度分解和延迟分布到错误率和机队规模。结果背后没有预计算结构。
优化引擎如何查询原始数据
优化引擎将数据存储在列式Apache Parquet格式中,并通过Apache DataFusion(一种向量化执行引擎)运行查询,Apache Calcite规划每个查询。由于引擎按列存储数据,分析查询只读取它触及的列,并批量处理它们的值,而不是完整读取每个匹配的文档。除了列式格式外,引擎还在相同数据上保留一个倒排索引,因此查询规划器将每个操作路由到最适合它的路径:列式引擎用于聚合和分析扫描,倒排索引用于选择性搜索和过滤。
您可以通过您今天使用的相同Bulk API和客户端摄取日志和跟踪数据,并对它们编写PPL或SQL查询。
一次一个查询的调查
以下演练从站点可靠性工程师(SRE)的角度,追踪了一个常见的可观测性用例:实时事件期间的根因分析。工程师注意到延迟升高和一些错误警报,没有指向明确原因的线索。没有现有的仪表板涵盖这个特定形状的问题,因此工程师打开Amazon OpenSearch Service,开始对原始跟踪数据提出问题,让每个答案决定下一个问题。PPL非常适合这项工作。每个命令转换数据并传递给下一个,因此工程师从左到右阅读查询,就像他们在调查中思考一样。
该演练使用来自合成负载生成器的生成的OpenTelemetry (OTEL) 数据,规模达到十亿文档。重点是查询能力,即工程师可以直接从原始跨度中表达和检索的内容,而不是每个结果中的具体值。
第1步:评估范围
任何调查的第一个问题是信号有多广泛。工程师在一次遍历中跨服务、HTTP方法和云区域分解错误,大约覆盖11亿个跨度。
source=otel-traces
| where @timestamp >= timestamp("2026-05-15 00:00:00") and @timestamp < timestamp("2026-05-18 00:00:00")
| eval e = if(status_code = 2, 1, 0)
| stats sum(e) as errors, avg(durationInNanos) as avg_ns, count() as total_count
by serviceName, http_method, cloud_region
| sort - errors
| head 8简而言之,这个查询回答了工程师的第一个问题:故障发生在哪里?它计算错误跨度,并按服务、HTTP方法和AWS区域在一次遍历中分解它们。而不是猜测首先打开哪个服务,工程师得到一个受影响最大的组合的排名列表进行调查。
| 错误 | 总数 | 平均纳秒 | 服务名称 | HTTP方法 | 云区域 |
| 730 | 112,436 | 41,246,806 | 出口服务 | GET | us-west-2 |
| 722 | 111,215 | 41,000,227 | 目录服务 | PUT | eu-central-1 |
| 704 | 112,051 | 41,295,539 | 图像服务 | PATCH | us-west-2 |
| 612 | 93,214 | 41,451,145 | 健康检查服务 | PUT | us-east-1 |
| 609 | 94,314 | 41,418,897 | 认证服务 | POST | us-east-1 |
| 609 | 94,414 | 41,447,444 | 电子邮件服务 | PATCH | ap-northeast-1 |
| 593 | 89,726 | 41,047,114 | 支付服务 | PUT | eu-central-1 |
| 581 | 89,854 | 41,195,643 | 文件服务 | PUT | ap-northeast-1 |
错误分布在服务、方法和区域之间,这指向一个系统性模式,而不是单个行为异常的服务。
第2步:检查是否有单个主机集中了故障
这种分布可能仍然反映了一个饱和节点或机队范围的状态。为了区分两者,工程师按异常类型、服务和主机对整个索引中的故障进行分组,没有时间过滤器来缩小扫描范围。
source=otel-traces
| where isnotnull(exception_type)
| stats count() as total_count by exception_type, serviceName, host_name
| sort - total_count
| head 8| 总数 | 异常类型 | 服务名称 | 主机名 |
| 6 | 死锁检测异常 | 通知服务 | ip-10-0-16-34 |
| 6 | 非法状态异常 | API网关 | ip-10-0-180-234 |
| 6 | 文件未找到异常 | 购物车服务 | ip-10-0-90-162 |
| 6 | 连接拒绝异常 | 功能标志服务 | ip-10-0-8-123 |
| 5 | 超时异常 | 认证服务 | ip-10-0-97-78 |
| 5 | 并发修改异常 | 订单服务 | ip-10-0-165-15 |
| 5 | 超时异常 | 优惠券服务 | ip-10-0-158-25 |
在此示例中,计数很低,每一行落在不同的主机上,因此没有单个节点突出。这指向一个机队范围的模式,而不是一个坏机器。在生产数据上,相同的查询直接做出了区分:代码级错误会跨多个主机显示,而单个故障节点会将其错误集中在一个 主机名。
第3步:量化每个服务的延迟分布
接下来,工程师为每个服务提取延迟配置文件。这包括计数、平均、最小和最大持续时间,以查看每个服务的行为以及分布的范围。
source=otel-traces
| where @timestamp >= timestamp("2026-05-15 00:00:00") and @timestamp < timestamp("2026-05-18 00:00:00")
| stats count() as total_count, avg(durationInNanos) as avg_ns, min(durationInNanos) as min_ns, max(durationInNanos) as max_ns
by serviceName
| sort - total_count
| head 8| 服务名称 | 总数 | 平均(纳秒) | 最小(纳秒) | 最大(纳秒) |
| 事件总线 | 11,087,263 | 41,249,552 | 26,113 | 9,304,132,159 |
| 调度程序服务 | 9,175,964 | 41,251,927 | 21,919 | 13,432,040,933 |
| CDN服务 | 9,173,572 | 41,225,385 | 23,468 | 13,768,293,306 |
| 机器学习推理 | 9,036,753 | 41,289,101 | 40,410 | 14,625,084,517 |
| 合规服务 | 8,274,635 | 41,294,694 | 41,915 | 7,462,983,016 |
| 指标收集器 | 7,804,234 | 41,334,728 | 16,535 | 23,228,217,669 |
| 通知服务 | 7,688,714 | 41,204,635 | 51,562 | 8,695,311,374 |
| 图像服务 | 7,674,406 | 41,248,069 | 47,473 | 15,350,500,299 |
这为工程师提供了每个服务的延迟指纹:平均值接近41毫秒。但多秒级的最大值揭示了长尾分布,与请求在慢依赖后面排队的情况一致。
第4步:测量每个服务的错误率
为了跟踪服务级别目标,工程师计算每个服务的错误率(错误与总请求之比)。查询使用内联条件,然后是分组求和和计数,最后进行除法以得到错误率。
source=otel-traces
| eval is_err = if(status_code = 2, 1, 0)
| stats sum(is_err) as errors, count() as total_count by serviceName
| eval error_pct = round(100.0 * errors / total_count, 2)
| sort - error_pct
| head 8| errors | total_count | error_pct | serviceName |
| 699,358 | 22,415,308 | 3.12 | payment-service |
| 647,811 | 26,880,140 | 2.41 | checkout-service |
| 562,811 | 30,096,860 | 1.87 | auth-service |
| 316,192 | 24,510,990 | 1.29 | cart-service |
| 288,314 | 30,671,704 | 0.94 | order-service |
| 202,612 | 28,140,552 | 0.72 | search-service |
| 186,012 | 33,820,415 | 0.55 | catalog-service |
| 134,722 | 35,453,247 | 0.38 | image-service |
工程师在查询中定义了错误率指标,引擎在整个索引上计算它。最繁忙的路径,如支付和结账,错误率接近3%,而有些服务保持在1%以下。
第5步:使用SQL调整集群规模
最后,工程师调整每个服务所占用的集群规模,这是一个容量和影响问题,并从PPL切换到SQL来表达。
SELECT serviceName,
COUNT(*) AS total_count,
COUNT(DISTINCT host_name) AS hosts
FROM otel-traces
GROUP BY serviceName
ORDER BY total_count DESC
LIMIT 8| serviceName | total_count | hosts |
| ml-inference | 35,481,688 | 2,535 |
| image-service | 35,453,247 | 2,491 |
| email-service | 35,443,569 | 2,517 |
| shipping-service | 30,700,372 | 2,438 |
| translation-service | 30,490,570 | 2,502 |
| auth-service | 30,096,860 | 2,466 |
| chat-service | 25,564,111 | 2,449 |
| recommendation-service | 25,366,844 | 2,483 |
该查询对高基数域执行 COUNT(DISTINCT),规模达数十亿行,在调查过程中切换语言对工程师来说不过是编写SQL而不是PPL。主机数量集中在约2,400–2,540范围内,因此每个服务都跨越了集群的很大一部分。这证实了先前的发现:错误反映了整个集群的模式,而不是单个节点。
工程师问了五个问题,运行了五个查询,每个答案都塑造了下一个。优化引擎直接从原始跟踪数据中为每个查询提供服务,无论是PPL还是SQL,都没有依赖汇总表或预计算摘要。
在您已经工作的地方运行这些查询
您不需要单独的工具来运行本教程中的查询。

图1:查询工作台中的调查查询和结果网格
查询工作台在OpenSearch Dashboards UI中提供了专门的编辑器,用于PPL和SQL。您编写查询,运行它,并在网格中读取结果,使用本文中展示的相同查询。当您想从书面查询转向交互式探索时,Discover会针对您的索引运行相同的PPL和SQL。在Discover中,您可以过滤、展开字段并深入单个文档,而无需离开页面。相同的查询语言在这两个地方都有效,因此您可以在Discover中开始调查,然后将其带到查询工作台,反之亦然,无需重写任何内容。

图2:Discover中的PPL查询和字段列表
保留所有数据并直接查询
直接查询原始数据只有在您能负担得起保留原始数据的情况下才有帮助。优化引擎比默认的通用引擎压缩可观测性数据的效率高出70%。这种压缩将“保留一切并直接查询”变成了实用的默认设置。您可以为无法预先预测的问题保留完整保真度的数据。而且存储成本比存储原始JSON更低。
这篇内容对你有用吗?
反馈只用于改善内容筛选,不等同于收藏