深入 Kibana 09 - Dashboard 与 Embeddable:面板的组合与依赖
上一篇(第 08 篇)补全了可视化类型的全貌:Lens 覆盖通用场景,TSVB 专注时序,Vega 作为全自定义逃生舱。本篇回答的问题是:这些可视化如何被组合到一个 Dashboard 里;面板之间如何共享过滤状态;Dashboard Saved Object 的结构如何用 references 管理对可视化对象的依赖;URL 里的 rison 编码存了什么。
Embeddable 框架:任意内容的统一容器契约
Dashboard 不是一个专门为可视化设计的容器,它是 Embeddable 框架的消费者。
1 | |
这意味着 Dashboard 里的"面板"不只是 Lens 可视化,也可以是地图(Maps 插件)、Saved Search(来自 Discover)、Controls(过滤器控件)、任何通过 EmbeddableFactory 注册的类型。Embeddable 框架是 Kibana New Platform 插件体系的一个具体应用:Dashboard 对面板的内容一无所知,只负责把输入传进去、提供容器、接收输出。
面板间的 filter 联动
Dashboard 的过滤状态存在一个全局的 FilterManager 和 QueryService 里。
1 | |
这个机制是 Dashboard 面板联动的核心:所有面板共享同一份 filter / query / time range 状态,任何一个面板改变这个状态,其他所有面板都会重新查询。这不是面板之间点对点通信,而是发布-订阅模型——面板不知道也不需要知道"谁改了过滤"。
Drilldown(钻取)是另一个维度的联动:点击面板里的某个数据点,跳转到另一个 Dashboard 或 URL,并把当前的过滤上下文带过去。这是在 filter 联动之上的导航层。
Dashboard Saved Object 结构
1 | |
panelsJSON 里的每个面板用 panelRefName 字段指向 references 数组里的一条记录。这是 Kibana Saved Object 引用图的标准做法:不在 attributes 里硬写 ID,而是在 references 数组里集中声明,让 Kibana 的引用追踪机制能正确处理导出/导入/迁移时的 ID 替换。
导出 Dashboard 时,Kibana 沿着 references 递归把所有依赖的 visualization、lens、search、index-pattern 一起打包。这就是为什么"导出 Dashboard"的文件体积通常比"Dashboard 自身"大得多——它实际上是整个依赖子图的序列化。
URL 状态与 rison 编码
打开一个 Dashboard 时,URL 里通常有两个关键参数:
1 | |
rison 是一种比标准 JSON 更紧凑的 URL 可读格式(RISON),把 JSON 的花括号/方括号/引号做了简化,使得复杂的过滤条件可以放在 URL 里而不至于过于冗长。Kibana 使用 rison 库在 JavaScript 侧序列化和反序列化这两个参数。
URL 状态机制的实际影响:可以通过拼接带特定 _g 参数的 URL 来预设过滤条件分享给其他人;_g 状态在 Kibana 不同 app(Discover、Dashboard)之间跳转时保留,这就是为什么从 Dashboard 跳到 Discover 后,时间范围还是原来的。
实验:观察 Dashboard 的依赖图和 URL 变化
1 | |
将实验结果映射到内部对象
1 | |
Dashboard 的 View-Only 模式
Kibana 支持 Dashboard-only 模式(通过 Spaces 的 Feature Controls 或 URL 参数 embed=true)。在这个模式下,面板仍然可以接收 filter(通过 URL _g/_a 参数预设),但不显示编辑工具栏,适合嵌入外部系统(iframe 嵌入)或分发给只读用户。
embed=true 参数还会隐藏 Kibana 的顶部导航栏,只渲染 Dashboard 内容区域,常用于把 Kibana Dashboard 嵌入到内部运维平台或报表系统的页面里。
模式提炼
1 | |
工程迁移表
| Kibana 概念 | Grafana 对应 | React 应用对应 | 微前端对应 |
|---|---|---|---|
| Embeddable 框架(type → factory → render) | Panel Plugin 注册 | React Context + 动态组件 | 微应用注册表 + 动态加载 |
| FilterManager(全局共享过滤) | Grafana 变量 + $__timeFilter | Redux store / Context provider | 共享状态层(Zustand/Jotai) |
| Dashboard references(依赖图) | Dashboard JSON panel.datasource | React prop 依赖 | 微应用依赖声明 |
| rison(URL 状态编码) | Grafana URL state(JSON + base64) | query-string / URLSearchParams | 路由状态序列化 |
| _g(global state 跨 app) | Grafana 全局变量(所有 panel 可见) | React Router location state | 全局路由状态 |
| embed=true(iframe 嵌入模式) | Grafana kiosk mode / share embed | React standalone render | 微前端 iframe 沙箱 |
常见误解
误解一:“Dashboard 面板共享一个 ES 请求”。每个面板各自独立发 ES 请求,没有跨面板的请求合并。一个有 10 个面板的 Dashboard 打开时会同时发出 10 个(或更多,因为有些面板发多个 sub-request)ES 请求。这是 Embeddable 各自独立 reload 的直接结果。
误解二:“修改一个面板不影响 Dashboard Saved Object”。在 Kibana 8.x 的 inline editing 模式下,直接在 Dashboard 内编辑 Lens 面板并保存,会同时更新面板对应的 Lens Saved Object 和 Dashboard 的 panelsJSON。Dashboard Saved Object 保存的是面板的位置/尺寸和对 viz 对象的 references,viz 内容的修改保存在 viz 自己的 Saved Object 里。
误解三:“URL 里的 rison 可以直接拼接过滤来"硬过滤"数据”。通过 URL 传入的过滤在 Kibana 的 FilterManager 里是可以被用户在界面上清除的(除非配置了 pinned filter 或特殊的 Controls 面板)。如果需要不可覆盖的过滤,应在 Kibana 的 Spaces 或 Data View 层面用 runtime field 或 index alias 做数据级别的隔离,而不是依赖 URL 参数。
误解四:“Dashboard 的 references 只有 visualization 类型”。Dashboard 可以引用 lens、visualization、search(Saved Search)、map(Maps 插件保存的地图)、index-pattern(Data View)等多种类型。Embeddable 框架的开放性决定了 references 的类型集合随已安装插件而变化。
练习
-
用 Kibana Saved Objects API 查看一个已有 Dashboard 的完整 JSON:
GET api/saved_objects/dashboard/{id},画出它的 references 图(面板 → visualization → data view 的三层引用关系),标出每条引用的 type 和 id。 -
在 Dashboard 里配置一个 Controls 面板(Options List Control),绑定到
log.level字段。观察当用户在 Controls 里选择一个值时,URL 的_a参数如何变化,以及其他面板是否收到了相同的 term filter。 -
把当前 Dashboard 的 URL(含
_g和_a)保存下来,在另一个浏览器标签页粘贴打开,验证时间范围、搜索条件、已应用的过滤是否完整恢复。然后手工修改_g参数里的time.from值,刷新页面,观察时间范围变化——理解 URL 状态作为"可编程快照"的含义。
系列导航
| 序号 | 主题 | 状态 |
|---|---|---|
| 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 |
参考资料
- Kibana Dashboard 官方文档:https://www.elastic.co/guide/en/kibana/current/dashboard.html(Embeddable 框架、面板类型、embed 模式)
- Kibana Embeddable 框架源码:https://github.com/elastic/kibana/tree/main/src/plugins/embeddable(IEmbeddable 接口、EmbeddableFactory 注册机制)
- Kibana URL state 说明:https://www.elastic.co/guide/en/kibana/current/sharing-dashboards.html(_g/_a 参数、rison 编码、分享链接)
- rison 格式规范:https://github.com/Nanonid/rison(URL 友好的 JSON 子集格式)
- Kibana Saved Objects API:https://www.elastic.co/guide/en/kibana/current/saved-objects-api.html(references 结构、导出/导入 API)
