【SkyWalking从入门到精通】第42篇:OAL语法全解析:声明式指标计算的优雅之舞
2026/7/12 19:17:46 网站建设 项目流程

上一篇【第41篇】OAL是什么:观察力分析语言的前世今生
下一篇【第43篇】OAL实现原理:从脚本到字节码的魔法之旅


一、开篇:一句话定义一个指标

OAL的设计哲学是**“一句话,一个指标”**。不夸张地说,你甚至可以把OAL语法写在一张小纸条上——但它蕴含的能力足以覆盖99%的APM指标计算需求。

让我们从最经典的例子开始:

// 这就是一个完整的OAL指标定义——代码级别 service_resp_time = from Service.latency;

就这么一行代码,它在运行时做的事情包括:

  1. 把每个探针上报的Segment中属于同一个Service的数据聚合
  2. 计算latency的平均值
  3. 按1分钟/1小时/1天三个粒度分别存储
  4. 自动生成可被Dashboard查询的指标

现在让我们深入这片"少即是多"的语法世界。


二、OAL文件的完整结构

+------------------------------------------------------------------+ | 一个标准OAL文件的结构 | +------------------------------------------------------------------+ | | | 1. 注释(// 或 /* */) | | | | 2. import声明(引入source类) | | import org.apache.skywalking.oap.server.core.source.*; | | import org.apache.skywalking.oap.server.core.source.Service; | | | | 3. filter定义(可选,定义过滤表达式) | | filter active_endpoints = endpoint.avg > 0; | | | | 4. 指标定义(核心) | | service_resp_time = from Service.latency; | | | | 5. disable语句(禁用不需要的指标) | | disable(service_instance_throughput); | | | +------------------------------------------------------------------+ 图1:OAL文件的标准结构

三、指标定义语法:核心四元素

一个完整的OAL指标定义由四个元素组成:

指标名称 = from 数据源 . 聚合函数 ( 字段 ) ; ======== ==== ====== ======== == | | | | | 唯一标识 关键字 数据从哪里来 怎么计算 末尾分号

3.1 数据源(Source)

Source是OAL的"食材"。SkyWalking内置了以下标准Source类型:

// 最常用的Source类型Service// 服务级别的数据ServiceInstance// 服务实例级别的数据Endpoint// 端点级别的数据ServiceRelation// 服务间的调用关系EndpointRelation// 端点间的调用关系

每个Source都有自己的属性字段:

Service { String name; // 服务名 int latency; // 响应时间(ms) boolean status; // 是否成功 int httpResponseStatusCode; // ... } Endpoint { String name; // 端点URI int latency; // 响应时间 boolean status; // 是否成功 // ... }

3.2 聚合函数(Aggregation Functions)

OAL支持的聚合函数覆盖了APM场景的全部需求:

函数说明典型场景存储开销
.avg(field)平均值平均响应时间O(1)
.sum(field)累加值总调用次数O(1)
.max(field)最大值P100响应时间O(1)
.min(field)最小值最快响应O(1)
.count()计数调用次数O(1)
.longAvg(field)长整型平均值大数值平均O(1)
.doubleAvg(field)双精度平均值高精度平均O(1)
.p99(field)P99分位数99%用户响应O(k)
.p95(field)P95分位数95%用户响应O(k)
.p90(field)P90分位数90%用户响应O(k)
.p75(field)P75分位数75%用户响应O(k)
.p50(field)P50分位数/中位数典型响应O(k)
.histogram(field, ...)直方图分桶分布可视化O(n)
.thermodynamic(..)热力图响应分布O(n)
.percentile(field, [p1,p2..])自定义分位灵活分位数按需

3.3 基本语法示例

// ===== 服务级别指标 =====// 服务调用次数service_cpm=fromService.count();// 服务平均响应时间service_resp_time=fromService.avg(latency);// 服务99分位响应时间service_p99=fromService.p99(latency);// 服务成功率(百分比)service_sla=fromService.avg(status==true?100:0);// 服务调用总数service_sum_call=fromService.sum(calls);// ===== 端点级别指标 =====// 端点调用次数endpoint_cpm=fromEndpoint.count();// 端点平均响应时间endpoint_avg=fromEndpoint.avg(latency);// 端点成功率endpoint_sla=fromEndpoint.avg(status==true?100:0);// ===== 实例级别指标 =====// 实例调用次数instance_cpm=fromServiceInstance.count();// 实例JVM指标(如果有)instance_jvm_memory_heap=fromServiceInstance.avg(heapUsed);instance_jvm_memory_max=fromServiceInstance.avg(heapMax);instance_jvm_cpu=fromServiceInstance.avg(cpuUsage);// ===== 关系级别指标 =====// 服务间调用关系指标service_relation_client_cpm=fromServiceRelation.count();service_relation_server_cpm=fromServiceRelation.count();// 服务间调用延迟service_relation_client_call_sla=fromServiceRelation.avg(status==true?100:0);// 端点间调用关系指标endpoint_relation_cpm=fromEndpointRelation.count();

四、Filter表达式:数据的"安检门"

Filter让你只对感兴趣的数据做聚合。它的语法类似于Java的三元表达式,但更简洁:

// 语法格式 指标名 = from Source.(filter表达式).聚合函数(字段); // 示例1:只统计成功的调用 service_success_cpm = from Service.(status == true).count(); // 示例2:只统计超过3秒的慢调用 slow_service_cpm = from Service.(latency > 3000).count(); // 示例3:只统计特定HTTP状态码的调用 http_500_cpm = from Service.(httpResponseStatusCode == 500).count(); // 示例4:过滤特定端点 user_login_cpm = from Endpoint.(name == "/api/user/login").count(); // 示例5:组合过滤条件 error_and_slow = from Service.(status == false && latency > 5000).count(); // 示例6:使用字符串匹配 api_endpoint_cpm = from Endpoint.(name like "/api/%").count(); // 示例7:排除健康检查端点 business_endpoint_cpm = from Endpoint.(name != "/health" && name != "/metrics").count();

Filter支持的操作符:

  • 比较:==,!=,>,<,>=,<=
  • 逻辑:&&,||
  • 字符串:like,not like
  • 算术:+,-,*,/

五、内置OAL文件解读

SkyWalking内置了几个OAL文件,覆盖了所有默认的APM指标。我们来拆解最重要的service.oal

// ============================================================// 文件名: oal/official_analysis.oal// 位置: oap-server/server-starter/src/main/resources///// 这是SkyWalking最核心的OAL文件// ============================================================// === 服务级别指标 ===// 1. 服务调用次数(每1分钟/小时/天)service_cpm=fromService.count();// 2. 服务平均响应时间service_resp_time=fromService.avg(latency);// 3. 服务成功率(status=true表示成功)service_sla=fromService.avg(status==true?100:0);// 4. 服务调用次数(累加)service_sum_call=fromService.sum(1);// 5. 服务P99/P95/P90/P75/P50分位响应时间service_percentile=fromService.percentile(latency,50,75,90,95,99);// 6. 服务响应时间直方图(4个桶: 0-500ms, 500-2000ms, 2000-5000ms, 5000+ms)service_resp_time_histogram=fromService.histogram(latency,500,2000,5000);// === 服务实例级别 ===// 7. 实列的调用次数service_instance_cpm=fromServiceInstance.count();// 8. 实例成功率service_instance_sla=fromServiceInstance.avg(status==true?100:0);// 9. 实例平均响应时间service_instance_resp_time=fromServiceInstance.avg(latency);// === 端点级别 ===// 10. 端点调用次数endpoint_cpm=fromEndpoint.count();// 11. 端点平均响应时间endpoint_avg=fromEndpoint.avg(latency);// 12. 端点成功率endpoint_sla=fromEndpoint.avg(status==true?100:0);// === 端点慢调用 ===// 13. 端点P99分位(用于识别慢端点)endpoint_percentile=fromEndpoint.percentile(latency,50,75,90,95,99);// === 关系级别指标 ===// 14. 服务间客户端调用次数service_relation_client_cpm=fromServiceRelation.count();// 15. 服务间服务端调用次数service_relation_server_cpm=fromServiceRelation.count();// 16. 服务间成功率service_relation_client_call_sla=fromServiceRelation.avg(status==true?100:0);// 17. 端点间调用次数endpoint_relation_cpm=fromEndpointRelation.count();// 18. 端点间成功率endpoint_relation_sla=fromEndpointRelation.avg(status==true?100:0);// === 慢服务和慢端点监测 ===// 19. 服务超过3秒的调用(慢调用监测)slow_service_call=fromService.(latency>3000).count();// 20. 端点超过3秒的调用slow_endpoint_call=fromEndpoint.(latency>3000).count();

六、高级语法特性

6.1 disable语句

当你不需要某个内置指标时,可以禁用它以节省计算和存储资源:

// 禁用不需要的指标 disable(service_instance_throughput); disable(endpoint_percentile); // 注意:disable语句必须在指标被定义之后 // 正确的顺序 endpoint_avg = from Endpoint.avg(latency); disable(endpoint_avg); // 放在定义之后

6.2 字符串匹配

// like 支持 % 通配符 api_calls = from Endpoint.(name like "/api/%").count(); // not like 排除 non_health_calls = from Endpoint.(name not like "/health/%").count();

6.3 多值聚合

// histogram需要指定分桶边界 // 格式:histogram(字段, 边界1, 边界2, 边界3, ...) response_histogram = from Service.histogram(latency, 100, // <= 100ms 500, // <= 500ms 2000, // <= 2000ms 10000 // <= 10000ms ); // > 10000ms 自动归入最后一个桶 // percentile可以指定任意分位点 custom_percentile = from Service.percentile(latency, 50, // P50 90, // P90 95, // P95 99, // P99 99.9 // P999 );

七、OAL语法速查卡

+=======================================================================+ | OAL 语法速查卡 | +=======================================================================+ | | | 【基本格式】 | | 指标名 = from 数据源.聚合函数(字段); | | 指标名 = from 数据源.(过滤).聚合函数(字段); | | | | 【常用聚合函数】 | | .avg(field) 平均值 | | .sum(field) 求和 | | .max(field) 最大值 | | .min(field) 最小值 | | .count() 计数 | | .p50/p75/p90/p95/p99(field) 分位数 | | .percentile(field, 50,90,95,99) 自定义分位 | | .histogram(field, 100,500,2000) 直方图分桶 | | | | 【Filter操作符】 | | == != > < >= <= | | && || like not like | | | | 【控制语句】 | | disable(指标名); 禁用指标 | | import 路径; 引入Source类 | | | +=======================================================================+ 图2:OAL语法速查卡——贴在显示器旁随时查阅

八、实战练习

试着写下以下场景的OAL定义:

Q1:统计支付接口(/api/payment)每分钟的错误次数

// 方法1:用Filterpayment_error_cpm=fromEndpoint.(name=="/api/payment"&&status==false).count();// 方法2:用成功率反推(100-SLA得到错误率)payment_sla=fromEndpoint.(name=="/api/payment").avg(status==true?100:0);

Q2:统计超过5秒的"超慢"调用数量

super_slow_calls=fromService.(latency>5000).count();

Q3:按服务统计不同响应时间段的分布(直方图)

service_latency_distribution=fromService.histogram(latency,10,// <= 10ms (极快)50,// <= 50ms200,// <= 200ms1000,// <= 1s3000// <= 3s);// > 3s (慢调用)

九、总结

OAL的语法设计体现了"少即是多"的哲学。它只有一种语句格式、十几个聚合函数、几个操作符——但能拼出几乎所有APM指标计算的需求。

关键要点:

  • 数据源(Source)+ 聚合函数 + Filter = 完整的指标定义
  • Filter是可选的"安检门",用Java语法风格过滤数据
  • 分位数函数(p50-p99)开销高于平均/求和,按需使用
  • disable语句可以关闭不需要的内置指标
  • 内置OAL文件是学习的最佳范本

下一篇,我们将深入OAL的编译器实现原理,揭开Antlr4语法解析和Java字节码生成的奥秘。


上一篇【第41篇】OAL是什么:观察力分析语言的前世今生
下一篇【第43篇】OAL实现原理:从脚本到字节码的魔法之旅


需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询