admin管理员组文章数量:1437479
快速Kibana仪表盘
几乎所有Elastic Stack的用户都会在某个阶段使用仪表盘。Elastic为所有集成提供了许多开箱即用的仪表盘,用户也会创建自定义仪表盘:用于与他人分享,进行根本原因分析,或者生成PNG报告。因此,仪表盘应用是Kibana中最常用的应用之一(另一个最受欢迎的应用是Discover)。
此外,仪表盘的许多核心应用组件也支持其他Kibana应用。例如,Kibana用于嵌入图表和表格的小部件框架最初是为仪表盘开发的,而数据插件则是从Kibana浏览器应用向Elasticsearch传递搜索请求的中介,所有Kibana插件都大量使用它。
换句话说,从产品和技术的角度来看,仪表盘应用在Kibana中占有重要地位,并且应该为用户提供最佳体验。
然而,Kibana中的仪表盘有时会显得“迟缓”。我们作为开发者会感受到这一点,用户也会反馈。
与其他工具(如Grafana,或在某种程度上是OpenSearch Dashboards)的比较也显示,Kibana中的仪表盘有时感觉较慢。
因此,Kibana团队最近开始努力减少仪表盘的渲染时间。
识别挑战
通过观察实际用户的遥测数据(我们稍后会详细讨论),我们看到仪表盘的渲染时间有明显的80/20分布。
a) 一方面,一些仪表盘加载时间需要几十秒
在这种情况下,时间主要被(非常)长时间运行的Elasticsearch查询所占据。第95百分位(即少数)仪表盘的渲染时间明显高于平均值。这并不一定是意外的;例如,搜索面板的问题可能跨越很长的时间范围,查询命中未优化的冷或冻结存储层。这些仪表盘占少数,是“长尾”。
数据中还有明显的季节性特征,工作日的渲染时间比周末长。这可能表明“最坏情况”受集群整体负载影响,包括数据摄取(不仅是运行中的分析查询),这种负载在工作时间通常较高。
b) 另一方面,大多数仪表盘加载时间在几秒钟以内
75%及以下(绿色、蓝色和红色线)的加载时间明显较少,但仍需要1-3秒。
当搜索Elasticsearch很快完成时,Kibana的时间都花在哪里了?为什么即使在部署良好且搜索迅速完成时,Kibana仪表盘仍然感觉迟缓?
在项目的初始阶段——也是我们将在本博文中总结的内容——我们决定在2024年春季集中改进b:75百分位仪表盘的渲染时间,确保这些仪表盘变得更迅速和愉悦。
我们没有忘记a!在文章末尾,我们将重点介绍减少前20百分位渲染时间的计划。
遥测
从一开始,我们就意识到对仪表盘渲染时间的测量不够准确。现有的仪器无法捕捉仪表盘页面加载的各个阶段。将指标与我们在日常开发中可以采取行动的内容对齐,并从现实世界的用户那里收集数据也很重要。
a) 测量什么
从高层次来看,我们引入了三个核心指标,每个指标捕捉仪表盘加载的特定阶段。这些指标在通过唯一URL在新标签页中打开仪表盘时可以整齐地堆叠在一起。
指标 | 内容 | 何时 | 频率 |
---|---|---|---|
kibana_loaded | 初始资产加载会话(“旋转图标”) | 首次打开Kibana | 每个用户会话一次 |
dashboard_overhead | 仪表盘应用和面板的引导 | 打开特定仪表盘 | 每个仪表盘一次 |
time_to_data | 数据出现在屏幕上的时间 | 更改过滤器、时间范围、控件等 | 每次查询状态更改一次 |
这些仪器主要是即席实施的。传统的核心Web Vitals(/articles/vitals)并不完全测量我们所寻找的内容,尽管我们可以找到一些相似之处。
具体来说,Time-To-Interactive(TTI)大致对应于“kibana_loaded”的结束。在那之后,应用程序是可用的,尽管所有UX可能还没有完全初始化。例如,仪表盘控件可能尚未初始化,尽管仪表盘应用程序技术上可以开始响应输入。
另一个棘手的指标是将仪表盘的“完成”匹配到所有数据出现在屏幕上时,这在精神上类似于Largest Contentful Paint(LCP)。这是由自定义的AJAX数据请求和前端渲染决定的,每种面板类型都不同。
因此,为了正确收集,每个仪表盘上的每个面板都需要报告其“完成”状态。
对于某些图表来说,这相当简单(例如,简单的度量图表),但对于其他图表来说则很复杂。例如,地图只有在所有瓦片都渲染到屏幕上时才算完成。检测这点并不容易。
在所有面板类型正确报告“完成”后,仪表盘应用程序本身需要观察所有这些“完成”事件,并在最后一个完成后相应地报告“time-to-data”指标。
此外,还引入了这些基准的进一步细分,以及额外的元数据,如仪表盘上的面板数量或用户是否从Kibana内导航到仪表盘(某些资产已经加载)或从Kibana外部导航到仪表盘(没有加载任何资产)。应用程序还会在服务器上收集数据请求的持续时间指标。
b) 每个段的重要性
每个段的语义不同。从上到下逐一分析这些指标:
当涉及到“快速性”时,它主要由time-2-data主导。每次用户操作过滤器状态(例如时间范围),用户都需要等待新数据出现在屏幕上。这是“滞后”最重要的地方。想象一下视频游戏。玩家可能会容忍关卡开始前的加载图标,但他们希望在开始控制游戏时有响应的游戏体验。仪表盘也是如此。用户与图表、控件、过滤器互动……这些互动是仪表盘的“游戏玩法”,决定了用户的响应体验。
Dashboard_overhead也很重要。它是加载仪表盘配置的时间(这是从Elasticsearch的系统索引中检索文档)。它还包括一些额外的代码加载。这是因为在Kibana插件系统中,有些代码是即席加载的。举个例子:假设一个仪表盘有一个swimlane面板。仪表盘应用程序会初始化一个“swimlane”嵌入对象。如果在该Kibana会话期间,这是第一次加载swimlane,那么swimlane嵌入对象需要确保它在渲染之前加载了所有与swimlane相关的代码。深入了解Kibana插件系统会带我们走得太远,但简而言之:一些代码加载的负担被捕获在这个“dashboard_overhead”中,而不仅仅是“kibana_loaded”。
kibana_loaded仅在整个Kibana用户会话中发生一次,并且不是特定于仪表盘的。用户可以从许多其他Kibana页面导航到仪表盘。因此,我们希望将kibana_loaded
与仪表盘的特定体验隔离开来。虽然它是最大的时间块,但在整体Kibana体验的快速性方面,它也是最不相关的。
基准测试
仪器到位后,我们现在需要在适当的环境中收集这些数据:在基准测试部署和实际用户部署中。
a) 在CI中
性能指标是为一些具有代表性的仪表盘收集的。这些仪表盘的配置类似于我们的集成,每个仪表盘包含多种图表类型的混合。
仪表盘基准测试示例
这些基准测试每三小时在Kibana的主发布分支上运行一次。运行程序在专用硬件上启动一个Elasticsearch和Kibana集群。指标是通过Chromium无头浏览器中的Playwright脚本收集的。
b) 在实际使用中
同样的指标也会报告给Elastic Cloud和Serverless用户,以及选择加入遥测的自托管用户。
虽然CI中的基准测试在某个时间点提供了可操作的信号,但在实际使用中收集这些指标提供了一个回顾信号,有助于验证我们的基准测试是否反映了现实世界中的情况。
在文章的后半部分,您将看到过去一年中两者是如何演变的。
关于过程的说明(会议!警报!)
没有单个工程师或团队“拥有”仪表盘体验,因为显示面板是由整个工程团队开发的。
为了协调努力,一些后勤安排被证明是有用的。
报告
每周两次的报告提供了一个回顾遥测数据演变和讨论任何相关工作的机会。这些会议可以看作是小型回顾会。
处理回归
基准测试证明相当可靠,运行高度可重复。
当基准测试中出现负面或意外的变化时,通常可靠地指示需要采取行动的回归。
没有硬性规定如何响应。重大回归通常会立即回滚。有时我们可能会让有问题的提交继续运行,直到错误修复合并。这是根据具体情况决定的,实际上取决于变更的性质。
基准测试中的典型笑脸模式。检测到并解决了回归问题。
即席运行 - 验证假设
随着对工具的熟悉程度增加,我们还在单个PR合并之前进行更多的即席性能测试运行。
这允许在代码更改合并到主开发分支之前更快地验证。
改进
在所有这些准备工作之后,让我们终于进入有趣的部分。
没有银弹。Kibana在各处都花费时间,所有这些都增加了边际负担,总体上加起来。对仪表盘渲染的改进来自于应用程序中许多层次的改进。下面,我们将这些分为几个主要主题。
减少代码和资产加载
高效的代码加载是目前Kibana最大的挑战之一。Kibana的插件架构非常灵活,允许快速添加新页面和应用程序。
这种灵活性确实带来了一些代价,其中两个与浏览器中的JavaScript代码加载密切相关。一个是加载了从未需要的代码,另一个是资产加载往往是分散的,为支持单个应用程序而加载多个小JavaScript资产,而不是少量较大的文件。
第一个问题对仪表盘特别严重。许多插件向仪表盘应用程序注册小部件,例如地图面板、swimlane面板等。然而,大多数仪表盘永远不会显示地图或swimlane。
示例:插件可以向仪表盘面板添加弹出链接。这些链接是上下文相关的。
之前:插件如何为仪表盘面板注册弹出项的伪代码。这种模式会导致加载不必要的代码。
代码语言:javascript代码运行次数:0运行复制import { isCompatible } from './is_compatible'; // 错误。页面加载时加载,即使从未需要
export class MyPlugin {
public start(core, plugins) {
plugins.uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, {
id: 'case_action',
isCompatible: async (context) => {
return isCompatible(context);
},
// ... 其他API方法 ...
});
// 错误。整个实现包含在页面加载中
}
}
为避免这种情况,引入了一种新模式,允许客户端延迟代码加载,直到需要时才加载。
之后:只有在需要时才包含代码。将定义隔离在不同模块中
./case_action.ts
import { isCompatible } from './is_compatible';
export const caseAction = {
isCompatible: async (context) => {
return isCompatible(context);
},
// ... 其他API方法 ...
};
./plugin.ts
export class MyPlugin {
public start(core, plugins) {
plugins.uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, 'case_action', async () => {
// 好的。让注册表决定何时加载定义
return import('./case_action');
// 好的。只有在需要时才加载操作实现。
});
}
}
另一个问题是插件的初始化会阻碍响应性,导致资产加载的瀑布效应变得串行化而不是并行化。
一个例子是仪表盘控件曾经阻碍页面渲染,导致所有面板必须等待控件加载所有资产才开始渲染。这当然是不必要的,因为渲染应该在控件完全初始化之前开始。
许多这些代码加载问题已经得到解决,增加了整体响应性。由于Kibana有许多插件(超过200个并且还在增加),需要持续关注以解决这些低效代码加载模式的误用。
可嵌入对象和渲染
2024年Kibana的一个大努力是可嵌入对象的重构。这项工作的目标之一是性能,虽然这在很大程度上是一个附带的关注点。该工作必须支持一些关键功能(如可折叠面板),删除许多未使用的代码路径(主要是angular相关),提高可测试性,并简化使用API的开发体验。您可以在这里阅读更多内容。
可嵌入对象允许整理仪表盘性能的一种方式是将所有渲染合并到单个React树中。以前,每个面板都被渲染到自己的渲染树中,使用ReactDOM.render()
。这种架构是Kibana中同时存在Angular和React(以及jQuery,咳)的时代的产物。这种混合渲染技术在Kibana中已经不存在超过4年,完全标准化为React作为唯一的UX渲染库。然而,仪表盘携带了这种遗留问题,增加了额外的抽象层。
减少面板响应的状态变化和重新渲染次数对仪表盘应用程序产生了边际改进,总体上增加了其响应性。代码的减少也有助于减少应用程序的负担。
避免混乱的内存分配
图表和表格的代码会将从Elasticsearch接收到的数据重新组织成更易于显示的数据结构。它们执行“平展”步骤,将嵌套的数据结构从ES响应转换为一维数组,其中数组的每个项对应一个特性(例如表中的一行,柱状图中的一个柱…)。
例如,考虑一个有许多子字段的嵌套ES文档,或者ES搜索的桶的层次结构组织。平展这些数据的实现通常分配短生命周期的对象,如对象字面量或lambda函数() => {}
。频繁使用数组方法如.map
或.reduce
是这种对象分配容易潜入的模式。
由于这些平展操作都发生在紧密的递归循环中(成千上万的文档,数百个桶),并且考虑到仪表盘可能包含多个表格和多个图表,这些分配会迅速累积。这样的堆分配不仅在构建时影响用户体验,还会增加垃圾回收器的负担(垃圾回收器的运行时间不确定,但往往会导致帧率的卡顿)。
我们的基准测试显示,通过移除一些最明显的紧密循环中的对象分配,可以实现有意义的改进(大约5-10%)。
数据传输改进
仪表盘运行的Kibana浏览器到Elasticsearch的数据请求往返是批处理的。多个请求会被收集,Kibana服务器会将这些请求分发到Elasticsearch作为单独的_async_search
请求,并将这些ES-JSON响应组合成新的Kibana特定格式。
这种批处理的主要原因是它绕过了HTTP1的浏览器连接限制,这大约为6个并发HTTP请求,这在包含多个面板的仪表盘上很容易超过。
这种方法有两个主要缺点。它增加了收集批次的一个小延迟。它还增加了Kibana服务器的负担,等待和重新编码ES响应。Kibana服务器需要先解压它们,解码JSON,连接响应,然后再压缩。虽然这种重新编码步骤通常很小,但在最坏情况下(例如对于大响应),可能会显著增加。它还会增加显著的内存压力,偶尔导致内存不足的问题。
鉴于Elastic Cloud和Serverless前面的代理已经支持HTTP 2.0,并且Kibana将在9.0中开始支持HTTP 2.0状态,决定移除这种批处理。此外,kibana服务器不再重新编码数据,而是从Elasticsearch流传输原始压缩结果。
这大大简化了数据传输架构,结合使用HTTP 2.0,显示了一些不错的性能改进。除了性能优势(更快,对内存不足更不敏感),由于架构简化和数据响应现在可以在浏览器调试器中轻松检查,调试性也大大提高。
结果
这些改进的总体效果是显著的,反映在基准测试和用户遥测中。
基准测试演变
下图显示了多个基准测试的混合指标,以及过去6个月的演变。我们可以看到总体下降,从大约3500毫秒下降到2000毫秒(*最近的上升与当前改变Kibana主题的努力有关。在这个迁移阶段,我们发布了多个主题。这将逐步移除。还有一些CI运行崩溃的间隙)。
现实世界用户
正如开头所述,现实世界更难测量。我们不知道用户运行的具体仪表盘,以及它们的配置如何随时间变化。
然而,从两个不同的角度来看,我们可以验证与合成基准测试环境中的演变相同。
首先,随着时间的推移,我们看到第75百分位的渲染时间下降。这使我们能够说——平均而言——2025年1月用户在仪表盘上的体验明显比24年6月更好。速度更快。
25、50和75百分位的仪表盘渲染时间
我们还可以比较所有用户在上周的版本的平均time_to_data。8.17版的用户等待数据出现在屏幕上的时间明显少于8.12版的用户。
现实世界中的下降也略微滞后于我们在基准测试中观察到的,这大致符合堆栈的发布节奏。
展望未来
总的来说,曲线在下降,主要是通过增加许多小的优化。
在某些重要领域,这种减少脂肪的方法最终会导致收益递减。以下是一些我们认为需要通过更结构化的方式来解决的问题。
继续优化代码加载
我们在本文中没有详细讨论kibana_loaded
指标。如果要描述它:Kibana插件架构优化了允许应用程序即席加载代码,代码打包过程生成了许多JavaScript代码包。然而,在实践中,我们确实看到加载了不必要的代码,以及代码加载的“瀑布效应”,代码加载可能阻碍UX的渲染。总的来说,这里的情况可以改进(见上文“减少代码和资产加载”)。
团队目前正在进行一个更广泛的努力,“可持续Kibana”,包括重新审视我们如何将代码打包和传送到浏览器。
我们预计这里会有更多的好处出现。当它们出现时,请务必查看博客文章!
处理慢速搜索
长时间搜索需要很长时间。这是事实。Elasticsearch搜索可能由于多种原因变慢,这甚至不一定是错误。考虑在一个具有数TB数据的大型集群上进行复杂聚合,跨越长时间范围,命中数百个不同存储层的节点。根据集群的配置,这可能最终是一次慢速搜索。Kibana需要在面对这种查询依赖的限制时保持弹性。
在这种情况下,我们无法通过Kibana中的低级改进(如上文讨论的那些)来提高仪表盘的“快速性”。为了解决固有的缓慢问题,需要一套新功能,允许用户选择“快速”模式。
例如,考虑对数据进行采样,用户可以以速度换取准确性。或者通过在数据进来时逐步填充图表来改善感知性能。或者允许用户通过可折叠面板隐藏仪表盘的部分(即将推出!)。
这些变化将更多地跨越产品功能和低级技术改进的界限。
图表和查询依赖的缓慢
目前的努力主要集中在对影响广泛的低级组件进行改进。然而,有些情况下,仪表盘由于特定的图表配置而变慢。
例如:
- 计算“其他”桶,
- 高基数数据的唯一计数聚合,
- ...
识别这些图表和查询将允许更有针对性的优化。默认设置是否正确(例如,所有图表都需要另一个桶)?是否有更高效的方式查询相同的数据?
将Discover加入程序
仪表盘的所有痛点在Discover中也存在(可插拔图表、数据密集、需要响应性……)。因此,我们已经将这一计划推广到Discover应用程序的开发指导。
目前,我们在Discover中已经看到了一些不错的收益,并希望在此基础上继续发展。这也值得一篇博客文章,所以请继续关注!
结论
Kibana中的仪表盘变得更快了。最近的改进是许多低级优化的复合效果。
要进一步推进,我们预计将采用更双管齐下的方法:首先,继续这种改进习惯的主题。其次,扩展到更广泛的计划,以解决导致缓慢的“长尾”原因。
本文标签: 快速Kibana仪表盘
版权声明:本文标题:快速Kibana仪表盘 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/biancheng/1747492441a2699888.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论