全文检索在日志量上来后就不好使了:没法聚合、没法过滤、没法跨字段关联。本文介绍炬鲸 OBSERVE 的 SQL 风格日志检索,给出常用查询写法、与全文检索的配合方式,以及让十亿级日志秒级聚合的索引实践。
全文检索(关键词模糊匹配)在日志量小时够用,一旦日志量上到每天几十亿条、上百台机器,问题就暴露了:无法聚合、无法做条件过滤、无法跨字段关联。比如"过去 5 分钟 502 错误按上游服务分组、取 Top 10"这种诉求,纯全文检索要么写正则,要么导出到别处二次处理。
炬鲸 OBSERVE 把日志检索做成 SQL 语义。底层是列式存储加向量化执行引擎,日志字段(时间、级别、trace_id、pod、状态码)先做类型化,再用 SQL 查询。运维不需要学新的 DSL,会写数据库查询就能上手。因为是真正的 SQL 语义,交互式查询可以原样保存成告警条件或大屏面板,不用重写。
几个高频场景的写法:
按状态码聚合错误:
SELECT status, count(*) AS cnt
FROM logs
WHERE status >= 500
AND time >= now() - interval '5 minute'
GROUP BY status
ORDER BY cnt DESC
按上游服务定位慢请求:
SELECT service, p95(latency) AS p95
FROM logs
WHERE time >= now() - interval '1 hour'
GROUP BY service
HAVING p95 > 500
关联 trace 查看完整链路:
SELECT trace_id, span_id, message
FROM logs
WHERE trace_id = 'e4f2...'
ORDER BY time
用共享字段把访问日志和应用日志 join 起来:
SELECT a.request_id, a.status, b.message
FROM access_logs a
LEFT JOIN app_logs b
ON a.request_id = b.request_id
WHERE a.status >= 500
AND a.time >= now() - interval '10 minute'
这些查询可以直接在控制台执行,也能保存为告警条件定时执行。最后这条 join 是全文检索做不到的——把两条日志流按字段关联起来,正是关系模型的价值所在。
全文检索的优势是"我不知道字段名,只想搜个关键词"。SQL 的优势是"我知道要算什么"。实际定位问题时两者是配合关系,不是二选一:
一个反例:用纯关键词排查"哪些接口 P99 超过 1 秒",需要把日志全量拉下来自己算,SQL 一条语句就出结果。反过来,如果连字段长什么样都不知道,先全文搜一把再转 SQL 会更顺。
SQL 快的前提是字段有类型、有索引。几条实践建议:
按照这些习惯,十亿级日志的秒级聚合是稳定可达的。我们在现场最常见的坑,是把日志当文本档案存,然后抱怨跨字段 join 慢——字段类型化、过滤列建索引,同一份数据立刻就快起来了。