上一篇(第 07 篇)展示了 Lens 的智能推断路径,覆盖了大多数通用可视化场景。本篇回答的问题是:当 Lens 的标准化模型不够用时,有哪些替代工具可用;这些工具在时序查询和自定义渲染上各自的边界在哪里;何时该选 TSVB,何时该用 Vega 直接接管数据与渲染。

三种工具的定位

1
2
3
4
Lens         通用推断型编辑器,覆盖大多数可视化场景,推荐首选
TSVB 专为时序设计,多 panel 类型,支持 series 级聚合组合
Timelion 时序表达式语言(已弃用),以 .es() 函数链为核心
Vega 全自定义逃生舱,直接接管数据获取 + 图形渲染

这不是平行关系,而是"覆盖范围递增、配置复杂度也递增"的梯度。绝大多数场景从 Lens 开始即可;只有 Lens 的 layer 模型或标准图表类型无法满足时,才向 TSVB 或 Vega 下沉。

TSVB:时序可视化构建器

TSVB(Time Series Visual Builder)是一个以时序分析为核心的面板编辑器。它最直接的特征是支持多种 panel 类型:

1
2
3
4
5
6
7
8
TSVB 面板类型:

Time Series 折线 / 柱状 / 面积,多 series 叠加
Metric 单一时间点的当前值,通常用于仪表盘大数字展示
Top N 按某一 metric 排名的水平柱状条
Gauge 圆形仪表,显示当前值相对阈值的位置
Table 行列聚合结果,支持按 metric 排序
Markdown 纯 Markdown 内容,可内嵌模板变量(取自聚合结果)

每个 series 可以独立配置聚合管道,这是 TSVB 区别于 Lens 的核心能力:

1
2
3
4
5
6
7
8
9
10
TSVB series 聚合管道示例:

series A:
bucket: date_histogram(interval: 1m)
pipeline agg 1: moving average(window: 5)
pipeline agg 2: positive only(clip negatives to 0)

series B(同一图,不同聚合):
bucket: date_histogram(interval: 1m)
metric: max(field: response_time)

Lens 的 formula 也可以表达移动平均,但 TSVB 的 pipeline 组合是可视化的下拉配置,在需要多个 pipeline 连接的复杂时序场景下,交互更直观。TSVB 还支持 panel 级别的 offset(往前偏移一个时间周期做环比),这在 Lens 8.x 中也有支持,但 TSVB 是更早且成熟的实现。

TSVB 的注解(Annotations)功能允许把另一个索引的 event 时间戳画成竖线叠加到时序图上,这在告警事件和 metric 变化的关联分析中常用。

TSVB 的局限

TSVB 的编辑界面针对时序深度定制,但这也导致它无法像 Lens 那样在不同图表类型之间保留配置。配置的可读性和可迁移性低于 Lens 的 JSON 状态。Kibana 官方文档(8.x 起)明确标注 TSVB 部分功能正在向 Lens 收敛,长期维护重心在 Lens。

Timelion:时序表达式语言(弃用)

Timelion 是 Kibana 早期引入的一套时序查询 DSL,以表达式链的方式描述时序操作:

1
2
3
4
5
6
7
8
9
10
Timelion 表达式示例(语法仅供历史参考):

.es(index=logstash-*, metric=avg:response_time)
.movingaverage(window=5)
.label('5m 移动平均')

.es(q='status:error').divide(.es()).multiply(100)
.label('错误率 %')

.quandl() # 外部时序数据源(Timelion 独有特性)

.es() 函数向 Elasticsearch 发一个聚合查询;其他函数(.movingaverage().divide().multiply())是 Timelion 在 server 端对时序结果做的后处理,不发给 ES。这意味着 Timelion 的部分计算发生在 Kibana server 而非 ES 侧,与 Lens formula 把管道聚合下推到 ES 的方式不同。

Timelion 在 Kibana 7.x 起就被标注为弃用,8.x 中仍存在但不再开发新功能。现存 Timelion 表达式可以通过 Kibana 提供的迁移助手转换为 Lens 公式。本篇不对 Timelion 语法做完整说明,仅保留其历史定位以便理解 TSVB 和 Lens 出现的背景。

Vega:全自定义逃生舱

Vega 和 Vega-Lite 是两个独立的开源可视化 grammar(由 UW Interactive Data Lab 开发),Kibana 把它们作为"当标准可视化类型都不够用时"的逃生舱内置进来。

