Elasticsearch 基准测试:性能验证的工具与技术

借助这份综合指南,掌握 Elasticsearch 性能验证。学习必要的基准测试技术,探索 Rally 等热门工具,并了解如何设计可重复的负载测试。通过了解关键指标并实施最佳实践,优化集群的索引和搜索性能,以获得准确结果。

46 浏览量

Elasticsearch 基准测试:性能验证的工具与技术

有效的性能验证对于任何 Elasticsearch 部署都至关重要。无论您是优化索引速度、查询延迟还是整体集群吞吐量,稳健的基准测试都能提供客观数据,以确认您的调整工作是成功的。如果没有适当的基准测试,性能改进可能仅凭主观判断,关键问题也可能被忽视。

本文将指导您完成 Elasticsearch 的基准测试过程,涵盖基本工具、设计可重复负载测试的方法论以及需要监控的关键指标。通过理解这些原则,您可以自信地衡量和验证性能改进,确保您的 Elasticsearch 集群以最高效率运行。

为什么基准测试至关重要

基准测试不仅仅是运行几次查询。它是一个系统化的过程,用于在各种工作负载下衡量 Elasticsearch 集群的性能。以下是它不可或缺的原因:

  • 客观测量:提供量化数据来评估性能。您确切地知道所做的更改使性能提升了多少或降低了多少,而不是猜测。
  • 识别瓶颈:帮助查明系统内部阻碍性能的具体区域,例如慢速查询、过载的节点或低效的索引。
  • 验证优化:对于确认性能调优期间所做的更改(例如索引设置、分片分配、硬件升级)是否达到了预期的效果至关重要。
  • 容量规划:通过了解集群的当前限制及其在负载增加下的行为,为集群扩展决策提供依据。
  • 回归测试:确保新的代码部署或配置更改不会对性能产生负面影响。

关键监控指标

在进行基准测试时,重点关注直接反映用户体验和系统运行状况的指标。这些通常可以分为以下几类:

索引指标

  • 索引吞吐量:每秒建立索引的文档数量。通常越高越好。
  • 索引延迟:文档在建立索引后可被搜索所需的时间。越低越好。
  • 刷新间隔影响refresh_interval 设置的变化如何影响索引速度和搜索可见性。

搜索指标

  • 搜索吞吐量:每秒处理的搜索请求数量。
  • 搜索延迟:响应搜索查询所需的时间。这通常细分为:
    • 总延迟:端到端时间。
    • 查询延迟:执行搜索查询本身所花费的时间。
    • 获取延迟:检索实际文档所花费的时间。
  • 每秒命中数:搜索查询每秒返回的文档数量。

集群健康指标

  • CPU 使用率:高 CPU 可能表明查询或索引效率低下。
  • 内存使用率:对 JVM 堆和操作系统文件系统缓存至关重要。
  • 磁盘 I/O:此处的瓶颈会严重影响索引和搜索。
  • 网络流量:在分布式环境中很重要。
  • JVM 堆使用率:监控可能导致暂停的垃圾回收活动。

流行的 Elasticsearch 基准测试工具

有几种工具可以帮助模拟负载并衡量 Elasticsearch 的性能。选择合适的工具取决于您的具体需求和技术专长。

1. Rally

Rally 是 Elasticsearch 的官方基准测试工具。它功能强大、灵活,旨在模拟真实的用户工作负载。

主要特点:

  • 工作负载定义:允许您使用 Rally DSL 定义复杂的索引和搜索任务。
  • 数据生成:可以生成合成数据或使用现有数据集。
  • 指标收集:在测试运行期间收集详细的性能指标。
  • 集成:与 Elasticsearch 和 OpenSearch 无缝协作。

示例:使用 Rally 运行基本搜索基准测试

首先,确保您已安装 Rally 并配置它以连接到您的 Elasticsearch 集群。您可以将任务定义在一个 JSON 文件中,例如 my_search_task.json

{
  "challenge": "my_custom_search_challenge",
  "clients": [
    {
      "current-version": "@version"
    }
  ],
  "tasks": [
    {
      "name": "search_some_data",
      "description": "Run a simple search query.",
      "operation": {
        "operation-type": "search",
        "index": "logs-*",
        "body": {
          "query": {
            "match": {
              "message": "error"
            }
          }
        }
      }
    }
  ]
}

然后,您可以使用 esrally 命令运行此任务:

esrally --challenge-file=my_search_task.json --target-hosts=localhost:9200 --challenge-name=my_custom_search_challenge

Rally 将多次执行指定的搜索查询,收集搜索延迟和吞吐量等指标,并提供详细报告。

2. 带有基准测试插件的 Logstash

Logstash 主要是一个 ETL 工具,可用于基本负载生成,尤其是在索引方面。

主要特点:

  • 输入插件:可以模拟来自各种数据源的数据摄取。
  • 输出插件:使用 elasticsearch 输出插件将数据发送到 Elasticsearch。
  • 过滤:允许在索引前进行数据转换。

示例:模拟索引负载

您可以配置 Logstash 管道以生成随机数据并将其发送到 Elasticsearch:

logstash_indexer.conf

input {
  generator {
    count => 1000000
    type => "event"
  }
}

filter {
  mutate {
    add_field => {
      "timestamp" => "%{+YYYY-MM-dd'T'HH:mm:ss.SSSZ}"
      "message" => "This is a test log message %{random}"
    }
    remove_field => ["random", "host"]
  }
}

