阿里云云原生挑战官方用例SPL

GetPatternsAnalyzer

sql 复制代码
# 定义一个叫做t0的临时表格
with t0 as (
    # 从原始日志表log中选择spanName和ServiceName两个字段
    select spanName, serviceName, 
    	# 
    	# JSON_EXTRACT_SCALAR 是 SPL 内置函数,用于从 JSON 字符串中提取标量值
    	# 路径 '$["k8s.pod.ip"]' 表示访问 JSON 对象中键为 "k8s.pod.ip" 的值
    	# 提取结果命名为 pod_ip
           JSON_EXTRACT_SCALAR(resources, '$["k8s.pod.ip"]') AS pod_ip,
           JSON_EXTRACT_SCALAR(resources, '$["k8s.node.name"]') AS node_name,
           JSON_EXTRACT_SCALAR(resources, '$["service.version"]') AS service_version, 
    	# 设置异常标签
           if((statusCode = 2 or statusCode = 3), 'true', 'false') as anomaly_label, 
    	# 使用if判断 statusCode 是否为 2 或 3。如果是,返回 1;否则返回 0。
		# 然后使用 cast(... as double) 将整数转为双精度浮点数。
    	# 实际返回是否出错的数值表示 0或者1
           cast(if((statusCode = 2 or statusCode = 3), 1, 0) as double) as error_count 
    from log 
    # 设置占位符 实际使用时将被替换成具体的执行添加
    # 在当前案例中的是上一个阶段生成的根因span条件
    where {self.condition}
),

假设输出的t0结构如此

spanName serviceName pod_ip node_name service_version anomaly_label error_count
"/login" "auth-service" "10.1.2.3" "node-a" "v1.2.0" "false" 0.0
"/getProfile" "user-service" "10.1.2.4" "node-b" "v2.0.1" "true" 1.0
"/login" "auth-service" "10.1.2.5" "node-a" "v1.2.0" "false" 0.0
sql 复制代码
# array_agg(column) 是 SPL(以及标准 SQL)中的聚合函数,用于将某一列的所有值收集到一个数组(list)中。
t1 as (
    select array_agg(spanName) as spanName, 
           array_agg(serviceName) as serviceName, 
           array_agg(pod_ip) as pod_ip, 
           array_agg(node_name) as node_name, 
           array_agg(service_version) as service_version, 
           array_agg(anomaly_label) as anomaly_label, 
           array_agg(error_count) as error_count 
    from t0
),
# 执行后,t1 只有一行,包含 7 个字段,每个字段都是一个数组,数组长度等于 t0 的行数
# 目前来看 t1保留了很多的字段 但是只使用了spanName 和 serviceName 可能是为后续进行了一些保留
json 复制代码
# t1
{
  "spanName": ["/login", "/getProfile", "/login"],
  "serviceName": ["auth-service", "user-service", "auth-service"],
  "pod_ip": ["10.1.2.3", "10.1.2.4", "10.1.2.5"],
  "node_name": ["node-a", "node-b", "node-a"],
  "service_version": ["v1.2.0", "v2.0.1", "v1.2.0"],
  "anomaly_label": ["false", "true", "false"],
  "error_count": [0.0, 1.0, 0.0]
}
sql 复制代码
# 将 t1 中的 spanName 和 serviceName 两个数组字段封装成一个结构化的行对象,便于作为整体传递给后续处理逻辑(如自定义函数),强调这两个字段的逻辑关联性。
t2 as (
    # row( ) 是一个用于构造结构化复合数据类型的函数,它返回一个 ROW 类型(也称为"行类型"或"结构体")的对象。 
    select row(spanName, serviceName) as table_row 
    from t1
),
# 返回一个 ROW(ARRAY<STRING>, ARRAY<STRING>) 类型的值
# 一个包含两个元素的结构体;第一个元素是 spanName 数组;第二个元素是 serviceName 数组
# 如果没有显式指定名称,SPL 会默认使用 col0, col1, col2, ... 作为内部字段名。
# table_row.col0 → 对应 spanName
# table_row.col1 → 对应 serviceName
json 复制代码
# t2
{
  "table_row": {
    "col0": ["/login", "/getProfile", "/login"],
    "col1": ["auth-service", "user-service", "auth-service"]
  }
}
sql 复制代码
# get_patterns用于从 trace 数据中提取高频或异常的调用序列模式
# table_row是上面的数组 ARRAY['spanName', 'serviceName'] 指明 col0 代表 spanName col1 代表 serviceName
t3 as (
    select get_patterns(table_row, ARRAY['spanName', 'serviceName']) as ret 
    from t2
)
select * from t3
# 该函数将统计所有(spanName,serviceName)的组合 
json 复制代码
# 某题实际的响应内容如下
{'ret': '[["serviceName=payment"],[118],null,null]'}

