上一篇完成了 Kibana 与 Grafana 的外部对比。这一篇是系列的收尾,核心问题是:Kibana 从 Kibana 3(无 server)到 Kibana 4(Node server)到旧平台(5–7)到 New Platform(7.x–8.x)再到 Serverless,每一步在解决什么结构性约束,牺牲了什么。

Kibana 3:无服务端,浏览器直连

Kibana 3 发布于 2014 年,是一个纯前端应用。部署方式是把静态文件丢进任意 Web 服务器或 Elasticsearch 的 site plugin 目录,浏览器直接向 ES 的 REST 接口发 HTTP 请求。

这个架构的优点是极度简单:没有额外运行时依赖,没有状态管理问题,没有服务端语言选型。

它的结构性缺陷有三条。

第一,安全问题。浏览器直连 ES,意味着 ES 的地址和凭据必须暴露给每一个打开页面的用户。任何能看到 Kibana 页面的人都能直接操作 ES。在公网或多用户环境里,这是不可接受的。

第二,状态无处安放。Dashboard 定义存在哪里?Kibana 3 的解法是把 Dashboard JSON 存回 Elasticsearch 的一个索引(kibana-int),这个索引没有类型系统,没有迁移机制,版本升级后经常损坏。

第三,服务端能力缺失。报表导出(需要渲染 PDF)、告警定时检查、后台任务这类工作需要一个持续运行的进程,纯前端做不到。

Kibana 4:加入 Node.js 服务端

Kibana 4 在 2015 年引入了 Node.js server。这一步的直接动机是解决上面三个问题。

浏览器改为只和 Kibana server 通信,ES 的凭据留在服务端,不再暴露给浏览器。状态管理被收拢到服务端,后来发展成 Saved Object 服务(带类型、带迁移框架、带引用关系)。服务端进程让报表、后台任务、告警定期执行成为可能。

这一步的代价是增加了一个运维组件。从此,运行 Kibana 意味着既要管 Elasticsearch 集群,又要管 Kibana Node.js 进程。Kibana 3 时代那种"丢个静态文件就完事"的简单消失了。

Node.js 的技术选型在当时有其合理性:ES 生态本身是 HTTP/JSON,Node.js 处理 JSON 和异步 HTTP 的能力与生态匹配;团队本来就在写 JavaScript,服务端也用 JavaScript 降低了切换成本。

Kibana 5 到 7:旧平台的功能扩张与债务积累

从 Kibana 4 到 Kibana 7 早期,核心架构基本稳定,主要变化是功能数量的爆炸式增长:Timelion、Canvas、Spaces、APM、Security、Machine Learning、Lens 的早期版本,一个接一个加进来。

旧平台的插件系统是随着功能增长有机演化出来的,没有统一的生命周期模型。每个插件在服务端的 init() 函数里随意注册路由,随意拿其他插件的引用,随意访问全局 server 对象。前端插件通过 uiExports 机制注入代码,机制混乱,文档稀少。

1
2
3
4
5
6
7
8
9
旧平台典型插件结构(简化)
export default function (kibana) {
return new kibana.Plugin({
init(server) {
const otherPlugin = server.plugins.otherPlugin; // 直接拿引用
server.route({ method: 'GET', path: '/api/...', handler: ... });
}
});
}

到 Kibana 7 早期,这套系统的问题已经不可忽视:循环依赖导致启动时顺序不确定;没有类型约束导致插件 API 变化无法静态检测;前端和服务端插件结构完全不对称,无法共用任何模式;没有清晰的生命周期,在配置阶段访问运行时资源的 bug 经常出现。

New Platform:架构重构

New Platform(NP)从 Kibana 7.0 开始引入,7.x 期间与旧平台并存(大量插件处于迁移中间态),8.0 中旧平台被彻底移除。

NP 的目标不是增加新功能,而是解决旧平台的结构性债务:

  • kibana.jsonc 声明式依赖替代运行时随意拿引用,循环依赖在启动阶段报错
  • 用 setup/start 两阶段生命周期替代单一 init(),强制区分配置阶段和运行阶段
  • 用 typed contract 替代任意 JavaScript 对象传递,接口变化在编译时可检测
  • 前后端插件采用对称结构,都实现 Plugin<S, T, SD, TD> 接口