output {
  elasticsearch {
    hosts => ["localhost:9200"]
    index => "logstash-benchmark-%{+YYYY.MM.dd}"
    # Consider using bulk API for better performance
    # Consider setting document_id for upserts if needed
  }
}

使用此配置运行 Logstash:

bin/logstash -f logstash_indexer.conf

监控 Elasticsearch 和 Logstash 日志以及集群指标,以评估性能。

3. 自定义脚本(Python、Java 等)

对于高度特定或复杂的场景,使用 Elasticsearch 客户端编写自定义脚本是一种可行的选择。

主要特点:

  • 最大灵活性:精确定制负载生成,以满足应用程序的查询模式和索引需求。
  • 客户端库:Elasticsearch 为许多流行语言(Python、Java、Go、.NET 等)提供官方客户端库。

示例:用于搜索负载的 Python 脚本

from elasticsearch import Elasticsearch
import time
import threading

# Configure your Elasticsearch connection
ES_HOST = "localhost:9200"
es = Elasticsearch([ES_HOST])

# Define your search query
SEARCH_QUERY = {
    "query": {
        "match": {
            "content": "example data"
        }
    }
}

NUM_THREADS = 10
QUERIES_PER_THREAD = 100

results = []

def perform_search():
    for _ in range(QUERIES_PER_THREAD):
        start_time = time.time()
        try:
            response = es.search(index="my-index-*", body=SEARCH_QUERY, size=10)
            end_time = time.time()
            results.append({
                "latency": (end_time - start_time) * 1000, # in milliseconds
                "success": True,
                "hits": response['hits']['total']['value']
            })
        except Exception as e:
            end_time = time.time()
            results.append({
                "latency": (end_time - start_time) * 1000,
                "success": False,
                "error": str(e)
            })
        time.sleep(0.1) # Small delay between queries

threads = []
for i in range(NUM_THREADS):
    thread = threading.Thread(target=perform_search)
    threads.append(thread)
    thread.start()

for thread in threads:
    thread.join()

# Analyze results
successful_searches = [r for r in results if r['success']]
failed_searches = [r for r in results if not r['success']]

if successful_searches:
    avg_latency = sum(r['latency'] for r in successful_searches) / len(successful_searches)
    total_hits = sum(r['hits'] for r in successful_searches)
    print(f"Average Latency: {avg_latency:.2f} ms")
    print(f"Total Hits: {total_hits}")
    print(f"Successful Searches: {len(successful_searches)}")
else:
    print("No successful searches performed.")

if failed_searches:
    print(f"Failed Searches: {len(failed_searches)}")
    for r in failed_searches:
        print(f"  - Error: {r['error']} (Latency: {r['latency']:.2f} ms)")

此脚本使用 Python 的 elasticsearch-py 客户端来模拟并发搜索请求并测量它们的延迟。

设计可重复的负载测试

为了获得有意义的结果,您的负载测试必须是可重复的,并且能够代表您的实际使用模式。

1. 定义逼真的工作负载

  • 索引:数据摄取的速率是多少?文档的大小和复杂性如何?您是执行批量索引还是单文档索引?
  • 搜索:典型的查询类型是什么(例如,matchtermrange、聚合)?这些查询的复杂程度如何?预期的并发量是多少?
  • 数据分布:您的数据如何在索引和分片之间分布?如果可能,请使用接近生产环境的数据分布。

2. 建立基线

在进行任何更改之前,运行您选择的基准测试工具以建立性能基线。此基线是衡量优化影响的参考点。

3. 隔离变量

一次只更改一个方面。如果您正在测试多项优化,请在每次单独更改后运行基准测试。这有助于您了解是哪一项特定更改带来了性能提升(或下降)。

4. 一致的环境

确保测试环境在所有基准测试运行中尽可能一致。这包括:

  • 硬件:使用具有相同规格的相同节点。
  • 软件:使用相同的 Elasticsearch 版本、JVM 设置和操作系统配置。
  • 网络:保持一致的网络条件。
  • 数据:使用相同的数据集或数据生成方法。

5. 足够的测试持续时间和预热

  • 预热期:在开始测量之前,让集群预热。这涉及运行一些初始负载,以便缓存可以填充,并且 JVM 稳定下来。
  • 测试持续时间:运行足够长的测试以捕获有意义的平均值,并考虑任何瞬态系统行为。短暂的测试可能会产生误导。

6. 监控系统资源

始终监控 Elasticsearch 节点和运行基准测试工具的任何客户端节点的系统资源(CPU、RAM、磁盘 I/O、网络)。这有助于将性能指标与资源利用率相关联,并识别瓶颈。

基准测试最佳实践

  • 自动化:将基准测试集成到您的 CI/CD 管道中,以便及早发现回归问题。
  • 从简单开始:在转向复杂场景之前,先从基本的索引和搜索基准测试开始。
  • 了解您的数据:数据的性质(文档大小、字段类型)会显著影响性能。
  • 考虑索引策略:测试不同的 refresh_intervaltranslog 设置和分片大小调整。
  • 优化查询:确保您的搜索查询高效。使用 profile API 来分析慢速查询。
  • 监控 JVM:密切关注垃圾回收日志和堆使用情况。

结论

Elasticsearch 的基准测试是一个迭代过程,需要仔细的规划、合适的工具和系统化的方法。通过利用 Rally 等工具、设计可重复的负载测试并关注关键性能指标,您可以深入了解集群的行为。这些客观数据对于验证性能改进、识别瓶颈以及确保您的 Elasticsearch 部署满足其严格要求是无价的。