
在之前的博客文章中,我们介绍了如何安装Rally、设置指标收集,并运行我们的第一次竞赛(即基准测试)。每次执行Rally都应该有明确的目的,比如测试我的集群是否可以每天处理5TB的数据摄取,处理每秒30万份文档,并在某段时间内应对50万份文档的峰值。没有明确目标的测试可能毫无意义,因为你不知道要优化什么。
Elastic不建议在生产集群上运行Rally,因为Rally涉及破坏性操作,可能导致数据丢失。此外,在其他地方同时有负载的集群上进行基准测试也没有意义,因为Rally的指标无法被正确解释。
免责声明: 以下基准测试是在GCP上运行的三个e2-standard-16 Elasticsearch节点上进行的。本文讨论的任何基准测试结果都不能作为您Elasticsearch集群的参考点。不能从这些输出中得出任何结论或参考。
我们的第一次竞赛使用了http_logs轨迹上的append-no-conflicts挑战。这一轨迹简单明了,因为它是一个尽可能快的索引挑战。我们设置为使用一个主分片和一个副本。具体命令如下:
esrally race --user-tags='{"benchmark_id": "1.1-http_logs-w20p1r1"}' --track=http_logs --kill-running-processes --target-hosts=https://to-benchmark.elastic.co:9200 --pipeline=benchmark-only --client-options="verify_certs:false,basic_auth_user:'rally',basic_auth_password:'*'" --track-params='{"bulk_indexing_clients":20,"number_of_shards":1,"number_of_replicas":1}' --challenge=append-no-conflicts-index-only完整的输出如下。让我们逐步分析。
____ ____
/ __ \____ _/ / /_ __
/ /_/ / __ `/ / / / / /
/ _, _/ /_/ / / / /_/ /
/_/ |_|\__,_/_/_/\__, /
/____/
[INFO] Race id is [99efadde-0c97-420b-a348-3ffa64cf3388]
[INFO] Racing on track [http_logs], challenge [append-no-conflicts-index-only] and car ['external'] with version [8.12.1].
[WARNING] merges_total_time is 1433768 ms indicating that the cluster is not in a defined clean state. Recorded index time metrics may be misleading.
[WARNING] merges_total_throttled_time is 366296 ms indicating that the cluster is not in a defined clean state. Recorded index time metrics may be misleading.
[WARNING] indexing_total_time is 11289407 ms indicating that the cluster is not in a defined clean state. Recorded index time metrics may be misleading.
[WARNING] refresh_total_time is 184085 ms indicating that the cluster is not in a defined clean state. Recorded index time metrics may be misleading.
[WARNING] flush_total_time is 866810 ms indicating that the cluster is not in a defined clean state. Recorded index time metrics may be misleading.
Running delete-index [100% done]
Running create-index [100% done]
Running check-cluster-health [100% done]
Running index-append [100% done]
Running refresh-after-index [100% done]
Running force-merge [100% done]
Running refresh-after-force-merge [100% done]
Running wait-until-merges-finish [100% done]
------------------------------------------------------
_______ __ _____
/ ____(_)___ ____ _/ / / ___/_________ ________
/ /_ / / __ \/ __ `/ / \__ \/ ___/ __ \/ ___/ _ \
/ __/ / / / / / /_/ / / ___/ / /__/ /_/ / / / __/
/_/ /_/_/ /_/\__,_/_/ /____/\___/\____/_/ \___/
------------------------------------------------------
| Metric | Task | Value | Unit |
|---------------------------------------------------------------:|-------------:|-----------------:|-------:|
| Cumulative indexing time of primary shards | | 196.216 | min |
| Min cumulative indexing time across primary shards | | 0 | min |
| Median cumulative indexing time across primary shards | | 0 | min |
| Max cumulative indexing time across primary shards | | 146.632 | min |
| Cumulative indexing throttle time of primary shards | | 0 | min |
| Min cumulative indexing throttle time across primary shards | | 0 | min |
| Median cumulative indexing throttle time across primary shards | | 0 | min |
| Max cumulative indexing throttle time across primary shards | | 0 | min |
| Cumulative merge time of primary shards | | 77.193 | min |
| Cumulative merge count of primary shards | | 41 | |
| Min cumulative merge time across primary shards | | 0 | min |
| Median cumulative merge time across primary shards | | 0 | min |
| Max cumulative merge time across primary shards | | 65.6786 | min |
| Cumulative merge throttle time of primary shards | | 21.9476 | min |
| Min cumulative merge throttle time across primary shards | | 0 | min |
| Median cumulative merge throttle time across primary shards | | 0 | min |
| Max cumulative merge throttle time across primary shards | | 20.2746 | min |
| Cumulative refresh time of primary shards | | 2.78462 | min |
| Cumulative refresh count of primary shards | | 400 | |
| Min cumulative refresh time across primary shards | | 0 | min |
| Median cumulative refresh time across primary shards | | 0 | min |
| Max cumulative refresh time across primary shards | | 1.07823 | min |
| Cumulative flush time of primary shards | | 16.0124 | min |
| Cumulative flush count of primary shards | | 58 | |
| Min cumulative flush time across primary shards | | 0.0001 | min |
| Median cumulative flush time across primary shards | | 0.0003 | min |
| Max cumulative flush time across primary shards | | 12.7057 | min |
| Total Young Gen GC time | | 12.677 | s |
| Total Young Gen GC count | | 215 | |
| Total Old Gen GC time | | 0 | s |
| Total Old Gen GC count | | 0 | |
| Store size | | 43.9349 | GB |
| Translog size | | 1.53668e-06 | GB |
| Heap used for segments | | 0 | MB |
| Heap used for doc values | | 0 | MB |
| Heap used for terms | | 0 | MB |
| Heap used for norms | | 0 | MB |
| Heap used for points | | 0 | MB |
| Heap used for stored fields | | 0 | MB |
| Segment count | | 36 | |
| Total Ingest Pipeline count | | 0 | |
| Total Ingest Pipeline time | | 0 | s |
| Total Ingest Pipeline failed | | 0 | |
| Min Throughput | index-append | 148682 | docs/s |
| Mean Throughput | index-append | 175950 | docs/s |
| Median Throughput | index-append | 166383 | docs/s |
| Max Throughput | index-append | 244183 | docs/s |
| 50th percentile latency | index-append | 330.002 | ms |
| 90th percentile latency | index-append | 1870.95 | ms |
| 99th percentile latency | index-append | 4708.83 | ms |
| 99.9th percentile latency | index-append | 8383.23 | ms |
| 99.99th percentile latency | index-append | 10537.2 | ms |
| 100th percentile latency | index-append | 14476 | ms |
| 50th percentile service time | index-append | 330.002 | ms |
| 90th percentile service time | index-append | 1870.95 | ms |
| 99th percentile service time | index-append | 4708.83 | ms |
| 99.9th percentile service time | index-append | 8383.23 | ms |
| 99.99th percentile service time | index-append | 10537.2 | ms |
| 100th percentile service time | index-append | 14476 | ms |
| error rate | index-append | 0 | % |
----------------------------------
[INFO] SUCCESS (took 3867 seconds)
----------------------------------竞赛报告以一个免责声明开始,因为我们并没有将集群重置为新的安装状态。大多数情况下,我们可以忽略这些警告,因为我们对这些累积时间并不感兴趣。需要注意的是,如果你正在对一个已经运行的现有集群进行测试,确保Rally是唯一与集群通信的工具,并记住Rally具有破坏性,因为它会删除竞赛中的索引和数据流。Rally假设每次运行后,集群都是新的,许多遥测计算都是基于最终测量的。要消除这些信息,可以通过完全重启集群,因为大多数节点信息在重启时会重置。我们在Rally收集的遥测文档中有详细介绍。
竞赛报告中有很多可能不相关的数值,具体取决于测试类型。在我们的摄取竞赛中,我们关注摄取相关的指标。信息性数据在存储大小之后。
存储大小表示分片中实际存储的数据,在本例中约为44GB。如果你想减少存储,这是一个有用的指标。可以通过将文本字段的映射更改为match_only_text或设置为synthetic source来进行许多优化。所有这些操作都有影响,因此请仔细阅读。
这些指标在本例中不太有用,可以忽略。
段数可以忽略,因为它基于GET _all/_stats?level=shards的调用,该调用使用_all.primaries.segments.count。由于它包括节点上运行的所有主分片,而不仅仅是Rally创建的索引的段,因此对我们不太有用。
这些指标在我们使用摄取管道时才相关。在本例中我们没有使用。摄取管道通常与索引工作负载一起使用,这些指标可能非常有用。总体计数告诉你摄取管道处理了多少文档。总时间是所有文档在管道中花费的时间,这可能是秒、分钟、小时,具体取决于复杂性和传送的文档数量。你可以使用此计算平均值,从而知道单个文档在摄取管道中平均花费的时间。
failed参数帮助识别失败的文档数量。它仅指示不在任何ignore_missing或ignore_failure设置中的处理器失败。与其他指标相反,摄取管道指标使用开始和结束时间差进行计算,因此无需全新集群进行测试。查看遥测文档以了解更多信息。
在纯索引轨迹中,有几个重要的吞吐量指标。这些指标告诉你在你的设置中每秒可以处理多少文档。最小吞吐量是达到的最小值。平均值是平均吞吐量,中位数是数据集中间值,最大值是记录的最高吞吐量。如何一般性地解释这些值?
最大值通常可以忽略。最大值通常是在基准测试的最初几秒内达成的,此时没有队列、缓存等被使用。在大多数生产环境中,集群上有持续负载,因此无法达到相同的最大值。
中位数和平均值是最重要的,它们应非常接近。平均值偏离的一个原因可能是能够维持更高的突发,从而使分布偏向最大值而不是高斯曲线。在我们的例子中,平均值为每秒约17,500个文档,以追加方式插入到单个分片中。中位数稍低,每秒16,600个文档。
这个值很重要,因为它告诉我们在单个主分片上以该数据的连续摄取工作负载大约为每秒16,000-18,000个文档。需要注意的是:目前我们仅查看具有一个副本的单个主分片的文档每秒数。我们还没有查看那个时段的CPU使用率以确定是否存在CPU瓶颈、磁盘瓶颈或其他因素。我们应该避免做的是乘以这个假设,即单个Elasticsearch节点持有10个具有相同数据的主分片能够处理每秒16,000到18,000个文档。
有两个百分位:一个是延迟,另一个是服务时间。百分位表示在某一阈值以下的数据量。百分位是一种查看一致性的好方法。它也是我们了解某些阈值的一种方式。在本例中,90%的索引请求在两秒内完成。其余10%花费的时间最长。例如,我们看到从90%到99%的请求花费的时间要长得多,通常是两倍。99百分位约为4.7秒。这意味着我们可以在4.7秒内处理99%的请求。然而,这比90%的请求两秒时间长了一倍。这是调整和优化的地方。
改变批量大小和改变并发工作者的数量可能会对我们有利。延迟和服务时间延迟之间的区别也在Rally官方文档的FAQ中有所介绍。一般而言,当你使用Rally进行仅摄取时,服务时间将等于延迟。
任何索引错误可能由于映射冲突、消息损坏、摄取管道失败等问题而发生。错误率告诉我们有多少消息失败。
在第一篇博客文章中,我们设置了Rally和Stack Monitoring以将遥测和竞赛信息发送到另一个集群。让我们看看Rally发送的一些文档。有rally-metrics、rally-results和rally-races索引。对于仪表盘和进一步的分析,我建议创建一个查看rally-metrics的数据视图,因为这些数据是在Rally本身期间流式传输的,你可以获得实时数据。

