<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Matthias Wilhelm - Elasticsearch Labs]]></title>
    <description><![CDATA[Articles and tutorials from the Search team at Elastic]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Matthias Wilhelm - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/cn/search-labs/author/matthias-wilhelm</link>
    </image>
    <link>https://www.elastic.co/cn/search-labs/author/matthias-wilhelm</link>
    <atom:link href="https://www.elastic.co/cn/search-labs/rss/author/matthias-wilhelm.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[cn]]></language>
    <lastBuildDate>Fri, 18 Sep 2026 21:53:52 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Kibana 将仪表板加载时间最多缩短了 25%——以下是其背后的轮询策略]]></title>
    <description><![CDATA[了解 Kibana 如何使用连续轮询和浏览器端 HTTP/2 检测将仪表板加载时间减少多达 25%，并自动回退到 HTTP/1。]]></description>
    <content:encoded><![CDATA[<p>由于采用了连续轮询，Kibana 仪表板和 Discover 的加载速度现在最多可提升 25%。现在，Kibana 不再在定期检查之间休眠，而是保持 HTTP 连接开放，并在 Elasticsearch 查询结果准备就绪时立即提供。在 HTTP/2+（Kibana 默认从 9.0 开始使用）上，此功能会自动启动，无需任何配置。在 HTTP/1 上，Kibana 会回退到传统轮询以防止连接池耗尽。</p><h2>Kibana 在加载仪表板时如何获取数据</h2><p>打开仪表板后，大部分面板（我们在内部称之为<em>嵌入式</em>面板）都会启动一个或多个 Elasticsearch 查询。但我们使用的不是同步 (sync) 搜索的简单调用和响应，而是异步 (async) 搜索（<a href="https://www.elastic.co/docs/solutions/search/async-search-api">文档</a>）的强大功能。</p><p>使用异步搜索，查询结果会保存在 Elasticsearch 中，而无需依赖任何特定的 HTTP 请求。这非常重要，因为它</p><ul><li><p>使数据加载不受网络动荡的影响</p></li><li><p>为我们的<a href="https://www.elastic.co/docs/explore-analyze/discover/background-search">后台搜索功能</a>提供支持，让用户在等待长时间运行的仪表板或 Discover 会话时，仍能在 Kibana 中处理其他任务</p></li></ul><p>提交初始查询后，Kibana 会监测搜索，以检测搜索何时完成并检索结果集。</p><h3>传统轮询如何影响 Kibana 仪表板的加载时间</h3><p>在传统轮询中，Kibana 会提交查询，关闭初始连接，然后定期检查 Elasticsearch 是否完成。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt093ed1a718d2f2ed/6a1710c28b73cb568118a109/2f44064a2e627866e129eb626f68ddd62230a4e2-1999x719.png" alt="Kibana 中的传统轮询示意图。Kibana 时间线显示，提交查询后，有一段短暂的连接开放期，随后是长时间的休眠期，然后是短暂的状态轮询，最后才交付结果。Elasticsearch 时间线运行的查询在 Kibana 的休眠期中途完成，这说明了导致时间损失的协调问题。" /><p>我们确实会在查询提交后给 Elasticsearch 一小段时间来完成搜索并返回结果。如果搜索完成得这么快，那就相当于一次简单的请求与响应。但是对于较长的搜索，初始连接会关闭，Kibana 开始定期检查搜索是否完成。这被称为<em>轮询</em>。</p><h4>传统轮询的性能缺陷</h4><p>从上图可以看出，这种方法的性能缺陷是：搜索很可能在 Kibana 的某个休眠间隔期间完成，从而造成时间损失。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3685326f1aa90a1b/6a1710c30c4857892b01ab7a/ad8b80d9e8d6d774065d62e352aad47c3ddb4686-1999x719.png" alt="显示传统轮询性能成本的时间线图。Kibana 时间线显示了连接打开阶段、一个较长的休眠阶段、一次状态轮询，然后交付结果。Elasticsearch 时间线显示，查询在 Kibana 休眠中途完成，随后出现一段红色的损失时间——即 Kibana 唤醒并检索结果之前被浪费的时间。" /><p>在最坏的情况下（搜索在休眠期开始时完成），整个轮询间隔的时间都将浪费。</p><h4>退避策略的影响</h4><p>在进行轮询时，采用退避策略是一种标准做法。这意味着搜索时间越长，我们的轮询频率越低。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt37fb76cf22647ee5/6a1710c5a929cf6fcaae0abd/77665de4a0fd166b533a2c2c55f6f28e38cf37ce-1200x338.png" alt="水平条形图显示了 Kibana 按查询持续时间划分的轮询间隔退避计划。1.5 秒以下的查询使用大约 0.5 秒的间隔；1.5——5 秒的查询使用 1 秒间隔；5——20 秒的查询使用大约 2.5 秒间隔；20 秒以上的查询使用 5 秒的轮询间隔。" /><p>然而，这也意味着潜在的损失时间会随着搜索持续时间的增加而扩展。</p><h4>轮询间隔如何产生锯齿延迟模式</h4><p>将这些因素综合起来，我们损失的时间就成了一个阶梯状的锯齿函数。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd4e81306b0c9f259/6a1710c147d49c34c42d8aec/d5cd43366f62de628c3a054ffb7bf0b05d7a1390-1500x600.png" alt="折线图显示了以秒为单位的损失时间与以秒为单位的查询完成时间之间的关系，呈现出锯齿状模式，即损失时间反复上升然后下降到零，随着查询持续时间从 0 秒增加到 30 秒，损失时间峰值从不到 1 秒增至 5 秒。" /><p>在这里，峰值是最坏的情况，峰谷是最好的情况。这表明，传统轮询的成本取决于搜索持续时间（以及网络状况），可能从零到整个轮询间隔的全部时长不等。</p><h2>持续轮询：Kibana 如何消除等待时间</h2><p>传统轮询的问题在于 Kibana 和 Elasticsearch 之间缺乏基本的协调。理想情况下，Kibana 能够立即知道结果是否可用。那么，如果我们将轮询模式颠倒，使几乎所有时间都用于检查 Elasticsearch，而不再有任何休眠时间，会怎么样？</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4566eaaec79150c7/6a1710c78b73cb1df318a10d/7edc138528dfe1310df42f393ee7279fe3c4703b-1999x713.png" alt="显示 Kibana 中连续轮询的时间线图。Kibana 时间线完全是蓝色的——从查询提交到两次连接刷新，连接一直保持打开状态，直到结果交付，没有休眠期。Elasticsearch 时间轴显示了查询的完成情况和立即交付的结果。图例中被划掉的“损失时间”表示该选项已排除。" /><p>通过这种长轮询和取消睡眠间隔，因此一旦准备就绪，就能立即获得结果。</p><h3>HTTP/1 降级</h3><p>这个理论很可靠。那么，为什么启用连续轮询后，Kibana 部署的性能会下降这么多？</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltede864738a88e1cb/6a1710c947d49c178d2d8af2/517378a73d36bd95927b81b1f912ce465b7adf4c-800x412.gif" alt="显示 Kibana 仪表板加载“示例日志数据”数据集的的动态屏幕录制，展示了多个面板依次填充的过程，包括响应代码时间序列、美国地图上的总请求数、唯一访客数量、HTTP 错误率指标，以及机器操作系统与目标数据的桑基图。" /><p>关键在于，此部署通过 HTTP/1 运行。在 HTTP/1 中，HTTP 请求与 TCP 连接一一对应。因此，多个长期轮询请求占用了浏览器有限的连接池，导致其他请求排队等待。</p><p>另一方面，在 HTTP/2+ 中，网络请求可以通过多路复用共享 TCP 连接，因此我们不会遇到这个问题。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5cddb4d6767a1ccf/6a1710cb839dfa5056dcffcd/f60f3a37baf5ec16c9f1773f08855e7f9e3a7491-1536x1024.png" alt="Kibana 连续轮询的 HTTP/1 与 HTTP/2 的对比图。HTTP/1 每次请求都需要一个 TCP 连接，这样浏览器的连接池就会被六个连接耗尽。HTTP/2 通过单个 TCP 连接多路复用多个轮询请求，避免池耗尽并保持性能。" /><p>因此，在 HTTP/2+ 中，持续轮询是一种优点，但在 HTTP/1 中，它却变成了一种缺点。</p><p></p><p>HTTP/1</p><p>HTTP/2+</p><p>TCP 连接</p><p>每个 HTTP 请求均有一个</p><p>多路复用（多个请求共享连接）</p><p>连续轮询行为</p><p>性能下降（连接池耗尽）</p><p>全面获益（立即见效）</p><h4>Kibana 如何检测 HTTP 协议以优化轮询</h4><p>HTTP/2 是推荐使用的协议，而且自 9.0 版起已成为 Kibana 的默认协议，因此不提供这项性能提升将是一大遗憾。另一方面，HTTP/1 体验已严重下降，任何尚未升级协议的本地部署均不应冒险使用该协议。答案显而易见：我们需要检测正在使用的协议，并采用最佳轮询策略。</p><p>Kibana 服务器当然有可能知道它使用的是哪种协议。但有一个问题：限制因素是浏览器的连接池。这意味着，真正重要的是<em>浏览器</em>所传达的信息。</p><p>由于代理的存在，这些并不总是相同的。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc61ff0abfe101eec/6a1710cd2867144b8893e412/13e38001fc4bd3fc60cfc69114fb9098fd745906-1970x786.png" alt="架构图显示了三个水平连接的组件：左侧是 Kibana 服务器，中间是可选的代理，右侧是 Kibana 客户端。服务器到代理的跳转由 kibana.yml server.protocol 标记，表示已知的协议。代理到客户端的跳转被标记为三个问号，表示该最终跳转所使用的协议未知，可能有所不同。" /><p>如果我们基于服务器协议进行优化，可能会有两种原因出错。</p><ol><li><p>在不应进行连续轮询的情况下进行轮询，会降低体验。</p></li><li><p>未能在需要时应用连续轮询，就会错过优化机会。</p></li></ol><p>幸运的是，现代浏览器提可以通过使用 <code>PerformanceObserver</code> 来检测任何已完成请求的最后一个网络跳转的协议。因此，我们会关注首次提交查询的协议，并在此基础上进行优化。</p>new PerformanceObserver((list) =&gt; {
  const entries = list.getEntries();
  const entry = entries.find(({ name }) =&gt; name.includes('/internal/search/'));
  if (entry) {
    this.protocolSupportsMultiplexing = ['h2', 'h3'].includes(entry.nextHopProtocol);
  }
});<h2>实验室结果：Kibana 中的连续轮询与传统轮询的对比</h2><p>为了验证连续轮询，我们创建了查询延迟时间为 1 至 23 秒的仪表板，并测量了已启用和未启用优化的加载时间。然后，我们加载了带连续轮询和不带连续轮询的仪表板，以衡量收益（我们在 <a href="https://github.com/kertal/race-for-the-prize">race-for-the-prize</a> 中获得了很多乐趣）。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltba4af840d8324923/6a1710ceb339d52fe076a0b6/5f19fb45c5307a7491037fe1ad1a302728793203-1200x742.png" alt="条形图显示了 Kibana 连续轮询的实验室测试结果：与传统轮询相比，在 1 至 23 秒的查询持续时间内节省的时间。根据查询完成时间相对于轮询间隔边界的位置不同，节省的时间在接近零到 4.9 秒之间变化，这证实了退避计划所预测的锯齿状延迟模式。" /><p>该模式与我们最初的锯齿状图相呼应。对于某些查询时长，收益很小，而对于其他查询时长，收益可达数秒。</p><h2>结论</h2><p>这一优化成功地用更高效的连续轮询策略取代了传统轮询固有的延迟。主要挑战在于有条件地实施此优化，以防止 HTTP/1 部署的性能下降。我们使用浏览器的 <code>PerformanceObserver</code> 来可靠地检测最终网络跳转所使用的协议，从而解决了这个问题。</p><p>实验室测试验证了这一理论，表明连续轮询可以在结果准备就绪后立即提供结果。平均而言，这将显著改善用户体验，使数据加载速度提高 25%。</p><p>这项工作是我们致力于缩短用户获得见解时间的最新举措。通过使 Kibana 成为 Elasticsearch 数据的更透明代理，我们推动了自身影响范围内的性能极限。更多精彩，敬请期待！</p><p>(在 2025 年，Thomas Neirynk 对提升 Kibana 仪表板性能的方法和动机进行了<a href="https://www.elastic.co/search-labs/blog/kibana-dashboard-rendering-time">精彩的概述</a>。这是该计划的最新进展。）</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/kibana-dashboard-performance-continuous-polling</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/kibana-dashboard-performance-continuous-polling</guid>
    <category><![CDATA[Kibana]]></category>
    <dc:creator><![CDATA[Drew Tate,Matthias Wilhelm]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd4e81306b0c9f259/6a1710c147d49c34c42d8aec/d5cd43366f62de628c3a054ffb7bf0b05d7a1390-1500x600.png" length="0" type="image/png"/>
    <pubDate>Fri, 22 May 2026 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>