# rocketmq-grpc-benchmark **Repository Path**: project-store-mark/rocketmq-grpc-benchmark ## Basic Information - **Project Name**: rocketmq-grpc-benchmark - **Description**: 企业级 RocketMQ 性能测试工具 · 原生 gRPC Proxy - **Primary Language**: Java - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 1 - **Created**: 2026-07-01 - **Last Updated**: 2026-07-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: mq, 性能, 测试, Grpc ## README
# 🚀 rocketmq-pressure **企业级 RocketMQ 性能测试工具 · 原生 gRPC Proxy** 基于 `rocketmq-client-java` 5.x (gRPC) 的生产可用压测利器 —— 非演示 Demo [English](README.md) · **简体中文** ![Java](https://img.shields.io/badge/Java-17-ED8B00?logo=openjdk&logoColor=white) ![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.3.x-6DB33F?logo=springboot&logoColor=white) ![RocketMQ](https://img.shields.io/badge/RocketMQ-5.x-D77311?logo=apacherocketmq&logoColor=white) ![Maven](https://img.shields.io/badge/Maven-3.8%2B-C71A36?logo=apachemaven&logoColor=white) ![License](https://img.shields.io/badge/license-Apache--2.0-blue) ![Version](https://img.shields.io/badge/version-1.0.0-success) [功能特性](#-功能特性) · [架构](#-架构) · [快速开始](#-快速开始) · [配置](#%EF%B8%8F-配置) · [使用](#-使用) · [监控](#-监控) · [路线图](#-路线图) · [贡献](#-贡献)
--- > **不是演示项目。** 这是一套可维护、生产可用的负载发生器,可直接部署到多台机器,对 RocketMQ 5.x 进行真实性能压测——配备精确的 HDR 直方图分位值、JVM/OS 监控、Prometheus 指标暴露,以及自动生成的 CSV/JSON 报告。 ## ✨ 功能特性 | 领域 | 能力 | |---|---| | **生产者** | 同步 / 异步 / 单向 / 批量 / 事务(预留) · 固定字节 / 随机字符串 / 随机 JSON / 固定 JSON 负载 · 1K–256K 消息大小 · 令牌桶固定 TPS 限速 · 多 Topic(1/10/50/100/200…) · 固定负载零分配复用 | | **消费者** | PushConsumer / SimpleConsumer · 集群 / 广播模式 · 多消费组 · Tag / SQL92 过滤 | | **压测控制** | 固定 TPS · 不限速 · 时长控制 · 持续发送/消费 · 可配置消息大小与内容 | | **实时统计** | 生产/消费 TPS · 成功/失败计数 · 平均/最大 RT · **P50/P90/P95/P99/P999(HdrHistogram)** · 吞吐 MB/s · 消息积压 · 每秒打印 | | **报告** | 自动生成 **CSV + JSON**:起止时间、时长、TPS、RT 分位、吞吐、失败率 | | **监控** | CPU / 内存 / GC / 线程 / 网络 / JVM Heap / NonHeap / 文件描述符 · **Prometheus 端点** | | **工程规范** | SOLID · 单一职责 · SLF4J 日志 · 阿里 Java 规范 · 纯 `ThreadPoolExecutor`(禁止裸 `new Thread`) · 线程异常隔离 | ## 🏗 架构 ``` ┌──────────────────────────────────────┐ │ PressureRunner │ 角色分发 · 生命周期 │ CommandLineRunner + @PreDestroy │ 优雅关闭 · 报告 └──────────┬───────────────┬────────────┘ ┌──────────────────────┘ └─────────────────────┐ ┌───────▼─────────┐ ┌──────▼──────────┐ │ ProducerEngine │ │ ConsumerEngine │ │ SendWorker ×N │ │ Push / Simple │ └───────┬─────────┘ └──────┬──────────┘ │ gRPC (Proxy :8080) │ ▼ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ RocketMQ 5.4.0 Proxy (gRPC) │ └──────────────────────────────────────────────────────────────────────────────┘ 横切关注点:Statistics(HdrHistogram+LongAdder) · Monitor(JVM/OS) · Report(CSV/JSON) · Micrometer→Prometheus ``` **分层设计(SOLID,每类单一职责):** ``` com.yyq ├── RocketmqPressureApplication # 启动入口 (@ConfigurationPropertiesScan) ├── common 枚举 · 常量 · 异常 ├── model @ConfigurationProperties 配置类(唯一参数源) ├── config 客户端工厂 · 线程池 · Micrometer 绑定 ├── thread 命名线程工厂 + 未捕获异常兜底 ├── util 负载 · byte[] 池 · 限流器 · json/csv/host/time ├── statistics 收集器 · 快照 · 打印器 · 任务 ├── monitor 采集器 · 快照 · 任务 ├── report 模型 · csv/json 写入器 · 生成器 ├── producer 发送策略 · Worker · Engine ├── consumer Push/Simple 管理器 · 监听器 · Worker · Engine └── service PressureRunner 编排器 ``` ## 🧱 技术栈 | 层 | 选型 | |---|---| | 运行时 | JDK 17, Spring Boot 3.3.x | | 消息 | `org.apache.rocketmq:rocketmq-client-java` 5.x (gRPC) | | 分位值 | HdrHistogram 2.x | | 指标 | Micrometer + Actuator + Prometheus registry | | 序列化 | Jackson | | 构建 | Maven 3.8+ | ## 📦 环境要求 - **RocketMQ 5.x** 且 **Proxy(gRPC)** 已启动(默认 `192.168.1.29:8080`,认证关闭) - 每台压测机 **JDK 17** - 构建机 **Maven 3.8+** - 推荐 Linux(CentOS / Alibaba Linux);文件描述符与网络指标读取 `/proc` ## 🚀 快速开始 ```bash # 1. 构建 fat jar mvn clean package # → target/rocketmq-pressure.jar chmod +x scripts/*.sh # 2. 单机冒烟:先起消费,再起小流量生产 ./scripts/start-consumer.sh --consumer.thread-count=20 --consumer.duration=90 sleep 3 ./scripts/start-producer.sh \ --producer.send-mode=sync --producer.tps-limit=200 \ --producer.message-size=1024 --producer.thread-count=10 \ --producer.duration=60 --server.port=8082 # 第二实例换端口 # 3. 观察实时统计 tail -f logs/rocketmq-pressure.log # 4. 停止并查看报告 ./scripts/stop.sh cat report/*.csv ``` **通过判据:** `sendSuccessTotal ≈ 12000`,`consumeSuccessTotal` 接近,`failureRate ≈ 0`。 ## ⚙️ 配置 全部参数位于 [`conf/application.yml`](conf/application.yml)。启动脚本以 `spring.config.additional-location` 加载它,覆盖 jar 内默认配置。**命令行参数 `--key=value` 再次覆盖文件。** > 优先级:**命令行参数** > `conf/application.yml` > 打包的 `src/main/resources/application.yml` ### 全局角色 | 键 | 取值 | |---|---| | `pressure.role` | `producer` / `consumer` | ### 连接 | 键 | 示例 | |---|---| | `rocketmq.endpoint` | `192.168.1.29:8080` | | `rocketmq.request-timeout` | `3s` | | `rocketmq.ssl-enabled` | `false` | | `rocketmq.access-key` / `rocketmq.secret-key` | 空 = 不鉴权 | #### 多 Proxy 端点与流量均分 5.x gRPC 客户端支持**多端点**,用 `;`(分号)分隔。2 个 Proxy 示例: ```yaml rocketmq: endpoint: 192.168.1.190:8080;192.168.1.186:8080 ``` > 命令行使用时**务必加引号**,避免 shell 吞掉分号: > `--rocketmq.endpoint='192.168.1.190:8080;192.168.1.186:8080'` > 支持**任意数量**端点(1、2、7、…)。 **为什么需要均分**:5.x 客户端对多端点采用 `pick_first`——每个实例只连**第一个**端点,其余仅作故障转移。若所有节点端点串相同,流量会全部压到同一个 Proxy。 **本工具自动均分(各节点命令完全一致)**:按实例序号对端点列表做循环轮转,使不同实例选到不同首选 Proxy。轮转偏移量按以下优先级解析: | 优先级 | 来源 | 怎么给 | |---|---|---| | 1 | 环境变量 `PRESSURE_NODE_INDEX` | `export PRESSURE_NODE_INDEX=0/1/2…` | | 2 | 系统属性 `-DPRESSURE_NODE_INDEX=N` | JVM 参数 | | 3 | 文件 `/etc/rocketmq-pressure/node-index` | 每台机器放一个数字 | | 4 | 都没有 | 回退主机名哈希(近似均分) | 设置实例序号后,**N 台机器对 M 个端点严格均分**(每个端点分到 ⌊N/M⌋ 或 ⌈N/M⌉ 个实例,数学最优)。各实例仍保留全部端点作故障转移。启动日志会打印实际首选端点: ```text Endpoints balanced (nodeIndex=3): primary=[192.168.1.186:8080] (offset=1/2), order=... ``` ### 生产者参数 | 键 | 默认 | 说明 | |---|---|---| | `producer.topic` | `test_yyq_simple-workload-0` | 单 Topic / 派生前缀 | | `producer.topics` | `[]` | 显式列表(优先级最高) | | `producer.topic-count` | `1` | `>1` 派生 `prefix-0..N-1` | | `producer.thread-count` | `200` | 发送线程数 | | `producer.message-size` | `1024` | 字节(1K/4K/16K/64K/128K/256K) | | `producer.payload-type` | `fixed_bytes` | `fixed_bytes`(最快、零分配复用)/`random_string`/`random_json`/`fixed_json`。random_* 每条重新生成 → 吞吐天花板显著降低 | | `producer.attach-keys` | `false` | 是否附加 `pressure-` Keys。关闭=无全局计数器争用、无每条字符串分配(最快)。开启=可按 Keys 查询 | | `producer.send-mode` | `async` | `sync`/`async`/`oneway`/`batch`/`transaction` | | `producer.batch-size` | `1` | 每批条数 | | `producer.tps-limit` | `0` | `0` = 不限速 | | `producer.duration` | `1800` | 秒,`<=0` = 持续 | | `producer.max-attempts` | `3` | 客户端重试 | | `producer.max-inflight` | `10000` | async/oneway 最大在途消息数(背压);`0` = 不限。大消息请下调,峰值堆 ≈ maxInflight × messageSize | | `producer.message-group` / `producer.tag` | 空 | 可选顺序分组 / Tag | ### 消费者参数 | 键 | 默认 | 说明 | |---|---|---| | `consumer.group` | `pressure-group` | 基础消费组 | | `consumer.groups` | `[]` | 显式多组 | | `consumer.topics` | `[]` | 空 → 复用 producer 的 Topic | | `consumer.thread-count` | `200` | push 并发线程 / SimpleConsumer 拉取线程 | | `consumer.consumer-type` | `push` | `push` / `simple` | | `consumer.consume-mode` | `clustering` | `clustering` / `broadcasting` | | `consumer.filter-expression` | `*` | tag 或 SQL92 | | `consumer.filter-type` | `tag` | `tag` / `sql92` | | `consumer.await-duration` | `30s` | Simple 长轮询等待 | | `consumer.invisible-duration` | `15s` | Simple 不可见时长 | | `consumer.receive-batch-size` | `64` | Simple 单次拉取(越大吞吐越高,仅 simple 生效) | | `consumer.max-inflight-ack` | `4096` | Simple 异步 ack 在途上限(仅 simple 生效);`0` = 不限。既限制内存(≈ 上限 × 消息大小),又保证 ack 在 `invisible-duration` 内完成,避免 Broker 重投 → 多节点集群**不重复消费** | | `consumer.max-cache-message-count` | `1024` | Push 缓存消息数 | | `consumer.max-cache-message-size` | `128MB` | Push 缓存字节 | | `consumer.duration` | `1800` | 秒,`<=0` = 持续 | ### 统计 / 监控 / 报告 / Web | 键 | 默认 | |---|---| | `statistics.enabled` / `statistics.interval` | `true` / `1` | | `statistics.per-topic-breakdown` | `false` —— 每条消息维护按 Topic 聚合计数(用于报告按 Topic 明细)。关闭 = 热路径跳过按 Topic 查找与写入(开销最低);开启 = 报告含按 Topic 明细 | | `monitor.enabled` / `monitor.interval` / `monitor.collect-fd` | `true` / `5` / `true` | | `report.enabled` / `report.dir` / `report.formats` | `true` / `report` / `[csv,json]` | | `server.port` | `8081`(避开 Proxy `8080`) | | `management.endpoints.web.exposure.include` | `prometheus,health,info` | ### 性能调优与 JVM 资源(16C16G / 5Gb) 启动脚本以 `MEM` 环境变量启动 JVM(默认 `-Xms4g -Xmx4g`)。启动前按机器覆盖即可——想"靠加线程把机器吃满",**这是第一道要先抬高的天花板**: ```bash MEM="-Xms8g -Xmx8g" ./scripts/start-producer.sh --producer.thread-count=1000 ``` `producer.thread-count` **没有硬性上限**,可随意调大。真正的天花板是 JVM 堆与 async 在途内存: | 发送模式 | 并发上限来源 | 提升吞吐的方法 | |---|---|---| | `sync` | `thread-count`(每线程阻塞等 ack) | 调大 `producer.thread-count` | | `async` / `oneway` | `producer.max-inflight`(信号量背压) | 调大 `max-inflight`(盯住堆),可选调 `thread-count` | | `batch` | `batch-size × thread-count`(`join()` 自限) | 调大 `batch-size` | **`producer.max-inflight`** 限制 `async`/`oneway` 同一时刻未完成的 `sendAsync` 数量。broker 变慢时,发送线程在获取许可处阻塞,而不是把消息堆进内存 → 不再 OOM,而是优雅自限速。峰值堆 ≈ `maxInflight × messageSize`(RANDOM 负载);设 `0` 完全关闭背压。 16C16G / 5Gb 推荐起点: ```bash MEM="-Xms8g -Xmx8g" ./scripts/start-producer.sh \ --producer.send-mode=async --producer.tps-limit=0 \ --producer.payload-type=fixed_bytes --producer.attach-keys=false \ --producer.message-size=1024 --producer.thread-count=64 \ --producer.max-inflight=50000 --producer.duration=1800 ``` > **async 是 IO 密集,不是 CPU 密集。** 吞吐由 `max-inflight` 与 gRPC/Netty IO 线程决定,**不是**发送线程数。async 下**不要**把 `thread-count` 拉到几百——那些自旋线程会跟处理 ack、发数据的 Netty IO 线程抢 CPU,反而*降低*吞吐。`thread-count` 保持在 `核数 × 2~4`,靠抬 `max-inflight` 提速(盯住堆 ≈ `maxInflight × messageSize`)。只有 `sync` 模式,`thread-count` 才是真正的并发旋钮。 **调参方法**:阶梯式抬 `max-inflight`(async/oneway)或 `thread-count`(sync),盯 `pressure_producer_tps`(Prometheus)与每秒控制台行。当 TPS 不再涨(只剩 RT / 失败率上升),就到了 **broker** 的天花板,即停。压测机 CPU 宜保持在 80% 以下,RT/TPS 才可信——压测机自己被打满,瓶颈就变成了测试工具而不是被测系统。 大消息(≥64KB)请下调 `max-inflight`,使 `maxInflight × messageSize` 远小于堆。极限吞吐下的可选进阶参数:`-XX:MaxDirectMemorySize=4g`(gRPC/Netty 直接内存)。 **消费侧** —— `consumer.thread-count` 无上限随意调大。要做**大批量 / 快速消费**,两条路径旋钮不同: | 消费类型 | "批量"的含义 | 提升吞吐的旋钮 | |---|---|---| | `simple` | 真正的批量拉取——`receive()` 一次最多返回 `receive-batch-size` 条 | `consumer.receive-batch-size` + `consumer.thread-count` | | `push` | 无批量概念(推模式、逐条回调)——只能靠并发 | `consumer.thread-count` + `consumer.max-cache-message-count` + `consumer.max-cache-message-size` | `receive-batch-size` 只对 `simple` 生效。吞吐 ≈ `thread-count × receive-batch-size ÷ 单次往返`。注意 `await-duration`/`invisible-duration` **不是**提速旋钮(长轮询等待 / 重投语义,与速度无关)。 ```bash # 大批量快速拉取(simple)——最大化消费吞吐的正解 MEM="-Xms8g -Xmx8g" ./scripts/start-consumer.sh \ --consumer.consumer-type=simple --consumer.receive-batch-size=256 \ --consumer.thread-count=300 --consumer.duration=1800 # 高并发推送(push)——thread-count 与 cache 要一起抬 MEM="-Xms8g -Xmx8g" ./scripts/start-consumer.sh \ --consumer.consumer-type=push --consumer.thread-count=300 \ --consumer.max-cache-message-count=8192 --consumer.max-cache-message-size=512MB ``` `simple` 的 ack 是逐条的,但走 **`ackAsync`**(同一 worker 的多条 ack 并发在途,不串行),`receive-batch-size` 调很大时 ack 数线性增长但影响有限。`consumer.max-inflight-ack` 限制每个 SimpleConsumer 的在途 ack 数——既限制内存(≈ 上限 × 消息大小),又保证 ack 在 `invisible-duration` 内完成、Broker 不重投,从而保证多节点集群**不重复消费**。置 `0` 关闭背压(ack 跟不上时有重投风险)。 > **多节点不重复消费。** 集群模式(默认,各节点同一 `consumer.group`)本身按消息级负载均衡——每条消息只投递给一个节点。异步 ack 设计保持这一点:一条消息**只有在 ack 成功后才计为已消费**,在途上限保证 ack 不超过 `invisible-duration`,避免 Broker 重投。广播模式(`consume-mode=broadcasting`)有意让每个节点消费 100%(通过每个实例独立消费组模拟),其"重复"是设计语义。 ## 📖 使用 ### 生产者 ```bash # 异步、不限速、1KB、200 线程、30 分钟 ./scripts/start-producer.sh \ --producer.send-mode=async --producer.tps-limit=0 \ --producer.message-size=1024 --producer.thread-count=200 --producer.duration=1800 # 自定义 Topic & 固定 5000 TPS ./scripts/start-producer.sh --producer.topic=my_topic --producer.tps-limit=5000 ``` | `send-mode` | 行为 | |---|---| | `sync` | 阻塞等待确认,可靠性最高,RT 最准 | | `async` | `sendAsync` + 回调,吞吐/可靠性均衡(**推荐**) | | `oneway` | 发射后即忘,无确认(见[设计说明](#-设计说明)) | | `batch` | 每周期提交 `batch-size` 条并等待 | | `transaction` | 预留 | ### 消费者 ```bash # Push、集群、100 线程 ./scripts/start-consumer.sh --consumer.consumer-type=push --consumer.thread-count=100 # Simple + SQL92 过滤 ./scripts/start-consumer.sh --consumer.consumer-type=simple \ --consumer.filter-type=sql92 --consumer.filter-expression="Tag='A'" ``` > **先起消费再起生产** —— 新消费组默认从最新位消费。 ## 📊 统计与报告 **实时(每秒):** ``` PTPS SendSucc SendFail ConsSucc ConsFail AvgRT MaxRT P50 P90 P95 P99 P999 MB/s Backlog FailR% 12345 1200034 12 1199500 5 2.31 45.20 1.95 3.10 4.02 6.88 12.40 15.20 5300 0.01 ``` **报告**(停止后在 `report/`):`pressure-<角色>-<时间戳>-<主机>.{csv,json}` —— 起止时间、时长、角色、Topic、消费组、线程数、消息大小、TPS、平均/最大 RT、P50–P999、吞吐、成功/失败计数、失败率。 ## 📈 监控 每个实例暴露 Prometheus 端点: ``` http://<压测机>:8081/actuator/prometheus ``` | 指标 | 类型 | 说明 | |---|---|---| | `pressure_producer_tps` | gauge | 生产者 msg/s | | `pressure_consumer_tps` | gauge | 消费者 msg/s | | `pressure_throughput_mbps` | gauge | 吞吐 MB/s | | `pressure_consumer_backlog` | gauge | 消息积压 | | `pressure_producer_send_success_total` | gauge | 累计发送成功 | | `pressure_producer_send_failure_total` | gauge | 累计发送失败 | | `pressure_consumer_consume_success_total` | gauge | 累计消费成功 | | `pressure_consumer_consume_failure_total` | gauge | 累计消费失败 | 同机跑两个实例 → 第二个加 `--server.port=8082`。 ## 🌐 分布式压测(6 台) 主机:`192.168.64.46 / .49`(消费) · `192.168.66.219 / .220 / .221 / .222`(生产)。 ```bash # 构建机:构建一次,分发 jar+配置+脚本到其余机器 for h in 192.168.64.49 192.168.66.219 192.168.66.220 192.168.66.221 192.168.66.222; do ssh user@$h "mkdir -p ~/mq-test-tool/{target,conf,scripts,logs,report}" scp target/rocketmq-pressure.jar user@$h:~/mq-test-tool/target/ scp conf/application.yml user@$h:~/mq-test-tool/conf/ scp scripts/*.sh user@$h:~/mq-test-tool/scripts/ done # 消费机(46、49)—— 同组 → 集群负载均衡 ./scripts/start-consumer.sh --consumer.thread-count=100 --consumer.duration=1900 # 生产机(219/220/221/222) ./scripts/start-producer.sh --producer.send-mode=async --producer.thread-count=200 --producer.duration=1800 # 停止(优雅,自动生成报告) ./scripts/stop.sh ``` ## 🛠 排障 | 现象 | 处理 | |---|---| | `mvn` 解析不到 `rocketmq-client-java` | Maven Central 当前到 `5.2.0`;保持即可,或私有 Nexus 有更高版本则改 `pom.xml` 的 `rocketmq-client-java.version` | | `endpoints should not be null` | 检查 `conf/application.yml` 的 `rocketmq.endpoint` 是否被加载 | | 发送失败持续增加 | 检查压测机到 `192.168.1.29:8080` 网络、Proxy 是否启动、ACL 是否需开启 | | 消费为 0 | **先起消费再起生产**;确认 Topic/消费组一致 | | 同机端口冲突 | 第二实例 `--server.port=8082` | | 无报告 | 检查 `report.enabled=true`、目录可写、`logs/` 是否有 `finalizing` 日志 | | OOM / GC 频繁 | 调大 `MEM`(默认 `-Xms4g -Xmx4g`),降低 `thread-count`/`batch-size`/`max-inflight`/`max-cache-message-size` —— 见 [性能调优](#性能调优与-jvm-资源16c16g--5gb) | ## 📌 设计说明 - **客户端版本 `5.2.0`** —— Broker 为 5.4.0;`rocketmq-client-java` 在 Maven Central 当前可解析至 `5.2.0`。官方兼容矩阵确认客户端 `5.0.0+` 可连接 Broker `5.4.0`(服务端向后兼容)。若私有仓库有更新版本,改 `pom.xml` 的属性即可,API 向前兼容。 - **广播模式** —— 5.x gRPC 客户端的 `PushConsumer`/`SimpleConsumer` **原生仅支持集群**(API 已移除 `MessageModel.BROADCASTING`)。本工具在 `broadcasting` 下为**每个实例生成独立消费组**(`--`),各实例独立消费全量,等价广播语义,与官方描述一致。 - **单向发送** —— 5.x `Producer` 接口不再提供 `sendOneway`;`OnewaySender` 用 `sendAsync` 发射后即忘(立即返回、无确认、时延记 0),保证跨版本可编译。 - **异常隔离** —— 各职责独立线程池;`NamedThreadFactory` 设置未捕获异常处理器,单线程异常仅记日志、绝不崩溃进程;单条消息异常被捕获并计入失败。 ## 🗺 路线图 - [ ] `TransactionSender` 实现(两阶段 + `TransactionChecker`) - [ ] `cluster-run.sh` 一键编排(分发 → 起消费 → 起生产 → 停止 → 回收报告) - [ ] 5.x 客户端开放原生批量 API 后接入 - [ ] 基于 JSON 报告的内置 HTML 仪表盘 ## 🤝 贡献 欢迎贡献!本项目遵循**阿里 Java 开发规范**与 SOLID 原则。 1. Fork 并开分支:`feat/<主题>` 或 `fix/<主题>` 2. 保持每类单一职责;完整 Javadoc + SLF4J 日志;禁止裸 `new Thread` 3. 确保 `mvn clean package` 通过(JDK 17) 4. 提交 PR 说明改动与理由 如遇编译/运行问题,请附上你的 `rocketmq-client-java` 版本,以便我们定位 API 差异。 ## 📄 许可证 基于 **Apache License, Version 2.0** 发布。详见 [LICENSE](LICENSE)。 ## 🙏 致谢 - [Apache RocketMQ](https://rocketmq.apache.org/) 及 5.x gRPC 客户端 - [HdrHistogram](https://github.com/HdrHistogram/HdrHistogram) 精确分位值 - [Spring Boot](https://spring.io/projects/spring-boot)、[Micrometer](https://micrometer.io/) ---
为需要可信数据、而非玩具演示的工程师而构建。