我们有多个有趣的字段以及一些可以忽略的字段。大多数文档包含相同的字段和值。
字段名称 | 描述 |
|---|---|
challenge | esrally命令中指定的挑战名称 |
meta.tag_* | 运行时指定的标签 --user-tags='{"benchmark_id": "1.1-http_logs-w20p1r1"}'。在本例中,它将是meta.tag_benchmark_id,值为1.1-http_logs-w20p1r1。 |
meta.error-count | 在此特定请求中遇到的错误总数 |
meta.distribution_version | 告诉我们目标集群的版本—在我们的例子中是8.14.3 |
meta.index | 告诉我们指标在此文档中针对哪个索引。当运行一个较大的基准测试,目标有多个不同的索引或数据流时,这可能很有用,其中每个索引有不同的摄取管道或不同的分片设置。 |
meta.success | 成功与否 |
meta.success-count | 与meta.error-count相同—在此请求中成功的次数 |
meta.took | Elasticsearch报告给Rally所需的时间,例如对于此批量操作,Elasticsearch花费了90毫秒。 |
operation | 挑战的一部分操作(例如index-append) |
operation-type | 在本例中,操作类型是批量。 |
race-id | 用于在仪表盘中唯一标识一次竞赛的独特竞赛ID |
sample-type | 根据竞赛,可能会有一个预热阶段,允许Elasticsearch集群预填充缓存等。该字段将告诉你这是预热还是正常阶段。 |
task | 任务名称与操作名称相同,除非任务名称通过"name"属性显式定义(参考)。 |
track | 使用的轨迹是http_logs。 |
tracks-params.* | 在esrally调用期间提供的各种参数。包括批量客户端数量、副本数量、分片数量、批量大小等。 |
unit | 用于知道值的单位(大多数情况下是毫秒)。 |
value | esrally完成此操作所花费的时间。在本例中,是一个需要104毫秒的批量请求。此值应始终大于meta.took,因为它包括Rally与Elasticsearch通信并接收响应所需的时间。我建议在任何仪表盘分析中使用此值,因为它能揭示网络中的问题。value与meta.took之间的巨大差异可能显示在防火墙和负载均衡器上的拥塞。 |
我个人喜欢以一种可以轻松查看平均值的方式构建可视化,确保平均值不会因某些长时间操作而被拉高。因此,我建议在进行此类分析时使用百分位数。
要使用的字段是:
有两个字段报告持续时间。一个是meta.took,代表Elasticsearch处理数据所需的时间。另一个是value,表示整个往返时间,包括Rally发送数据直到收到响应。两个值都以毫秒为单位。

对于右侧的CPU使用率,由于我使用了Elastic Agent和Stack Monitoring指标,我还可以访问host.cpu.usage,返回0-100%范围内的CPU使用率,无论核心数如何。这也包括在该主机上运行的任何其他内容,在我们的例子中可以使用,因为它只托管Elasticsearch。
仪表盘顶部的控件字段如下:
还有一些改进需要进行,比如错误计数与成功的对比、整个时间的可见性以及分析某些操作所花费的不同时间。

在这篇博客中,我们解释了竞赛报告的样子以及如何解读这些数字。在下一篇博客文章中,我们将探讨如何调整竞赛,并理解不同的值(如CPU使用情况)如何与仅摄取轨迹关联。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。