日志检索长期停留在关键词和正则匹配,复杂查询只能写脚本。炬鲸 OBSERVE 把日志当表、字段当列,用 SQL 完成过滤、聚合与跨服务关联,本文拆解其数据模型与性能取舍。
过去的日志工具基本是两种用法:要么关键词搜索,要么正则。查“某个用户下单失败”要先翻 trace,再拿 trace_id 去 grep,最后人肉对时间线。条件一多就退化成一串正则,跨字段关联基本靠复制粘贴。问题不在工具“不够智能”,而在数据模型:日志被当成一行文本,字段只在展示层存在,查询层根本不认识它。
炬鲸 OBSERVE 的检索引擎从数据模型入手,把一条日志解析成若干字段,字段即列,日志即行,时间戳是隐式排序键。于是查询变成标准的 SQL:
SELECT service, status, COUNT(*)
FROM logs
WHERE level = 'error'
AND ts > now() - INTERVAL '1 hour'
GROUP BY service, status
ORDER BY COUNT(*) DESC;
字段来自采集端的结构化解析(JSON、key=value、正则提取),也支持运行时用 json_extract 从 message 里按需取。也就是说,不用预先定义 schema,也不用写索引配置,直接写 SQL 就能查。
跨服务关联:一条慢请求会跨十几个服务。过去要按 trace_id 手动串,现在直接 JOIN:
SELECT a.service, b.service, b.duration
FROM logs a JOIN logs b ON a.trace_id = b.trace_id
WHERE a.service = 'gateway' AND b.duration > 1000;
聚合找规律:5xx 到底是哪个接口、哪个机房、哪个版本引起的,一个 GROUP BY 就能定位,不用导出到 Excel。
告警前置查询:告警规则可以直接写 SQL,命中即触发。查询逻辑和告警逻辑用同一套表达,避免“告警配一套、排查又写一套”的割裂。
把 SQL 直接跑在原始日志上当然不现实。引擎做了三层处理:一是按时间 + 服务 + 字段哈希做分区,把扫描范围压到最小;二是对高频字段自动建倒排索引,等值过滤走索引;三是聚合下推到存储层,COUNT/SUM 不把明细拉回内存。实测 30 亿行日志上,带索引的等值过滤在 200ms 内返回,无索引的全表聚合控制在 3 秒内。代价是写入时多一次字段抽取,我们把它做成采集端流式完成,对吞吐影响不到 5%。
不是所有查询都该上 SQL。单关键词、模糊匹配、快速翻页看上下文,关键词检索更快更顺手。SQL 适合三类场景:跨字段组合条件、聚合统计、跨服务关联。我们的建议是:日常看日志用关键词,定位问题时切到 SQL,两者共用同一套字段模型,切换零成本。
如果你们正在选日志方案,优先看三点:查询是不是结构化(SQL 或类 SQL)、聚合是否下推、能不能和链路/指标共享一套字段。这三点决定了排查效率的上限,而不是界面上有多少个图表。