NP 迁移本身是一次耗时数年的大规模重构。Kibana 代码库里曾经有数百个插件需要从旧平台迁移到 NP,这个过程贯穿了整个 7.x 生命周期。迁移完成后,8.x 的代码库在可维护性和可测试性上都有显著提升——至少从 Elastic 的内部工程博客和外部可观察的 PR 数量来看如此。

NP 的代价是迁移期间的工程成本。数年时间里,Kibana 贡献者需要同时维护两套插件 API,理解两种模式,这对外部插件开发者尤其不友好。NP 迁移期间有相当数量的第三方 Kibana 插件因为无法跟上迁移节奏而失去维护。

从 Dashboard 保存格式看复杂度增长

Kibana 3 时代,Dashboard 定义是一个相当扁平的 JSON:panel 类型、位置、尺寸、查询字符串,直接内嵌在一个对象里。没有 references,没有 type 体系,没有迁移版本。

到 Kibana 8,同一个 Dashboard 的 Saved Object 结构变成了:

1
2
3
4
5
6
7
8
9
Dashboard Saved Object (8.x)
├── type: "dashboard"
├── attributes
│ ├── title
│ ├── panelsJSON panel 配置(含 embeddable type、state)
│ ├── optionsJSON dashboard 级配置
│ └── kibanaSavedObjectMeta.searchSourceJSON
├── references ← 指向 visualization、data view 等对象的引用数组
└── migrationVersion ← 该对象上次被哪个版本的迁移框架处理过

references 数组、migrationVersion 字段、embeddable 架构、searchSource 的分离——每一项都是某个历史版本为了解决特定问题而加进来的。复杂度的增长是真实功能扩张的痕迹,不是随意膨胀。

比较这两个 JSON 是理解 Kibana 演进最直观的方式:用老版本备份的 Dashboard JSON 导入新版 Kibana,迁移框架会按 migrationVersion 逐步把它升级到当前格式。这个升级过程是可追踪的,每个版本的迁移函数都在源码里。

Serverless:运维复杂度的转移

Elastic Cloud Serverless 是 Elastic 在 2023 年推出的托管模式,针对 Security、Observability、Elasticsearch 三种用量场景分别提供 Serverless 项目类型。

在 Serverless 模式下,用户不再管理 Kibana 进程。没有 Kibana server 的版本选择,没有 JVM 调优,没有 Node.js 堆内存配置,没有 Task Manager 的并发参数。用户看到的是一个 URL,背后是 Elastic 托管的多租户基础设施。

1
2
3
4
5
6
7
传统自管理部署
用户 → [自管 Kibana Node.js] → [自管 ES 集群]
↑ 版本选择 / 内存调优 / 升级窗口 / 证书管理

Elastic Cloud Serverless
用户 → [托管 Kibana + ES,多租户,自动伸缩]
↑ 只需关心:用什么功能,用了多少量

Serverless 解决的问题是运维复杂度:自管 Kibana 集群需要处理版本兼容、滚动升级、内存参数、证书轮换,这些对于主业不是基础设施的团队是真实的负担。

Serverless 的代价也是真实的。首先是功能子集:Serverless 项目不支持自管版本的全部功能(某些高级配置项、某些 API 端点在 Serverless 里不存在或行为不同)。其次是厂商绑定:选择 Elastic Cloud Serverless 意味着放弃在任意云或自有硬件上运行的能力。第三是成本模型差异:按用量计费在高流量场景下可能比预留容量的自管方案更贵。

Kibana 在 Elastic 生态里的当前定位

Kibana 今天不只是"可视化前端",它是 Elastic 整个平台的统一操作界面:

1
2
3
4
5
Kibana 作为统一前端
├── Observability APM · Metrics · Logs · Synthetics · SLOs
├── Security SIEM · Endpoint · Cloud Security · SOAR
├── Search Enterprise Search · App Search
└── Platform Discover · Lens · Dashboard · Maps · Canvas · ML

这四个解决方案垂直域(Observability、Security、Search、Platform)都以 Kibana 为前端,背后的数据都在 Elasticsearch 里。Kibana 的 New Platform 架构是支撑这四个垂直域在同一个代码库里共存、互相调用、统一权限管理的基础设施。

从"ES 的图形界面"到"Elastic Platform 的统一前端",这个定位转变贯穿了过去十年的每一次架构决策。

实验:对比 Kibana 3 与 Kibana 8 的 Dashboard JSON 结构

Kibana 3 时代的 Dashboard JSON 可以在 Elasticsearch 的历史 issue 和早期博客文章里找到样本,也可以在 Kibana GitHub 的早期 commit(2014 年前后)里看到测试 fixture。