Vega 在 Kibana 里的位置

1
2
3
4
5
6
7
8
9
10
11
12
13
标准 Kibana 可视化路径:

Lens → ES 聚合查询 → Kibana 渲染层(EUI Charts)

Vega 路径:

Vega spec(JSON)→ Kibana Vega 插件(解析)→ Vega runtime

Vega 内置的 data 节点:
→ 通过 url.index + url.body 直接向 ES 发请求(绕过 Kibana query pipeline)
→ 或从 spec 里的 values 数组读取静态数据

Vega runtime 渲染 SVG / Canvas(绕过 Kibana 渲染层)

Vega 绕过了两层:一是 Kibana 的查询流水线(Search Source、Data Plugin),改为在 spec 里直接指定 ES 的 index 和 request body;二是 Kibana 的图表渲染层(EUI Charts),改为由 Vega runtime 直接输出 SVG 或 Canvas。

Vega-Lite 最小示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {
"url": {
"%context%": true,
"%timefield%": "@timestamp",
"index": "my-logs-*",
"body": {
"size": 0,
"aggs": {
"over_time": {
"date_histogram": {
"field": "@timestamp",
"calendar_interval": "1h"
},
"aggs": {
"avg_bytes": { "avg": { "field": "bytes" } }
}
}
}
}
},
"format": {
"type": "json",
"property": "aggregations.over_time.buckets"
}
},
"mark": "line",
"encoding": {
"x": { "field": "key_as_string", "type": "temporal" },
"y": { "field": "avg_bytes.value", "type": "quantitative" }
}
}

%context% 是 Kibana 注入的占位符,表示把当前 Dashboard 的时间过滤和查询上下文透传到这个 ES 请求里。没有这个占位符,Vega 的 ES 请求就完全独立于 Dashboard 的全局过滤,这既是 Vega 灵活性的来源,也是容易产生歧义的地方。

何时下沉到 Vega

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
应该用 Lens 的情况:
- 标准图表类型满足需求
- 需要 Dashboard filter 联动
- 需要 Saved Object 方式保存和共享

应该用 Vega 的情况:
- 渲染逻辑超出 Kibana 标准图表(自定义连线、树状图、桑基图、网络图)
- 需要静态或外部数据与 ES 数据混合渲染
- 需要精确控制每个视觉元素的位置、颜色、交互
- 需要 Vega 的 signal 机制做图内交互(悬浮、选择、缩放)

Vega 的代价:
- spec 是 JSON,复杂图表的 spec 可达几百行
- 调试困难:错误提示不如 Lens 直观
- 维护成本高:Kibana 版本升级后 spec 语法可能需要调整
- 绕过 Query pipeline 后,filter、time picker 的联动需要手动处理

实验:TSVB 注解 + Vega-Lite 直查

实验分两部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Part 1 — TSVB 多 series + 注解:

1. 创建 TSVB 面板,Time Series 类型
2. 添加两个 series:
- series A:avg(response_time),聚合间隔 1m
- series B:moving average(avg(response_time)),window=5
3. 在 Annotations 标签页添加一条注解:
- 指向一个包含 deployment_event 的索引
- 时间字段选 @timestamp,标签字段选 event_name
4. 观察主时序图上出现竖线标记,记录竖线与 spike 的位置关系

Part 2 — Vega-Lite 绕过 Query pipeline:

1. 创建 Vega 面板,粘入上面的 Vega-Lite 最小示例
2. 修改 %context% 为 false,固定 gte/lte 时间范围
3. 观察 Dashboard 时间选择器变化时,Vega 面板不跟随刷新
4. 将 %context% 改回 true,再次改变时间选择器,确认 Vega 面板跟随
5. 打开浏览器 DevTools → Network,对比有无 %context% 时 Vega 发出的 ES 请求 body

模式提炼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
模式:可视化工具梯度选择

核心原则:
能在 Lens 里完成的不要去 TSVB,能在 TSVB 里完成的不要去 Vega
每下沉一层,灵活性增加但可维护性降低

TSVB 的价值边界:
- 多个独立 pipeline 聚合叠加在同一时序图
- 跨索引事件注解覆盖
- panel 级别的时间偏移(环比)

Vega 的价值边界:
- 标准图表无法表达的拓扑结构
- 混合数据源(ES + 静态 + 外部 API)
- 需要精确的视觉控制

