← 返回文章列表
使用指南 4 分钟阅读 炬鲸团队

从 ELK 到 SQL 式日志检索:一条语句跨集群查日志

很多团队同时维护 Elasticsearch、ClickHouse 与对象存储三套日志后端,检索语法互不兼容。本文演示炬鲸 OBSERVE 用同一条 SQL 式查询跨集群命中日志、按 host 聚合、定位慢接口,并给出三种后端切换时的迁移检查清单。

问题:三套后端,三套语法

日志团队常见的现状是:实时检索放 Elasticsearch,冷数据归档到 ClickHouse 做分析,超长期留存丢进对象存储压成本。三套系统三套查询语法——Lucene 的 query_string、ClickHouse 的 SQL 方言、对象存储上的 grep 或 Presto。排查一次线上问题,要在三个界面里来回切换,同一个条件写三遍。

炬鲸 OBSERVE 把这三层统一成一套 SQL 式检索语法。你在搜索框里写 status >= 500 AND host = 'api-gw-01',引擎会根据数据所在的后端自动翻译成对应的底层查询,返回结果对上层无感。

基础语法

# 字段过滤
level = 'ERROR' AND service = 'order'

# 范围与 IN
elapsed > 2000 AND host IN ('api-01','api-02')

# 通配与正则
path LIKE '/api/order/%'
message REGEXP 'OutOfMemory|OOM'

# 排序与分页
ORDER BY timestamp DESC LIMIT 100

字段名来自结构化日志的 JSON key。如果你的应用还在打纯文本日志,先在采集端配一条 parse 规则把 timestamplevelhostservicepath 抽出来,检索体验会立刻上一个台阶。

跨集群聚合

单条查询只能看明细,定位瓶颈要靠聚合。下面这条按 host 统计 5xx 数量:

SELECT host, COUNT(*) AS cnt
FROM logs
WHERE status >= 500 AND time >= now() - 1h
GROUP BY host
ORDER BY cnt DESC

嵌套聚合同样可用。定位「哪个接口最慢」:

SELECT path,
       COUNT(*) AS calls,
       AVG(elapsed) AS avg_ms,
       P95(elapsed) AS p95_ms
FROM logs
WHERE service = 'gateway' AND time >= now() - 30m
GROUP BY path
HAVING p95_ms > 1000
ORDER BY p95_ms DESC

引擎把 P95 这类分位数函数下推到底层:ClickHouse 走 quantile(0.95),Elasticsearch 走 percentiles 聚合,不需要你在客户端拉全量数据再自己算。

三种后端的切换成本

迁移时最大的坑是「语法兼容」而非数据搬移。给你一份检查清单:

  1. 字段类型:ES 的动态映射会把数字识别成 long,ClickHouse 要显式建表;迁移前先对齐 elapsedstatus 这类数值字段类型,避免聚合时类型报错。
  2. 分词差异:ES 默认 analyzer 和 ClickHouse 的 tokenbf 索引行为不同,LIKE '%xxx%' 的召回率要重新验证。
  3. 时间分片:按天建索引/分区是双方共识,但时区要统一成 UTC,否则跨天查询会漏数据。
  4. 保留策略:冷热分层(hot ES → warm ClickHouse → cold S3)的 TTL 要在路由层配好,别在存储层重复删数据。

实践建议

  • 先给高频排查路径建查询模板:登录接口 5xx、某服务错误日志、慢接口 Top10,存成保存的查询,值班同学点一下就有结果。
  • 检索条件里永远带上时间范围,无范围的全表扫描是集群被打爆的头号原因。
  • 聚合查询设 HAVING 而非客户端二次过滤,把算力留在服务端。

把语法统一之后,值班同学从「记得住三种语法」里解放出来,排查时间通常能砍掉一半以上。