一个 Kibana 3 Dashboard 片段(示意):

1
2
3
4
5
6
7
8
9
10
11
{
"title": "My Dashboard",
"panels": [
{
"type": "histogram",
"query": "status:200",
"col": 1, "row": 1, "size_x": 6, "size_y": 4
}
],
"index": { "default": "logstash-*", "interval": "day" }
}

一个 Kibana 8 Dashboard Saved Object 的顶层结构(通过 Saved Objects API 导出):

1
2
GET /api/saved_objects/_export
{"type": "dashboard", "excludeExportDetails": false, "includeReferencesDeep": true}

拿到的 ndjson 里,Dashboard 对象有 references 数组,migrationVersion 字段,panelsJSON 里每个 panel 有 embeddableConfigpanelRefNameincludeReferencesDeep: true 参数让导出包含所有引用对象,这正是 references 体系的设计价值:可以递归追踪依赖。

对比两个 JSON,量化一下:Kibana 3 的 Dashboard JSON 通常在 1–5 KB;Kibana 8 的相同功能 Dashboard(带 references)通常在 20–100 KB。复杂度增加了一个数量级,但换来的是版本迁移能力、跨对象引用完整性、多租户隔离。

模式提炼

每次架构演进都对应一个无法在当前结构里继续忽视的约束:安全(K3→K4)、状态持久化(K4设计 Saved Object)、架构债(旧平台→NP)、运维成本(自管→Serverless)。架构演进不是为了追新技术,而是被现实约束推着走。

NP 迁移期间旧平台与新平台的并存是大型代码库重构的标准模式:不能一次性切换,需要两套系统共存、逐步迁移、最终删除旧代码。这个模式在其他大型重构(Rails 升级路径、Spring 迁移、React class→hooks)里同样出现。

Serverless 不是技术进步,而是运维责任的转移。功能子集和厂商绑定是真实的代价,选择时需要明确哪些运维工作是真正的负担、哪些是需要保留的控制权。

工程迁移表

演进步骤 解决的问题 引入的代价 可迁移的决策模式
K3→K4:加 server 凭据安全 + 状态持久化 多一个运维组件 安全边界需要服务端代理
K4→5:Saved Object 类型化状态 + 迁移框架 升级耦合 ES 版本化持久化对象
旧平台→NP 循环依赖 + 类型安全 数年迁移成本 声明式依赖 + 两阶段生命周期
自管→Serverless 运维复杂度 功能子集 + 厂商绑定 按用量计费适合波峰明显的工作负载

常见误解

Serverless Kibana 功能与自管版本完全相同。不对。Serverless 是一个针对特定用量场景优化的托管产品,部分高级配置项、部分管理 API、部分插件功能在 Serverless 里不支持或行为不同。Elastic 的文档会标注哪些功能是"Serverless only"或"not available in Serverless"。

New Platform 迁移是 Kibana 8 强制完成的。不完全准确。NP 迁移贯穿 7.x,旧平台 API 在 8.0 时被移除,但部分遗留模式(如某些 uiExports 机制)的清理持续到 8.x 后续版本。

Kibana 的状态存在 ES 里是一种"反模式"。这取决于视角。对于需要独立备份状态或状态与数据源解耦的场景,这确实是约束。但对于 ES 已经是基础设施的团队,ES 存状态意味着备份、迁移、监控全部复用现有的 ES 运维工具链,是合理的工程取舍。

练习

  1. 在 Kibana GitHub 的 commit 历史里找到 2015 年前后引入 server/ 目录的 PR,阅读 commit message,确认 Node.js server 加入时解决的是哪些具体问题。

  2. 在运行中的 Kibana 8 实例里,通过 Saved Objects API 导出一张 Dashboard(含 includeReferencesDeep: true),统计导出的 ndjson 里有多少个不同 type 的 Saved Object,以及 references 图里最深的依赖链长度。

  3. 对比 Elastic Cloud Serverless(Observability 项目)和自管 Kibana 8 的 Stack Management 菜单,列出哪些配置项在 Serverless 里消失了,推断 Elastic 认为哪些运维决策不应该暴露给 Serverless 用户。

系列导航

  • 上一篇:深入 Kibana 16 - Kibana vs Grafana:两种可视化平台的设计取舍
  • 系列首篇:深入 Kibana 00 - 导读:Kibana 的状态存在 Elasticsearch 里

参考资料