DiffPatternsAnalyzer

sql 复制代码
# 进行原始日志过滤以及字段的提取 大部分内容同上
with t0 as (
    select 
        spanName, 
        serviceName, 
        JSON_EXTRACT_SCALAR(resources, '$["k8s.pod.ip"]') AS pod_ip,
        JSON_EXTRACT_SCALAR(resources, '$["k8s.node.name"]') AS node_name,
        JSON_EXTRACT_SCALAR(resources, '$["service.version"]') AS service_version, 
        # 根据上面给出的根因span进行标记
        if(({self.condition}), 'true', 'false') as anomaly_label, 
        cast(if((statusCode = 2 or statusCode = 3), 1, 0) as double) as error_count 
    from log 
    where statusCode > 0
)
sql 复制代码
# 将 t0 中所有行的每个字段聚合成一个数组 同上
t1 as (
    select 
        array_agg(spanName) as spanName, 
        array_agg(serviceName) as serviceName, 
        array_agg(pod_ip) as pod_ip, 
        array_agg(node_name) as node_name, 
        array_agg(service_version) as service_version, 
        array_agg(anomaly_label) as anomaly_label, 
        array_agg(error_count) as error_count 
    from t0
)
sql 复制代码
# 只关心服务与是否异常的关联性 同上
t2 as (
    select row(serviceName, anomaly_label) as table_row 
    from t1
)
sql 复制代码
t3 as (
    select diff_patterns(
        table_row,	-- 包含维度字段和标签字段的 ROW 对象
        ARRAY['serviceName', 'anomaly_label'],	-- 字段名映射数组
        'anomaly_label',	-- 用于分组的标签列,用于划分正常数组和异常数组
        'true',	 -- 正样本标签值
        'false'	 -- 负样本标签值	
    ) as ret 
    from t2
)

diff_patterns 函数首先会对输入的所有记录按照异常标签(anomaly_label)进行分组:将 anomaly_label = 'true' 的记录划分为"异常组"(Group A),anomaly_label = 'false' 的记录划分为"正常组"(Group B),并分别提取两组中对应的 serviceName 值。

接着,函数会统计每个服务名称在异常组和正常组中的出现频次,例如某个服务如 payment-service 可能在异常组中出现了 200 次,而在正常组中仅出现 50 次,而另一个服务如 auth-service 可能在异常组中出现 50 次,却在正常组中出现 1000 次。

基于这些频次数据,函数进一步计算关键的差异指标,包括提升度(Lift,即异常组中该服务的占比除以正常组中的占比)、差异比例(Diff Ratio)以及统计显著性(如 p-value),用以量化每个服务与异常行为的关联强度。最后,函数会根据这些指标(通常是 Lift 或显著性)对服务进行排序,并返回最显著的差异模式列表,从而帮助用户快速识别出与异常高度相关的核心服务。

具体内容详见差异模式挖掘函数diff_patterns通过分析表格数据的维度和指标差异,识别测试组与对照组之间的显著模式,适用于云数据诊断与分析。