逃生舱原则:
逃生舱的存在是为了让工程师不受标准路径束缚,
但每次使用都是在以长期维护成本换取短期表达能力。
决策前先问:这个需求是否可以通过改 Lens formula 或数据预处理解决?

工程迁移表

Kibana 概念 Grafana 对应 Jupyter / Observable 对应 自研 BI 对应
TSVB 多 series + pipeline Grafana Time Series + Transforms Matplotlib 多 subplot 自定义时序 widget
TSVB Annotations Grafana Annotations(事件叠加) Matplotlib axvline 事件时间线叠加
Timelion 表达式(弃用) Grafana 旧版 Graph + series override 无直接对应
Vega spec(内嵌 ES 查询) Grafana Custom Panel Plugin Observable notebook cell 自定义 D3.js widget
%context% 占位符(Dashboard 联动) $__timeFilter 变量注入 无(手动传参) Context 参数注入
Vega signal(图内交互) Grafana Panel link + drill-down ipywidgets 回调 自定义 DOM 事件

常见误解

误解一:“TSVB 就是功能更强的 Lens 时序模式”。TSVB 和 Lens 是并列的编辑器,各自有独立的配置模型。TSVB 的 pipeline 配置不能直接迁移到 Lens,反之亦然。官方推荐方向是逐步迁移到 Lens,但迁移需要手工重建配置,不是自动转换。

误解二:“Vega 可以访问任意外部 HTTP 接口”。Kibana 默认限制 Vega 只能向自身代理的 ES 端点发请求,出于安全策略,直接向外部域名发请求会被 CSP(Content Security Policy)阻止。若需要外部数据,通常需要管理员在 kibana.yml 里配置 vis_type_vega.enableExternalUrls: true,这是一个非默认安全设置。

误解三:“Timelion 和 Lens formula 是同一套引擎”。Timelion 的计算(.movingaverage().divide() 等)在 Kibana server 侧执行,结果是 server 内存里的时序数组操作。Lens formula 把表达式编译为 ES 管道聚合(bucket_scriptmoving_avg 等),计算在 ES 节点上发生。两者的执行位置、性能特征、精度语义都不同。

误解四:“TSVB 的 Markdown panel 只能放静态文本”。Markdown panel 支持 Handlebars 模板语法,可以把聚合结果(当前值、最大值等)嵌入文本。这使得 Markdown panel 实际上是一个 "metric + 文字说明"的混合展示形式,而不是纯静态内容。

练习

  1. 用 TSVB 建一个 Gauge 面板,显示最近 15 分钟的错误率(errors / total_requests * 100)。配置三段颜色阈值(绿色 < 5%,黄色 5%-10%,红色 > 10%)。理解 TSVB 在 Gauge 场景下是否仍然发送 date_histogram 聚合,还是改为单值聚合。

  2. 编写一个 Vega-Lite spec,同时展示两个独立索引的时序数据(一个是 metrics 索引,一个是 events 索引),在同一坐标轴上用不同颜色区分。验证 Kibana 对两个 data 节点各自发出两个独立的 ES 请求。

  3. 思考题:如果团队中有一张 TSVB 面板使用了移动平均 + 跨索引注解,需要迁移到 Lens,列出所有需要手工重建的配置项,并判断哪些在 Lens 8.x 中有等价功能,哪些目前没有。

系列导航

序号 主题 状态
00 导读:Kibana 的状态存在 Elasticsearch 里
01 Kibana 架构:浏览器、Node.js server 与 New Platform
02 Saved Object:Kibana 一切状态的统一模型
03 Data View(Index Pattern):查询之前的字段抽象
04 Search Source 与查询翻译:KQL、Lucene 与 Query DSL
05 Discover:一次查询的完整执行路径
06 Visualize:手动聚合配置的模型
07 Lens:拖拽背后的自动聚合推断
08 TSVB、Timelion 与 Vega:时序与自定义可视化 本篇
09 Dashboard 与 Embeddable:面板的组合与依赖 下一篇
10 Alerting 框架:Rule、Connector 与 Action
11 Reporting:从 Dashboard 到 PDF/PNG
12 Task Manager:分布式任务调度
13 Spaces 与安全:RBAC、Feature Controls
14 插件体系:New Platform 的 setup/start 生命周期
15 性能模型:bundle、bootstrap 与异步搜索会话
16 Kibana vs Grafana:两种可视化平台的设计取舍
17 演进:从纯前端到 New Platform 再到 Serverless

参考资料