# es-benchmark **Repository Path**: ycpanda/es-benchmark ## Basic Information - **Project Name**: es-benchmark - **Description**: Elasticsearch 性能压测工具 - **Primary Language**: Python - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 3 - **Created**: 2026-06-30 - **Last Updated**: 2026-06-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # es-benchmark > 企业级 **Elasticsearch 性能压测工具** —— 模块化、多进程/多线程、令牌桶限速、实时监控、CSV/Excel/HTML 报告,支持 ES 7.x / 8.x、Basic Auth、HTTPS、多节点自动负载均衡。 [![python](https://img.shields.io/badge/python-3.11-blue)](https://www.python.org/) [![elasticsearch](https://img.shields.io/badge/elasticsearch-7.x%20%7C%208.x-green)](https://www.elastic.co/) [![license](https://img.shields.io/badge/license-MIT-lightgrey)](#许可) --- ## 目录 - [特性一览](#特性一览) - [项目结构](#项目结构) - [架构设计](#架构设计) - [安装步骤](#安装步骤) - [配置步骤](#配置步骤) - [运行步骤](#运行步骤) - [性能测试场景](#性能测试场景) - [参数说明](#参数说明) - [Linux 部署](#linux-部署) - [Windows 部署](#windows-部署) - [Docker 部署](#docker-部署) - [分布式压测(6 台机器)](#分布式压测6-台机器) - [长稳测试](#长稳测试) - [报告说明](#报告说明) - [FAQ](#faq) - [许可](#许可) --- ## 特性一览 - **双版本兼容**:同时支持 Elasticsearch **7.x / 8.x**(自动探测客户端版本,选用兼容 API)。 - **完备连接能力**:Basic Auth、HTTP/HTTPS、自签名证书、多节点、连接池、自动重连、节点嗅探、客户端层重试。 - **批量写入**:强制使用 `elasticsearch.helpers.bulk()`,绝不逐条 POST;支持 **指数退避重试**,对 `429 / 503 / 超时 / 断连` 等瞬时错误自动重试。 - **高并发**:`ThreadPoolExecutor` 多线程 + 可选多进程(`multiprocessing`),线程数 / 进程数均可配置。 - **限速**:令牌桶算法,支持 `不限速 / docs·s⁻¹ / MB·s⁻¹`。 - **实时统计**:docs/s、MB/s、TPS、成功 / 失败 / Retry、P50/P90/P95/P99/Max/Min/Avg,每 5 秒刷新。 - **实时监控**:线程数、当前 TPS、当前 docs/s、当前 MB/s、累计文档、成功率 / 失败率、Retry 次数。 - **多种报告**:自动生成 **CSV / Excel(多 Sheet)/ HTML(含趋势图)**。 - **数据丰富**:UUID、手机号、姓名、地址、省份、城市、随机串、日期、时间、JSON 对象、数组;文档大小 `1KB / 5KB / 10KB / 20KB / 50KB / 100KB`;每条文档全局唯一。 - **长稳测试**:30 分钟 / 1 小时 / 2 小时 / 8 小时 / 24 小时;`Ctrl+C` **优雅退出**并自动生成报告。 - **企业级代码质量**:分层架构、单一职责、`typing` + `dataclass` + `pathlib`、完整 DocString、PEP8、单文件 ≤ 500 行。 --- ## 项目结构 ``` es-benchmark/ ├── config/ # 配置层(强类型 dataclass + YAML 加载) │ ├── __init__.py │ └── settings.py # 各配置 dataclass + load_config() ├── benchmark/ # 引擎层(各模块职责单一) │ ├── __init__.py │ ├── version.py # 版本号 │ ├── logging_setup.py # 滚动日志(控制台 + 文件) │ ├── es_client.py # ES 客户端工厂(7.x/8.x 兼容、连接池、重试、嗅探) │ ├── index_manager.py # 索引生命周期(创建/删除/Mapping/分片/副本/刷新) │ ├── data_generator.py # 随机文档生成(指定大小、唯一、多字段类型) │ ├── rate_limiter.py # 令牌桶限速(docs/s、MB/s) │ ├── bulk_writer.py # helpers.bulk 批量写入 + 指数退避重试 │ ├── stats.py # 线程安全实时统计 + 百分位 + 多进程合并 │ ├── monitor.py # 线程实时监控(转置追加表) │ ├── reporter.py # CSV / Excel / HTML 报告 │ ├── scenarios.py # 写入场景(index/create/update/multi_index/time_series) │ ├── template_generator.py # 自定义业务文档模板($gen 生成器) │ ├── mp_runner.py # 多进程编排 │ └── runner.py # 单进程引擎(线程池 + 阶梯/固定 + 优雅退出) ├── scripts/ # 辅助脚本 │ ├── __init__.py │ ├── distributed_run.py # 分布式多机编排(SSH 派发) │ ├── long_stability.py # 长稳测试预设(30m/1h/2h/8h/24h) │ └── sync_nodes.sh # 一键同步项目到多节点(ping→装rsync→覆盖同步) ├── templates/ # 自定义文档模板示例 │ └── user_file_index.json # 业务文档结构示例(含 $gen 联动字段) ├── reports/ # 报告输出(CSV/Excel/HTML,运行时自动生成) ├── logs/ # 日志输出(滚动文件,运行时自动生成) ├── config.yaml # 全局配置(所有参数集中于此) ├── requirements.txt # Python 依赖 ├── Dockerfile # Docker 构建 ├── .dockerignore ├── README.md └── run.py # 主入口 ``` ### 核心能力速览 | 能力 | 说明 | | --- | --- | | 写入场景 | `index` / `create` / `update` / `multi_index` / `time_series` 五种(`--scenario`) | | 自定义文档 | 业务文档模板(`--template`)+ 通用 `$gen` 随机函数库 + 精确大小(`1.46KB`) | | 负载模式 | 固定并发 / **阶梯式递增**(`--staircase "200:300,300:300"`) | | 真并发 | 消除重复序列化、连接池≥线程、bulk 单请求合并 | | 部署 | 一键同步到多节点(`scripts/sync_nodes.sh`)、Docker、分布式 SSH 派发 | --- ## 架构设计 采用 **分层 + 单一职责** 设计: ``` ┌──────────────────────────────────────────────┐ │ run.py (入口: 参数解析 / 日志初始化 / SIGINT)│ └───────────────┬──────────────────────────────┘ │ ┌───────▼────────┐ │ runner.py │ 并发编排(线程池 / 多进程 / 优雅退出 / 报告聚合) └───┬──┬──┬──┬────┘ │ │ │ │ ┌────────┘ │ │ └─────────────┐ ▼ ▼ ▼ ▼ es_client index_manager data_generator rate_limiter │ │ │ │ └────┬──────┘ │ │ │ │ │ ▼ ▼ ▼ bulk_writer ───────────► stats ◄──────── monitor (helpers.bulk (线程安全 (线程数 + + 重试) 百分位) rich 表格) │ ▼ reporter (CSV/Excel/HTML) ``` - **配置层**:`config/settings.py` 把扁平 YAML 转为强类型 `dataclass`,所有模块只依赖配置对象,实现「配置与逻辑解耦」。 - **引擎层**:每个 `.py` 文件一个清晰职责,互不越界,便于测试与替换。 - **跨进程聚合**:`stats.merge_summaries()` 将多进程结果合并为总体汇总。 --- ## 安装步骤 需 **Python 3.11+**。 ```bash # 1. 克隆 / 进入项目 cd es-benchmark # 2. (推荐)创建虚拟环境 python3.11 -m venv .venv source .venv/bin/activate # Linux/macOS # .venv\Scripts\activate # Windows PowerShell # 3. 安装依赖 pip install --upgrade pip pip install -r requirements.txt ``` > 默认安装 `elasticsearch>=7.17,<9.0`(即最新 8.x 客户端,可同时连接 7.x 与 8.x 服务端)。 > 若**明确针对 7.x 服务端**且希望使用 7.x 客户端,可执行: > `pip install "elasticsearch>=7.17,<8.0"` --- ## 配置步骤 所有参数集中在根目录 **`config.yaml`**,运行前按需修改: ```yaml elasticsearch: nodes: ["192.168.0.186:9200", "192.168.0.190:9200", "192.168.0.192:9200"] username: "" # Basic Auth 用户名(无则留空) password: "" use_https: false verify_certs: false version: "8" # 目标服务端版本 "7" 或 "8" timeout: 60 max_retries: 5 index: name: "benchmark_index" auto_delete_old: true number_of_shards: 3 number_of_replicas: 0 # 压测写吞吐建议 0 refresh_interval: "30s" # 压测写入建议拉长 data: doc_size: "10KB" # 1/5/10/20/50/100KB bulk_size: 1000 # 100/500/1000/2000/5000 concurrency: threads: 8 processes: 1 # >1 启用多进程 test: duration_seconds: 300 warmup_seconds: 10 rate_limit: mode: "none" # none / docs / mb rate: 0.0 ``` 完整字段说明见 [参数说明](#参数说明)。命令行参数可覆盖 YAML(见下)。 --- ## 运行步骤 ```bash # 使用 config.yaml 默认参数运行 python run.py # 常用覆盖:时长 / 线程 / bulk / 文档大小 python run.py --duration 1800 --threads 16 --bulk 2000 --doc-size 20KB # 限速到每秒 5000 文档 python run.py --rate-mode docs --rate 5000 # 多进程(本机 4 进程 × 各自线程) python run.py --processes 4 --threads 8 # 指定索引名 / 节点 ID(分布式区分) python run.py --index perf_index --node-id bench1 # 查看版本 / 帮助 python run.py --version python run.py --help ``` 运行过程中:每 5 秒打印一次 rich 实时监控表格;`Ctrl+C` 优雅退出并自动生成报告;结束后打印最终汇总。 --- ## 性能测试场景 | 场景 | 目标 | 推荐配置 | | --- | --- | --- | | **极限写吞吐** | 测集群最大 docs/s | `replicas=0`、`refresh=-1`、`threads=16~32`、`bulk=1000~2000`、`doc=1KB`、不限速 | | **大文档压力** | 测大对象写入与 GC | `doc=50KB/100KB`、`bulk=500`、`threads=8` | | **稳定吞吐(限速)** | 模拟生产匀速写入 | `--rate-mode docs --rate N`(略低于极限) | | **长稳可靠性** | 长时间稳定性 / 内存泄漏 | `scripts/long_stability.py --preset 8h/24h` | | **分布式极限** | 6 机压满集群 | 见 [分布式压测](#分布式压测6-台机器) | | **多进程压满 CPU** | 单机多核打满 | `--processes <核数> --threads 8` | | **阶梯式压测** | 逐档递增并发,找容量拐点/崩溃点 | `--staircase "200:300,300:300,400:300"` | ### 阶梯式压测(逐档递增并发) 固定并发只能测一个点的吞吐。**阶梯式**按档位逐步加压(如 200→300→400 并发,每档 5 分钟),可清晰观察吞吐随并发的变化、延迟拐点与崩溃点(何时开始大量 429/超时)。 ```bash # 命令行:200/300/400 并发各 5 分钟(300 秒) python run.py --staircase "200:300,300:300,400:300" --bulk 1000 # 或在 config.yaml 配置 # test: # profile: staircase # staircase_steps: # - [200, 300] # - [300, 300] # - [400, 300] ``` 每档独立统计后合并为总体报告,Excel/HTML 报告含 **「阶梯步骤」** 分档表(每档并发、docs/s 均值/峰值、P95/P99、成功率),便于一眼定位拐点。 > 阶梯模式跳过预热,每档开始前重置统计,各档速率/延迟/成功率互不干扰。 ### 写入场景(`--scenario` / `data.scenario`) 不同的写入语义会触发 ES 不同的内部路径,本项目内置 5 种写入场景,以 `benchmark_index` 为基名举例: | 场景 | `_op_type` | 索引命名 | `_id` 策略 | 适用 | | --- | --- | --- | --- | --- | | `index`(默认) | index | `benchmark_index` | 唯一(前缀+UUID) | 常规插入吞吐基线 | | `create` | create | `benchmark_index` | 唯一 | 测试 create 路径(冲突即失败) | | `update` | update + doc_as_upsert | `benchmark_index` | 取模命中已有文档(`update_id_space`) | 更新/upsert 热点 workload | | `multi_index` | index | `benchmark_index_0…_{num_indices-1}` | 唯一 | 多索引路由 / 多 Mapping 开销 | | `time_series` | index | `benchmark_index-YYYY.MM.DD`(跨天滚动) | 唯一 | 日志/指标类时序写入 | > 另有 `--mix-sizes`(`data.mix_sizes`)开启**混合文档大小**:每条文档从 1/5/10/20/50KB 随机选取,模拟真实流量,此时忽略 `doc_size`。 ```bash # 更新场景:反复 upsert 同一批文档(热点更新压力) python run.py --scenario update --update-id-space 100000 --threads 16 # 多索引场景:写入 8 个索引,测试路由与多 Mapping 开销 python run.py --scenario multi_index --num-indices 8 --threads 16 # 时序场景:按天滚动索引(跑跨天的长稳测试可见每日新建索引) python scripts/long_stability.py --preset 24h --scenario time_series # 混合大小 + 时序,贴近真实日志流量 python run.py --scenario time_series --mix-sizes --threads 32 ``` ### 自定义业务文档模板(按真实结构压测) 默认生成器使用内置固定结构。若要按**你们真实的业务文档结构**压测(并指定任意精确大小,如 1.46KB),提供一份模板文件(JSON/YAML): - 字段值是字面量 → 原样使用; - 字段值是 `{"$gen": "<类型>", ...}` → 动态生成,保证每条文档唯一且贴近真实。 支持的 `$gen` 类型:`int` / `str` / `choice` / `seq` / `uuid` / `bool` / `timestamp` / `pad`(大小吸收字段)。顶层可加 `__id_field__` 指定某字段值作为 ES `_id`。示例见 `templates/user_file_index.json`。 ```bash # 用真实业务文档结构,精确写入 1.46KB python run.py --template templates/user_file_index.json --doc-size 1.46KB # 真实结构 + 时序滚动索引 + 混合大小 python run.py --template templates/user_file_index.json \ --scenario time_series --mix-sizes --threads 32 ``` > 模板模式与所有写入场景(`--scenario`)正交,可任意组合。`--doc-size` 支持任意值:`10KB`、`1.46KB`、`800B`、`1496`(字节)。 **典型基线测试示例:** ```bash # 场景 A:极限吞吐(5 分钟) python run.py --index bench_max --doc-size 1KB --bulk 2000 \ --threads 24 --duration 300 # 场景 B:大文档(10 分钟) python run.py --index bench_big --doc-size 100KB --bulk 500 \ --threads 8 --duration 600 # 场景 C:限速稳定(匀速 20000 docs/s,30 分钟) python run.py --index bench_stable --rate-mode docs --rate 20000 \ --duration 1800 # 场景 D:混合大小 + 多索引(真实流量画像) python run.py --scenario multi_index --num-indices 4 --mix-sizes \ --threads 24 --duration 600 # 场景 E:真实业务文档结构 + 阶梯式压测(找容量拐点) python run.py --template templates/user_file_index.json \ --staircase "200:300,300:300,400:300" --bulk 1000 ``` > 压测前请先把目标索引的 `number_of_replicas` 设为 0、`refresh_interval` 设为 `-1` 或较长值(本项目 `config.yaml` 默认即如此),以排除副本复制与刷新带来的非写入开销,获得更纯净的写入基线。测试后恢复生产设置。 --- ## 参数说明 ### `config.yaml` | 节.字段 | 说明 | 默认 | | --- | --- | --- | | `elasticsearch.nodes` | 节点列表 `host:port`,多节点自动轮询负载均衡 | `["localhost:9200"]` | | `elasticsearch.username/password` | Basic Auth 凭据 | 空 | | `elasticsearch.use_https` | 是否 HTTPS | `false` | | `elasticsearch.verify_certs` | 是否校验 TLS 证书 | `false` | | `elasticsearch.ca_certs` | CA 证书路径 | 空 | | `elasticsearch.version` | 目标服务端版本 `"7"`/`"8"` | `"8"` | | `elasticsearch.timeout` | 单请求超时(秒) | `60` | | `elasticsearch.max_retries` | 客户端层重试次数 | `5` | | `elasticsearch.retry_on_timeout` | 超时是否重试 | `true` | | `elasticsearch.sniff_*` | 节点嗅探相关 | 见文件 | | `elasticsearch.pool_maxsize` | 连接池大小(7.x 客户端) | `32` | | `index.name` | 索引名 | `benchmark_index` | | `index.auto_create` | 自动创建索引 | `true` | | `index.auto_delete_old` | 自动删除同名旧索引 | `true` | | `index.number_of_shards` | 主分片数 | `3` | | `index.number_of_replicas` | 副本数 | `0` | | `index.refresh_interval` | 刷新间隔 | `"30s"` | | `index.payload_index` | 大字段 payload 是否建倒排索引 | `true` | | `data.doc_size` | 单文档大小 | `"10KB"` | | `data.bulk_size` | 单批 bulk 文档数 | `1000` | | `data.unique_id_prefix` | 文档 ID 前缀(分布式区分) | 空 | | `data.scenario` | 写入场景 `index/create/update/multi_index/time_series` | `"index"` | | `data.num_indices` | multi_index 场景索引数量 | `4` | | `data.update_id_space` | update 场景 ID 取模空间 | `100000` | | `data.time_series_suffix` | time_series 日期后缀(strftime) | `"%Y.%m.%d"` | | `data.mix_sizes` | 混合多种文档大小 | `false` | | `data.template_file` | 自定义业务文档模板(JSON/YAML) | 空 | | `concurrency.threads` | 单进程线程数 | `8` | | `concurrency.processes` | 进程数(>1 多进程) | `1` | | `test.duration_seconds` | 测试时长(秒) | `300` | | `test.warmup_seconds` | 预热时长(不计入统计) | `10` | | `test.profile` | 负载模式 `fixed/staircase` | `"fixed"` | | `test.staircase_steps` | 阶梯步骤 `[[并发,秒],...]` | `[]` | | `index.mapping_file` | 业务真实 Mapping 文件(JSON/YAML) | 空 | | `rate_limit.mode` | 限速模式 `none/docs/mb` | `"none"` | | `rate_limit.rate` | 速率(docs/s 或 MB/s) | `0.0` | | `rate_limit.burst` | 桶容量(0=2×rate) | `0.0` | | `statistics.interval_seconds` | 统计刷新间隔 | `5` | | `statistics.percentile_sample_cap` | 延迟样本上限 | `200000` | | `report.*` | 报告输出目录与开关 | `reports/`,全开 | | `log.level` | 日志等级 | `"INFO"` | | `log.dir` | 日志目录 | `"logs"` | | `log.max_bytes / backup_count` | 日志滚动大小 / 份数 | `50MB / 10` | ### 命令行覆盖参数 | 参数 | 说明 | | --- | --- | | `-c/--config` | 配置文件路径 | | `--duration` | 覆盖 `test.duration_seconds` | | `--threads` | 覆盖 `concurrency.threads` | | `--processes` | 覆盖 `concurrency.processes` | | `--bulk` | 覆盖 `data.bulk_size` | | `--doc-size` | 覆盖 `data.doc_size` | | `--index` | 覆盖 `index.name` | | `--rate-mode/--rate` | 覆盖 `rate_limit.mode/rate` | | `--node-id` | 节点 ID(写入文档 ID 前缀) | | `--scenario` | 覆盖 `data.scenario`(写入场景) | | `--mix-sizes` | 混合多种文档大小 | | `--num-indices` | 覆盖 `data.num_indices`(multi_index) | | `--template` | 自定义业务文档模板(JSON/YAML) | | `--staircase` | 阶梯式压测 `"并发:秒,..."` | | `--no-report` | 禁用报告生成 | --- ## Linux 部署 ```bash # 安装 Python 3.11(以 Ubuntu/Debian 为例) sudo apt-get update sudo apt-get install -y python3.11 python3.11-venv cd es-benchmark python3.11 -m venv .venv && source .venv/bin/activate pip install -r requirements.txt # 编辑配置 vi config.yaml # 后台运行长稳测试,日志写文件 nohup python scripts/long_stability.py --preset 8h --threads 32 \ > /tmp/es-bench.out 2>&1 & # 优雅停止(会自动生成报告) kill -INT ``` ### 一键同步到多节点(`scripts/sync_nodes.sh`) 把本项目从控制机一键分发到多台压测机,自动完成:**ping 探测 → 安装 rsync → 清空历史目录 → 覆盖同步**(可选远程 `pip install`)。适合 6 台压测机快速铺开同一版本代码。 ```bash # 在控制机(项目根目录下)执行,全程交互 chmod +x scripts/sync_nodes.sh ./scripts/sync_nodes.sh # 然后依次输入: # 1) 节点 IP(逗号/空格分隔),如 192.168.64.46,192.168.64.49,192.168.66.219 # 2) SSH 用户(默认 root) # 3) 认证方式:1=密码(自动用 sshpass)/ 2=SSH 密钥(默认) # 4) 目标目录(留空=与当前项目路径一致) # 5) 是否在节点上 pip install 依赖(y/N) # 半自动:直接传 IP 与目标目录 SSH_USER=root ./scripts/sync_nodes.sh "192.168.64.46,192.168.64.49" /opt/es-benchmark ``` 特性: - ping 不通(或 ICMP 被禁)自动回退到 SSH 端口探测;SSH 不通则跳过该节点。 - 自动识别远程包管理器(yum/dnf/apt)安装 `rsync`。 - **重复同步会先 `rm -rf` 远程目标目录再全量覆盖**(`rsync --delete`),杜绝历史残留。 - 自动排除 `.venv/`、`__pycache__/`、`logs/`、`reports/`、`.git/`、本地中转仓库等。 - 目标 IP 为本机时走本地 `cp`,避免自删自。 - SSH 端口可用 `SSH_PORT=22` 环境变量覆盖。 > 控制机需为 Linux(含 `bash`/`ssh`/`rsync`)。Windows 控制机请在 WSL 或 git-bash(装 rsync)中运行。同步完成后在各节点分别运行 `run.py` 即可分布式施压。 --- ## Windows 部署 ```powershell # 安装 Python 3.11(官网安装包,勾选 Add to PATH) cd es-benchmark python -m venv .venv .\.venv\Scripts\Activate.ps1 pip install -r requirements.txt # 编辑配置后运行 python run.py --duration 1800 --threads 16 --bulk 2000 # 在终端按 Ctrl+C 优雅退出并自动生成报告 ``` > 若执行策略限制激活脚本,先执行: > `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` --- ## Docker 部署 ```bash # 构建镜像 docker build -t es-benchmark:latest . # 方式 1:用镜像内默认 config.yaml(请先改好再 build,或挂载覆盖) docker run --rm \ -v "$(pwd)/reports:/app/reports" \ -v "$(pwd)/logs:/app/logs" \ es-benchmark:latest --duration 600 --threads 16 # 方式 2:挂载宿主机 config.yaml 覆盖配置 docker run --rm \ -v "$(pwd)/config.yaml:/app/config.yaml:ro" \ -v "$(pwd)/reports:/app/reports" \ -v "$(pwd)/logs:/app/logs" \ es-benchmark:latest --duration 600 # Windows PowerShell: 把 $(pwd) 换成 ${PWD} ``` `ENTRYPOINT` 已固定为 `python run.py --config /app/config.yaml`,`CMD` 可被任意 `run.py` 参数覆盖。 --- ## 分布式压测(6 台机器) 目标:6 台压测机同时向同一 ES 集群施压。每台机器独立运行 `run.py`,通过 `--node-id` 区分(文档 ID 内含 UUID,保证全局唯一,写入同一索引)。 **方式 A:手动在各机运行(最简单可靠)** 在每台机器上部署项目后,分别执行(仅 `--node-id` 不同): ```bash # 机器 1 python run.py --node-id bench1 --threads 16 --duration 1800 # 机器 2 python run.py --node-id bench2 --threads 16 --duration 1800 # ... 机器 3~6 同理 ``` 各机各自产出报告;最终集群总吞吐 ≈ 各机 `docs/s` 之和。 **方式 B:从一台控制机 SSH 派发** ```bash # 前提:6 台机已部署项目于 /opt/es-benchmark,且控制机可免密 SSH 登录 python scripts/distributed_run.py \ --hosts user@bench1,user@bench2,user@bench3,user@bench4,user@bench5,user@bench6 \ --remote-project /opt/es-benchmark \ --node-id control \ --threads 16 --duration 1800 ``` 该脚本会:在每台远程机后台 `nohup` 启动 `run.py`(日志写入远程 `/tmp/es-bench-.log`),并在本机前台并行运行。各机独立产出报告。 > 说明:本工具不内置跨机协调器(分布式聚合在 [FAQ](#faq) 说明)。多进程(`--processes`)用于**单机**多核;跨机请用本节方式。 --- ## 长稳测试 内置预设脚本,复用 `run.py` 的优雅退出与报告能力: ```bash python scripts/long_stability.py --preset 30m # 30 分钟 python scripts/long_stability.py --preset 1h # 1 小时 python scripts/long_stability.py --preset 2h # 2 小时 python scripts/long_stability.py --preset 8h # 8 小时 python scripts/long_stability.py --preset 24h # 24 小时 ``` `Ctrl+C` 触发优雅退出:等待在途 bulk 完成 → 生成报告 → 打印汇总。即使运行中途中断,也**保证产出报告**。 --- ## 报告说明 运行结束(或优雅退出)后在 `reports/` 生成(可用 `--no-report` 关闭): - **CSV** `benchmark_<时间戳>.csv`:每个统计间隔一行的完整时间序列(docs/s、MB/s、TPS、线程数、P50/P90/P95/P99 等)。 - **Excel** `benchmark_<时间戳>.xlsx`:三个 Sheet —— `Summary`(汇总)、`Percentiles`(百分位)、`Timeseries`(时间序列)。 - **HTML** `benchmark_<时间戳>.html`:自包含单文件,含汇总卡片、延迟分布表、**docs/s 趋势 SVG 折线图**、时间序列表,可直接浏览器打开。 多进程模式额外生成带 `_merged` 标签的**合并报告**。 **关键指标定义:** | 指标 | 含义 | | --- | --- | | `docs/s` | 每秒成功写入文档数(主吞吐指标) | | `MB/s` | 每秒写入数据量 | | `TPS` | 每秒 bulk 事务数(Transactions/s) | | `P50/P90/P95/P99` | 单次 bulk 事务延迟百分位(ms) | | `Peak / Avg` | 各速率指标的峰值与全程平均 | --- ## FAQ **Q1:连接 ES 报「无法连接」/证书错误?** - 检查 `nodes`、`username/password`、`use_https` 是否与服务端一致。 - 自签名证书:`verify_certs: false`;如需校验,配置 `ca_certs` 指向 CA 证书。 - 网络/防火墙:确认压测机到 9200 端口可达。 **Q2:8.x 客户端能否连 7.x 服务端?** - 可以(本项目默认安装 8.x 客户端)。如需严格匹配,针对 7.x 服务端执行 `pip install "elasticsearch>=7.17,<8.0"`。`elasticsearch.version` 配置用于选择 API 调用方式(创建索引参数差异)。 **Q3:写入很慢 / 大量 429?** - 429 = 集群过载(队列满)。措施:调大 bulk、调小线程、拉长 `refresh_interval`、副本设 0、增加分片/节点、或用 `--rate-mode docs --rate <较低值>` 限速。 **Q4:内存占用很高?** - 单批内存 ≈ `bulk_size × doc_size`(如 5000 × 100KB ≈ 500MB/批/线程)。请按机器内存合理组合 `bulk` 与 `doc_size`;启动时若单批过大会有告警提示。 **Q5:多进程与多线程如何选?** - ES 写入是 I/O 密集型:**单进程多线程**通常足以打满网络与集群。仅当单进程线程数已很高却仍打不满 CPU/网络时,再启用 `--processes`(单机多核)。跨机扩展用 [分布式压测](#分布式压测6-台机器)。 **Q6:分布式多机的总体指标如何聚合?** - 各机独立产出报告;总体 docs/s ≈ 各机 docs/s 之和。本工具的单进程多进程合并(`merge_summaries`)仅用于**同一台机器**的多进程结果聚合。 **Q7:百分位基于什么采样?** - 基于「单次 bulk 事务延迟」采样,环形队列上限 `statistics.percentile_sample_cap`(默认 20 万),长稳测试不会内存膨胀。 **Q8:如何只测不限速的极限值?** - `rate_limit.mode: none`(默认即不限速)。`Peak docs/s` 即近似极限吞吐。 **Q9:如何复现测试数据?** - `DataGenerator` 支持 `seed`(代码内默认基于时间)。如需完全可复现,可在 `data_generator.py` 构造时传入固定种子。 **Q10:报告里的成功率不到 100%?** - 失败可能来自:文档级映射错误(查看日志 `BulkIndexError`)、集群拒绝(429,会先重试再计失败)、网络异常。日志 `logs/es-benchmark.log` 含详细错误。 **Q11:自定义模板写入 100% 失败,但普通模式正常?** - 多半是 **Mapping 冲突**:模板里若包含带点的字段名(如 `filename.kw_filename`),ES 会解析为对象路径,与 `filename`(text 叶子字段)冲突,导致每条文档被拒。这些通常是业务的 **mapping 多字段(分词器)**,不在 `_source` 中——模板里只写源字段(`filename`),多字段交给 mapping。 - 自定义模板默认用**动态 mapping**(不套内置固定 mapping),避免字段名冲突;若要贴近真实索引成本(含 ngram/pinyin 分词器),用 `index.mapping_file` 指定业务真实 mapping。 **Q12:阶梯式压测怎么解读结果?** - 看报告「阶梯步骤」表:随并发递增,**docs/s 不再线性增长、P95/P99 急剧抬升、开始出现 429/失败** 的那一档即为容量拐点/崩溃点,据此确定生产安全并发。 **Q13:实时监控表格如何刷新?** - 用 `rich.Live` **原位刷新**:表头固定置顶,指标每 `statistics.interval_seconds` 秒原地更新,不再每次滚动新表。多进程子进程关闭渲染(避免表格交错),仅写日志文件。 --- ## 许可 MIT License. 本项目可作为开源项目自由使用与二次开发。