LogPatternAnalyzer

stage1

sql 复制代码
# t1:聚合所有日志消息为一个数组
with t0 as (
  select 
    statusCode,	# 状态码 
    statusMessage,# 错误信息描述 
    serviceName,# 服务名
    # 拼接出一个人工日志文本 如[serviceName] statusMessage
    CONCAT('[', serviceName, '] ', statusMessage) as combined_message 
  from log 
  # 对根因节点列表中状态码大于0的部分进行检索
  where {self.condition} and statusCode > 0
)
sql 复制代码
# 聚合所有日志消息为一个数组
t1 as (
  select array_agg(combined_message) as contents
  from t0
)
复制代码
# 模拟结果
[
  "[auth-service] Invalid token",
  "[user-service] User not found: id=123",
  "[user-service] User not found: id=456",
  ...
]
sql 复制代码
# 调用日志发现函数
t2 as (
  select 
    contents,
    get_log_patterns(
      contents, -- 日志行数组
      ARRAY[' ', '\\n', '\\t', '\\r', '\\f', '\\v', ':', ',', '[', ']'], -- 分词分隔符列表
      null, -- 时间格式(null 表示不解析时间)
      null, -- 正则过滤(null 表示不过滤)
      '{"threshold": 3, "tolerance": 0.3, "maxDigitRatio": 0.3}'-- JSON 字符串,控制聚类参数
        # "threshold": 3 最小支持度 一个模式至少出现 3 次才被视为有效模板
        # "tolerance": 0.3 容错率 允许 30% 的 token 差异仍归为同一模式(用于模糊匹配)
        # "maxDigitRatio": 0.3 若一行日志中数字字符占比 > 30%,可能被过滤或特殊处理(避免纯 ID 日志干扰)
    ) as ret 
  from t1
)
sql 复制代码
# 提取所需的关键结果 只要模式id和对应的错误信息(可以去阿里云文档看看get_log_patterns的返回内容)
select 
  ret.model_id as model_id,
  ret.error_msg as error_msg
from t2

stage2

sql 复制代码
# 效果同上
with t0 as (
    select CONCAT('[', serviceName, '] ', statusMessage) as combined_message
    from log
    where {self.condition} and statusCode > 0
)
sql 复制代码
# 调用match_log_patterns
# 使用指定的模型(model_id)对单条日志(log_line)进行解析,判断是否匹配已知模式,并返回结构化结果。
select match_log_patterns('{model_id}', combined_message) as ret, combined_message 
from t0
sql 复制代码
# 外层循环 筛选并输出结构化结果
select 
    ret.is_matched as is_matched,
    ret.pattern_id as pattern_id,
    ret.pattern as pattern,
    ret.regexp as pattern_regexp,
    ret.variables as variables,
    combined_message as content
from (
    ... -- 上述子查询
) 
where ret.is_matched = true
limit 1000
相关推荐
hello_25010 小时前
k8s安全机制解析:RBAC、Service Account与安全上下文
java·安全·kubernetes
JanelSirry10 小时前
VMware+RockyLinux+ikuai+docker+cri-docker+k8s 自用 实践笔记(一)
linux·docker·kubernetes
Misnice10 小时前
k8s 常用命令
linux·docker·kubernetes
NanXi_XZ11 小时前
kubernetes事件监控工具--Kube-Event
python·kubernetes
斯普信专业组14 小时前
Kubernetes(K8S)完全详解:从架构设计到云原生实践
云原生·容器·kubernetes
能不能别报错15 小时前
K8s学习笔记(四) etcd组件
笔记·学习·kubernetes
白-胖-子16 小时前
阿里云 “封神” 组件:云平台监控告警的智能中枢
阿里云·云计算·阿里云封神
能不能别报错17 小时前
kubeasz二进制部署k8s生产环境集群
云原生·容器·kubernetes
qq_5693841217 小时前
Jenkins(速通版)
java·kubernetes·jenkins