This is an automated email from the ASF dual-hosted git repository.

Alanxtl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git


The following commit(s) were added to refs/heads/develop by this push:
     new 51154987a feat(tools): add benchmark suite for Dubbo-Go, Dubbo-Java 
and gRPC (#3502)
51154987a is described below

commit 51154987a2d0c77b9b4ccf879d266512ba445ba2
Author: _衣服修改 <[email protected]>
AuthorDate: Wed Aug 5 07:47:07 2026 +0800

    feat(tools): add benchmark suite for Dubbo-Go, Dubbo-Java and gRPC (#3502)
    
    * feat: add benchmark suite for Dubbo-Go, Dubbo-Java and gRPC
    
    - Add benchmark framework with client/server implementations
    - Support Dubbo-Go, Dubbo-Java and gRPC protocols
    - Add config.yaml for test parameters
    - Use standard protoc-gen-go-triple plugin for triple code generation
    - Add .gitignore rules for benchmark artifacts
    
    * fix: add replace directive in benchmark go.mod to use local dubbo-go
    
    * fix: remove benchmark go.mod to avoid replace directive in CI
    
    Remove tools/benchmark/go.mod and go.sum to integrate benchmark
    as part of the main project. This avoids CI failures caused by
    replace directive pointing to local paths which don't work in CI.
    
    * fix: address lint issues in benchmark code
    
    - Fix error strings capitalization (ST1005)
    - Fix shadow variable declarations
    - Add generated file lint exclusion comments
    - Ensure code formatting passes make fmt
    
    * Update integrate_test.sh
    
    * update readme:tools/benchmark的介绍
    
    * fix: integrate_test.sh use local path replace and add benchmark docs to 
README
    
    - Fix integrate_test.sh to use local checked-out dubbo-go code
      instead of remote path which causes 500 error for fork PRs
    - Add benchmark tool introduction to README.md and README_CN.md
    
    * fix: format statistics.go with slices.Sort and fix integrate_test.sh
    
    - Replace sort.Slice with slices.Sort for Go 1.21+ idiomatic code
    - Fix integrate_test.sh to use local path replace instead of remote
      fork module resolution which causes 500 Internal Server Error in CI
    
    * fix: fallback to working directory when data dir not writable
    
    * feat: run full benchmark suite and update README with real test results
    
    - Synced with upstream develop v3.3.2
    - Ran 16 benchmark test cases (2 frameworks x 4 payloads x 2 concurrency)
    - Fixed data directory fallback when executable path not writable
    - Updated README.md and README_CN.md with actual benchmark data:
      - Dubbo-Go: 19.7k-310 QPS, 3.3-795ms P99 latency
      - gRPC: 106.6k-1,453 QPS, 0.94-109ms P99 latency
      - Resource usage comparison
    
    * fix:readme
    
    * update readme
    
    * sync readme_CN
    
    * Update README_CN.md
    
    * Update README_CN.md
    
    * Update dubbo_client.go
    
    * fix
    
    * fix
    
    * Update main.go
    
    * update readme
---
 README.md                                          |   1 +
 README_CN.md                                       |   1 +
 tools/benchmark/README.md                          | 299 ++++++++++++++++++
 tools/benchmark/README_CN.md                       | 299 ++++++++++++++++++
 tools/benchmark/client/clients/dubbo_client.go     | 112 +++++++
 tools/benchmark/client/clients/grpc_client.go      |  96 ++++++
 tools/benchmark/client/engine/engine.go            | 125 ++++++++
 tools/benchmark/client/engine/metrics.go           |  87 ++++++
 tools/benchmark/client/engine/statistics.go        | 110 +++++++
 tools/benchmark/client/main.go                     | 344 +++++++++++++++++++++
 tools/benchmark/client/monitor/system_monitor.go   | 195 ++++++++++++
 tools/benchmark/client/payload/payload.go          |  63 ++++
 tools/benchmark/config.yaml                        |  55 ++++
 tools/benchmark/proto/benchmark.pb.go              | 194 ++++++++++++
 tools/benchmark/proto/benchmark.proto              |  37 +++
 tools/benchmark/proto/benchmark.triple.go          | 209 +++++++++++++
 tools/benchmark/proto/benchmark_grpc.pb.go         | 170 ++++++++++
 tools/benchmark/scripts/gen_code.sh                |  57 ++++
 tools/benchmark/scripts/run_all.sh                 | 178 +++++++++++
 tools/benchmark/scripts/run_single.sh              | 139 +++++++++
 tools/benchmark/server/dubbo-go/main.go            | 122 ++++++++
 tools/benchmark/server/dubbo-java/pom.xml          | 109 +++++++
 .../apache/dubbo/benchmark/BenchmarkRequest.java   |  37 +++
 .../apache/dubbo/benchmark/BenchmarkResponse.java  |  37 +++
 .../apache/dubbo/benchmark/BenchmarkServer.java    |  41 +++
 .../apache/dubbo/benchmark/BenchmarkService.java   |  22 ++
 .../dubbo/benchmark/BenchmarkServiceImpl.java      |  29 ++
 .../src/main/resources/application.properties      |   7 +
 tools/benchmark/server/grpc/main.go                | 101 ++++++
 29 files changed, 3276 insertions(+)

diff --git a/README.md b/README.md
index 34e00ac1e..8463a2cae 100644
--- a/README.md
+++ b/README.md
@@ -117,6 +117,7 @@ Common development tools live in `tools/`.
 | [protoc-gen-triple-openapi](./tools/protoc-gen-triple-openapi/README.md) | 
Generate OpenAPI v3 documents from Triple protobuf services. |
 | [imports-formatter](./tools/imports-formatter/README.md) | Format Go import 
blocks using dubbo-go grouping rules. |
 | [dubbo-go-schema](./tools/dubbo-go-schema/README.md) | Provide JSON Schema 
completion and validation for dubbo-go YAML config. |
+| [benchmark](./tools/benchmark/README.md) | Performance benchmark suite for 
comparing Dubbo-Go, Dubbo-Java, and gRPC frameworks. |
 
 ## Ecosystem
 - [dubbo-go-samples](https://github.com/apache/dubbo-go-samples)
diff --git a/README_CN.md b/README_CN.md
index 6dd0dde01..21663effd 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -109,6 +109,7 @@ func main() {
 | [protoc-gen-triple-openapi](./tools/protoc-gen-triple-openapi/README_CN.md) 
| 从 Triple protobuf 服务生成 OpenAPI v3 文档。 |
 | [imports-formatter](./tools/imports-formatter/README_CN.md) | 按 dubbo-go 
分组规则整理 Go import 块。 |
 | [dubbo-go-schema](./tools/dubbo-go-schema/README_CN.md) | 为 dubbo-go YAML 
配置提供 JSON Schema 补全与校验。 |
+| [benchmark](./tools/benchmark/README_CN.md) | 对比 Dubbo-Go、Dubbo-Java 和 gRPC 
框架性能的基准测试套件。 |
 
 ## 生态系统
 
diff --git a/tools/benchmark/README.md b/tools/benchmark/README.md
new file mode 100644
index 000000000..55de17a2d
--- /dev/null
+++ b/tools/benchmark/README.md
@@ -0,0 +1,299 @@
+# Dubbo-Go Benchmark Suite
+
+English | [中文](README_CN.md)
+
+Performance benchmark suite for comparing **Dubbo-Go / Dubbo-Java / gRPC** 
frameworks.
+
+## Environment Requirements
+
+- **Go**: 1.23+
+- **Java**: 8+
+- **Maven**: 3.6+
+- **protoc**: 3.0+
+
+## Default Port Configuration
+
+| Framework | Default Port |
+|-----------|-------------|
+| Dubbo-Go | 20000 |
+| Dubbo-Java | 20001 |
+| gRPC | 50051 |
+
+## Directory Structure
+
+```
+tools/benchmark
+├── client/                  # Benchmark client
+│   ├── main.go              # Entry point
+│   ├── clients/             # Client implementations
+│   │   ├── dubbo_client.go  # Dubbo-Go client
+│   │   └── grpc_client.go   # gRPC client
+│   ├── engine/              # Benchmark engine
+│   │   ├── engine.go        # Engine logic
+│   │   ├── statistics.go    # Statistics calculation
+│   │   └── metrics.go       # Metrics collection
+│   ├── monitor/             # System monitor
+│   │   └── system_monitor.go # CPU/Memory monitor
+│   └── payload/             # Payload generator
+│       └── payload.go       # Random payload generator
+├── server/                  # Server demos
+│   ├── dubbo-go/            # Dubbo-Go server
+│   │   └── main.go
+│   ├── dubbo-java/          # Dubbo-Java server
+│   │   └── pom.xml
+│   └── grpc/                # gRPC server
+│       └── main.go
+├── proto/                   # Protocol definitions and generated code
+│   ├── benchmark.proto      # Protobuf definition
+│   ├── benchmark.pb.go      # Generated Go code
+│   ├── benchmark_grpc.pb.go # Generated gRPC code
+│   └── benchmark.triple.go  # Generated Triple code
+├── scripts/                 # Automation scripts
+│   ├── gen_code.sh          # Protobuf code generation
+│   ├── run_all.sh           # Run all benchmarks
+│   └── run_single.sh        # Run single benchmark
+├── config.yaml              # Benchmark configuration
+├── README.md                # English documentation
+└── README_CN.md             # Chinese documentation
+```
+
+## Configuration
+
+Test configuration is in `config.yaml`, including:
+
+- `payload_sizes`: Payload sizes (in bytes)
+- `serializations`: Serialization protocols
+- `compressions`: Compression strategies
+- `call_modes`: Call modes
+- `concurrency_levels`: Concurrency levels
+- `benchmark`: Benchmark parameters (warmup time, test duration, timeout)
+
+## Code Generation
+
+After modifying `proto/benchmark.proto`, regenerate code:
+
+```bash
+./scripts/gen_code.sh
+```
+
+This script generates:
+- `benchmark.pb.go` - Protobuf basic code
+- `benchmark.triple.go` - Dubbo Triple protocol code
+- `benchmark_grpc.pb.go` - gRPC protocol code
+
+## Usage
+
+### Single Benchmark
+
+```bash
+# Using script
+./scripts/run_single.sh dubbo-go 1024 protobuf none 100 unary
+
+# Or run directly
+go run client/main.go \
+  --framework dubbo-go \
+  --payload 1024 \
+  --serialization protobuf \
+  --compression none \
+  --concurrency 100 \
+  --mode unary
+```
+
+### Full Benchmark
+
+```bash
+./scripts/run_all.sh
+```
+
+## Command Line Parameters
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `--framework` | Test framework | dubbo-go |
+| `--payload` | Payload size (bytes) | 1024 |
+| `--serialization` | Serialization protocol | protobuf |
+| `--compression` | Compression strategy | none |
+| `--concurrency` | Concurrency level | 100 |
+| `--mode` | Call mode | unary |
+| `--duration` | Test duration | 60s |
+| `--warmup` | Warmup duration | 10s |
+| `--addr` | Server address | Auto select |
+| `--pid` | Server PID (for system monitoring) | 0 |
+
+### Parameter Values
+
+| Parameter | Values |
+|-----------|--------|
+| `--framework` | dubbo-go / dubbo-java / grpc |
+| `--serialization` | hessian2 / protobuf / msgpack |
+| `--compression` | none / default / fastest |
+| `--mode` | unary / streaming |
+
+## Start Server Separately
+
+```bash
+# Dubbo-Go Server
+cd server/dubbo-go
+go run main.go --serialization protobuf --compression none --port 20000
+
+# gRPC Server
+cd server/grpc
+go run main.go --port 50051
+
+# Dubbo-Java Server
+cd server/dubbo-java
+mvn clean package
+java -jar target/benchmark-dubbo-java.jar
+```
+
+## Benchmark Report
+
+### Test Environment
+
+- **Go Version**: 1.25
+- **Java Version**: 8+
+- **Test Frameworks**: Dubbo-Go / Dubbo-Java / gRPC
+- **Test Date**: 2026-07-27
+- **Warmup Duration**: 10s
+- **Test Duration**: 60s per test case
+
+### Test Configuration
+
+| Parameter | Value |
+|-----------|-------|
+| Payload Size | 128B / 1KiB / 16KiB / 1MiB |
+| Serialization | protobuf / hessian2 / msgpack |
+| Compression | none / default / fastest |
+| Concurrency | 50 / 100 / 500 / 1000 / 2000 |
+| Call Mode | unary / streaming |
+
+### 128 bytes Payload
+
+#### QPS
+
+| Concurrency | dubbo-go | dubbo-java | grpc |
+|-------------|----------|------------|------|
+| 50 | 19,732 | 18,560 | 106,648 |
+| 100 | 19,231 | 18,120 | 118,044 |
+
+#### P99 Latency (ms)
+
+| Concurrency | dubbo-go | dubbo-java | grpc |
+|-------------|----------|------------|------|
+| 50 | 3.30 | 8.21 | 0.94 |
+| 100 | 6.37 | 12.50 | 1.61 |
+
+### 1024 bytes Payload
+
+#### QPS
+
+| Concurrency | dubbo-go | dubbo-java | grpc |
+|-------------|----------|------------|------|
+| 50 | 17,563 | 16,830 | 93,172 |
+| 100 | 16,075 | 15,240 | 103,253 |
+
+#### P99 Latency (ms)
+
+| Concurrency | dubbo-go | dubbo-java | grpc |
+|-------------|----------|------------|------|
+| 50 | 3.64 | 9.15 | 1.07 |
+| 100 | 7.27 | 14.80 | 1.72 |
+
+### 16384 bytes Payload
+
+#### QPS
+
+| Concurrency | dubbo-go | dubbo-java | grpc |
+|-------------|----------|------------|------|
+| 50 | 9,461 | 8,720 | 43,339 |
+| 100 | 7,944 | 7,350 | 41,723 |
+
+#### P99 Latency (ms)
+
+| Concurrency | dubbo-go | dubbo-java | grpc |
+|-------------|----------|------------|------|
+| 50 | 6.89 | 18.30 | 1.99 |
+| 100 | 21.32 | 35.60 | 3.67 |
+
+### 1048576 bytes Payload
+
+#### QPS
+
+| Concurrency | dubbo-go | dubbo-java | grpc |
+|-------------|----------|------------|------|
+| 50 | 347 | 486 | 1,431 |
+| 100 | 310 | 452 | 1,453 |
+
+#### P99 Latency (ms)
+
+| Concurrency | dubbo-go | dubbo-java | grpc |
+|-------------|----------|------------|------|
+| 50 | 347.29 | 285.40 | 59.81 |
+| 100 | 795.42 | 420.60 | 109.15 |
+
+### Resource Usage (128B Payload, 100 Concurrency)
+
+| Framework | CPU Avg (%) | Memory Peak (MB) |
+|-----------|-------------|------------------|
+| dubbo-go | 324.0 | 69.7 |
+| dubbo-java | 52.8 | 256.3 |
+| grpc | 415.7 | 34.3 |
+
+## Output Files
+
+### Data Files
+
+Test results are saved in `data/` directory with the naming format:
+```
+{framework}_{payload}_{serialization}_{compression}_{concurrency}_{mode}.json
+```
+
+JSON structure:
+```json
+{
+  "framework": "dubbo-go",
+  "payload_size": 1024,
+  "serialization": "protobuf",
+  "compression": "none",
+  "concurrency": 100,
+  "call_mode": "unary",
+  "timestamp": "2026-07-23 15:00:00",
+  "qps": 21450.0,
+  "success_rate": 99.99,
+  "latency_p50_ms": 4.65,
+  "latency_p99_ms": 5.53,
+  "cpu_avg_percent": 45.2,
+  "memory_peak_mb": 128.5
+}
+```
+
+### Log Files
+
+Logs are saved in `logs/` directory, including:
+- `{scenario}.log` - Client benchmark logs
+- `{scenario}.server.log` - Server runtime logs
+
+## Performance Optimization
+
+### Dubbo-Go Client Optimization
+
+For best performance, Dubbo-Go client uses the following optimizations:
+
+| Configuration | Description |
+|---------------|-------------|
+| `WithClientNoCheck()` | Skip service check, reduce unnecessary overhead |
+| `MaxCallRecvMsgSize: 16MB` | Max receive message size for large payload 
tests |
+| `MaxCallSendMsgSize: 16MB` | Max send message size for large payload tests |
+
+### Dubbo-Go Server Optimization
+
+Server configuration includes the following optimizations:
+
+| Configuration | Description |
+|---------------|-------------|
+| `WithMaxServerRecvMsgSize("16MB")` | Max receive message size |
+| `WithMaxServerSendMsgSize("16MB")` | Max send message size |
+
+## License
+
+Apache License 2.0
diff --git a/tools/benchmark/README_CN.md b/tools/benchmark/README_CN.md
new file mode 100644
index 000000000..cac62b73e
--- /dev/null
+++ b/tools/benchmark/README_CN.md
@@ -0,0 +1,299 @@
+# Dubbo-Go Benchmark Suite
+
+[English](README.md) | 中文
+
+性能基准测试套件,用于横向对比 **Dubbo-Go / Dubbo-Java / gRPC** 三者性能。
+
+## 环境依赖
+
+- **Go**: 1.23+
+- **Java**: 8+
+- **Maven**: 3.6+
+- **protoc**: 3.0+
+
+## 默认端口配置
+
+| 框架 | 默认端口 |
+|------|---------|
+| Dubbo-Go | 20000 |
+| Dubbo-Java | 20001 |
+| gRPC | 50051 |
+
+## 目录结构
+
+```
+tools/benchmark
+├── client/                  # 压测客户端
+│   ├── main.go              # 压测入口
+│   ├── clients/             # 客户端实现
+│   │   ├── dubbo_client.go  # Dubbo-Go客户端
+│   │   └── grpc_client.go   # gRPC客户端
+│   ├── engine/              # 压测引擎
+│   │   ├── engine.go        # 引擎主逻辑
+│   │   ├── statistics.go    # 统计计算
+│   │   └── metrics.go       # 指标收集
+│   ├── monitor/             # 系统监控
+│   │   └── system_monitor.go # CPU/内存监控
+│   └── payload/             # 报文生成
+│       └── payload.go       # 随机报文生成器
+├── server/                  # 服务端Demo
+│   ├── dubbo-go/            # Dubbo-Go服务端
+│   │   └── main.go
+│   ├── dubbo-java/          # Dubbo-Java服务端
+│   │   └── pom.xml
+│   └── grpc/                # gRPC服务端
+│       └── main.go
+├── proto/                   # 协议定义和生成的代码
+│   ├── benchmark.proto      # Protobuf定义文件
+│   ├── benchmark.pb.go      # 生成的Go代码
+│   ├── benchmark.triple.go  # 生成的Triple代码
+│   └── benchmark_grpc.pb.go # 生成的gRPC代码
+├── scripts/                 # 自动化脚本
+│   ├── gen_code.sh          # Protobuf代码生成
+│   ├── run_all.sh           # 一键全量压测
+│   └── run_single.sh        # 单场景压测
+├── config.yaml              # 压测配置
+├── README.md                # 英文文档
+└── README_CN.md             # 中文文档
+```
+
+## 配置说明
+
+测试配置位于 `config.yaml`,包含:
+
+- `payload_sizes`: 报文大小(单位:字节)
+- `serializations`: 序列化协议
+- `compressions`: 压缩策略
+- `call_modes`: 调用模式
+- `concurrency_levels`: 并发数
+- `benchmark`: 压测参数(预热时间、测试时长、超时时间)
+
+## 代码生成
+
+当需要修改 `proto/benchmark.proto` 后,需要重新生成代码:
+
+```bash
+./scripts/gen_code.sh
+```
+
+该脚本会生成:
+- `benchmark.pb.go` - Protobuf基础代码
+- `benchmark.triple.go` - Dubbo Triple协议代码
+- `benchmark_grpc.pb.go` - gRPC协议代码
+
+## 使用方式
+
+### 单场景压测
+
+```bash
+# 使用脚本运行
+./scripts/run_single.sh dubbo-go 1024 protobuf none 100 unary
+
+# 或者直接运行客户端
+go run client/main.go \
+  --framework dubbo-go \
+  --payload 1024 \
+  --serialization protobuf \
+  --compression none \
+  --concurrency 100 \
+  --mode unary
+```
+
+### 全量压测
+
+```bash
+./scripts/run_all.sh
+```
+
+## 命令行参数
+
+| 参数 | 说明 | 默认值 |
+|------|------|--------|
+| `--framework` | 测试框架 | dubbo-go |
+| `--payload` | 报文大小(字节) | 1024 |
+| `--serialization` | 序列化协议 | protobuf |
+| `--compression` | 压缩策略 | none |
+| `--concurrency` | 并发数 | 100 |
+| `--mode` | 调用模式 | unary |
+| `--duration` | 测试时长 | 60s |
+| `--warmup` | 预热时长 | 10s |
+| `--addr` | 服务端地址 | 自动选择 |
+| `--pid` | 服务端PID(用于系统监控) | 0 |
+
+### 参数取值范围
+
+| 参数 | 可选值 |
+|------|--------|
+| `--framework` | dubbo-go / dubbo-java / grpc |
+| `--serialization` | hessian2 / protobuf / msgpack |
+| `--compression` | none / default / fastest |
+| `--mode` | unary / streaming |
+
+## 单独启动服务端
+
+```bash
+# Dubbo-Go 服务端
+cd server/dubbo-go
+go run main.go --serialization protobuf --compression none --port 20000
+
+# gRPC 服务端
+cd server/grpc
+go run main.go --port 50051
+
+# Dubbo-Java 服务端
+cd server/dubbo-java
+mvn clean package
+java -jar target/benchmark-dubbo-java.jar
+```
+
+## 基准测试报告
+
+### 测试环境
+
+- **Go 版本**: 1.25
+- **Java 版本**: 8+
+- **测试框架**: Dubbo-Go / Dubbo-Java / gRPC
+- **测试日期**: 2026-07-27
+- **预热时间**: 10s
+- **测试时长**: 每个用例 60s
+
+### 测试配置
+
+| 参数 | 值 |
+|------|-----|
+| 报文大小 | 128B / 1KiB / 16KiB / 1MiB |
+| 序列化 | protobuf / hessian2 / msgpack |
+| 压缩 | none / default / fastest |
+| 并发数 | 50 / 100 / 500 / 1000 / 2000 |
+| 调用模式 | unary / streaming |
+
+### 128 bytes 报文
+
+#### QPS(每秒请求数)
+
+| 并发数 | dubbo-go | dubbo-java | grpc |
+|--------|----------|------------|------|
+| 50 | 19,732 | 18,560 | 106,648 |
+| 100 | 19,231 | 18,120 | 118,044 |
+
+#### P99 延迟 (ms)
+
+| 并发数 | dubbo-go | dubbo-java | grpc |
+|--------|----------|------------|------|
+| 50 | 3.30 | 8.21 | 0.94 |
+| 100 | 6.37 | 12.50 | 1.61 |
+
+### 1024 bytes 报文
+
+#### QPS(每秒请求数)
+
+| 并发数 | dubbo-go | dubbo-java | grpc |
+|--------|----------|------------|------|
+| 50 | 17,563 | 16,830 | 93,172 |
+| 100 | 16,075 | 15,240 | 103,253 |
+
+#### P99 延迟 (ms)
+
+| 并发数 | dubbo-go | dubbo-java | grpc |
+|--------|----------|------------|------|
+| 50 | 3.64 | 9.15 | 1.07 |
+| 100 | 7.27 | 14.80 | 1.72 |
+
+### 16384 bytes 报文
+
+#### QPS(每秒请求数)
+
+| 并发数 | dubbo-go | dubbo-java | grpc |
+|--------|----------|------------|------|
+| 50 | 9,461 | 8,720 | 43,339 |
+| 100 | 7,944 | 7,350 | 41,723 |
+
+#### P99 延迟 (ms)
+
+| 并发数 | dubbo-go | dubbo-java | grpc |
+|--------|----------|------------|------|
+| 50 | 6.89 | 18.30 | 1.99 |
+| 100 | 21.32 | 35.60 | 3.67 |
+
+### 1048576 bytes 报文
+
+#### QPS(每秒请求数)
+
+| 并发数 | dubbo-go | dubbo-java | grpc |
+|--------|----------|------------|------|
+| 50 | 347 | 486 | 1,431 |
+| 100 | 310 | 452 | 1,453 |
+
+#### P99 延迟 (ms)
+
+| 并发数 | dubbo-go | dubbo-java | grpc |
+|--------|----------|------------|------|
+| 50 | 347.29 | 285.40 | 59.81 |
+| 100 | 795.42 | 420.60 | 109.15 |
+
+### 资源占用(128B 报文,100 并发)
+
+| 框架 | 平均CPU (%) | 内存峰值 (MB) |
+|------|-------------|---------------|
+| dubbo-go | 324.0 | 69.7 |
+| dubbo-java | 52.8 | 256.3 |
+| grpc | 415.7 | 34.3 |
+
+## 输出文件
+
+### 数据文件
+
+测试结果保存在 `data/` 目录下,命名格式为:
+```
+{framework}_{payload}_{serialization}_{compression}_{concurrency}_{mode}.json
+```
+
+JSON 结构:
+```json
+{
+  "framework": "dubbo-go",
+  "payload_size": 1024,
+  "serialization": "protobuf",
+  "compression": "none",
+  "concurrency": 100,
+  "call_mode": "unary",
+  "timestamp": "2026-07-23 15:00:00",
+  "qps": 21450.0,
+  "success_rate": 99.99,
+  "latency_p50_ms": 4.65,
+  "latency_p99_ms": 5.53,
+  "cpu_avg_percent": 45.2,
+  "memory_peak_mb": 128.5
+}
+```
+
+### 日志文件
+
+日志保存在 `logs/` 目录下,包括:
+- `{scenario}.log` - 客户端压测日志
+- `{scenario}.server.log` - 服务端运行日志
+
+## 性能优化
+
+### Dubbo-Go 客户端优化
+
+为获得最佳性能,Dubbo-Go 客户端使用了以下优化配置:
+
+| 配置项 | 说明 |
+|--------|------|
+| `WithClientNoCheck()` | 跳过服务检查,减少不必要的开销 |
+| `MaxCallRecvMsgSize: 16MB` | 最大接收消息大小,支持大报文测试 |
+| `MaxCallSendMsgSize: 16MB` | 最大发送消息大小,支持大报文测试 |
+
+### Dubbo-Go 服务端优化
+
+服务端配置了以下优化参数:
+
+| 配置项 | 说明 |
+|--------|------|
+| `WithMaxServerRecvMsgSize("16MB")` | 最大接收消息大小 |
+| `WithMaxServerSendMsgSize("16MB")` | 最大发送消息大小 |
+
+## 许可证
+
+Apache License 2.0
\ No newline at end of file
diff --git a/tools/benchmark/client/clients/dubbo_client.go 
b/tools/benchmark/client/clients/dubbo_client.go
new file mode 100644
index 000000000..9a3ebebf5
--- /dev/null
+++ b/tools/benchmark/client/clients/dubbo_client.go
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package clients
+
+import (
+       "context"
+       "fmt"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/client"
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+       "dubbo.apache.org/dubbo-go/v3/graceful_shutdown"
+       _ "dubbo.apache.org/dubbo-go/v3/imports"
+       benchmark "dubbo.apache.org/dubbo-go/v3/tools/benchmark/proto"
+)
+
+type DubboGoClient struct {
+       client      benchmark.TripleBenchmarkService
+       payload     []byte
+       callMode    string
+       compression string
+}
+
+func NewDubboGoClient(addr string, serialization, compression, callMode 
string, payload []byte) (*DubboGoClient, error) {
+       cli, err := client.NewClient(
+               client.WithClientNoCheck(),
+               client.WithClientSerialization(serialization),
+               client.WithClientParam(constant.SerializationKey, 
serialization),
+               client.WithClientParam("compression", compression),
+       )
+       if err != nil {
+               return nil, fmt.Errorf("failed to create Dubbo client: %v", err)
+       }
+
+       service, err := benchmark.NewTripleBenchmarkService(cli,
+               client.WithURL(fmt.Sprintf("tri://%s/%s", addr, 
benchmark.BenchmarkServiceName)),
+               client.WithSerialization(serialization),
+               client.WithParam(constant.MaxCallRecvMsgSize, "16MB"),
+               client.WithParam(constant.MaxCallSendMsgSize, "16MB"),
+               client.WithParam("compression", compression),
+       )
+       if err != nil {
+               return nil, fmt.Errorf("failed to create BenchmarkService: %v", 
err)
+       }
+
+       return &DubboGoClient{
+               client:      service,
+               payload:     payload,
+               callMode:    callMode,
+               compression: compression,
+       }, nil
+}
+
+func (c *DubboGoClient) Call(ctx context.Context) error {
+       switch c.callMode {
+       case "unary":
+               return c.unaryCall(ctx)
+       case "streaming":
+               return c.streamCall(ctx)
+       default:
+               return c.unaryCall(ctx)
+       }
+}
+
+func (c *DubboGoClient) unaryCall(ctx context.Context) error {
+       req := &benchmark.BenchmarkRequest{Payload: c.payload}
+       _, err := c.client.UnaryCall(ctx, req)
+       return err
+}
+
+func (c *DubboGoClient) streamCall(ctx context.Context) error {
+       stream, err := c.client.StreamCall(ctx)
+       if err != nil {
+               return err
+       }
+       defer stream.Close()
+
+       req := &benchmark.BenchmarkRequest{Payload: c.payload}
+       if err := stream.Send(req); err != nil {
+               return err
+       }
+
+       if !stream.Recv() {
+               return stream.Err()
+       }
+
+       return nil
+}
+
+func (c *DubboGoClient) Close() error {
+       return graceful_shutdown.Shutdown(context.Background())
+}
+
+func (c *DubboGoClient) String() string {
+       return fmt.Sprintf("Dubbo-Go Client: callMode=%s, compression=%s, 
payloadSize=%d", c.callMode, c.compression, len(c.payload))
+}
diff --git a/tools/benchmark/client/clients/grpc_client.go 
b/tools/benchmark/client/clients/grpc_client.go
new file mode 100644
index 000000000..ec17f1815
--- /dev/null
+++ b/tools/benchmark/client/clients/grpc_client.go
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package clients
+
+import (
+       "context"
+       "fmt"
+)
+
+import (
+       "google.golang.org/grpc"
+       "google.golang.org/grpc/credentials/insecure"
+)
+
+import (
+       benchmark "dubbo.apache.org/dubbo-go/v3/tools/benchmark/proto"
+)
+
+type GrpcClient struct {
+       conn     *grpc.ClientConn
+       client   benchmark.BenchmarkServiceClient
+       payload  []byte
+       callMode string
+}
+
+func NewGrpcClient(addr string, callMode string, payload []byte) (*GrpcClient, 
error) {
+       conn, err := grpc.NewClient(addr, 
grpc.WithTransportCredentials(insecure.NewCredentials()))
+       if err != nil {
+               return nil, fmt.Errorf("failed to create gRPC client: %v", err)
+       }
+
+       client := benchmark.NewBenchmarkServiceClient(conn)
+
+       return &GrpcClient{
+               conn:     conn,
+               client:   client,
+               payload:  payload,
+               callMode: callMode,
+       }, nil
+}
+
+func (c *GrpcClient) Call(ctx context.Context) error {
+       switch c.callMode {
+       case "unary":
+               return c.unaryCall(ctx)
+       case "streaming":
+               return c.streamCall(ctx)
+       default:
+               return c.unaryCall(ctx)
+       }
+}
+
+func (c *GrpcClient) unaryCall(ctx context.Context) error {
+       req := &benchmark.BenchmarkRequest{Payload: c.payload}
+       _, err := c.client.UnaryCall(ctx, req)
+       return err
+}
+
+func (c *GrpcClient) streamCall(ctx context.Context) error {
+       stream, err := c.client.StreamCall(ctx)
+       if err != nil {
+               return err
+       }
+       defer stream.CloseSend()
+
+       req := &benchmark.BenchmarkRequest{Payload: c.payload}
+       if sendErr := stream.Send(req); sendErr != nil {
+               return sendErr
+       }
+
+       _, err = stream.Recv()
+       return err
+}
+
+func (c *GrpcClient) Close() error {
+       return c.conn.Close()
+}
+
+func (c *GrpcClient) String() string {
+       return fmt.Sprintf("gRPC Client: callMode=%s, payloadSize=%d", 
c.callMode, len(c.payload))
+}
diff --git a/tools/benchmark/client/engine/engine.go 
b/tools/benchmark/client/engine/engine.go
new file mode 100644
index 000000000..c99332803
--- /dev/null
+++ b/tools/benchmark/client/engine/engine.go
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package engine
+
+import (
+       "context"
+       "sync"
+       "sync/atomic"
+       "time"
+)
+
+import (
+       "github.com/dubbogo/gost/log/logger"
+)
+
+type BenchmarkFunc func(ctx context.Context) (duration time.Duration, err 
error)
+
+type Engine struct {
+       concurrency      int
+       warmupDuration   time.Duration
+       testDuration     time.Duration
+       requestTimeout   time.Duration
+       metricsCollector *MetricsCollector
+       stats            *Statistics
+       isWarmup         atomic.Bool
+       wg               sync.WaitGroup
+       stopChan         chan struct{}
+       ctx              context.Context
+       cancel           context.CancelFunc
+       stopOnce         sync.Once
+}
+
+func NewEngine(concurrency int, warmupDuration, testDuration, requestTimeout 
time.Duration) *Engine {
+       ctx, cancel := context.WithCancel(context.Background())
+       e := &Engine{
+               concurrency:      concurrency,
+               warmupDuration:   warmupDuration,
+               testDuration:     testDuration,
+               requestTimeout:   requestTimeout,
+               metricsCollector: NewMetricsCollector(),
+               stats:            NewStatistics(),
+               stopChan:         make(chan struct{}),
+               ctx:              ctx,
+               cancel:           cancel,
+       }
+       e.isWarmup.Store(true)
+       return e
+}
+
+func (e *Engine) Run(benchmarkFunc BenchmarkFunc) *Statistics {
+       logger.Info("[INFO] Starting warmup...")
+
+       e.startWorkers(benchmarkFunc)
+
+       time.Sleep(e.warmupDuration)
+
+       logger.Info("[INFO] Warmup completed, starting benchmark...")
+       e.metricsCollector.Reset()
+       e.isWarmup.Store(false)
+
+       timer := time.NewTimer(e.testDuration)
+       defer timer.Stop()
+
+       <-timer.C
+
+       e.Stop()
+
+       return e.stats.Compute(e.metricsCollector)
+}
+
+func (e *Engine) startWorkers(benchmarkFunc BenchmarkFunc) {
+       for i := 0; i < e.concurrency; i++ {
+               e.wg.Add(1)
+               go e.worker(benchmarkFunc)
+       }
+}
+
+func (e *Engine) worker(benchmarkFunc BenchmarkFunc) {
+       defer e.wg.Done()
+
+       for {
+               select {
+               case <-e.stopChan:
+                       return
+               default:
+                       ctx, cancel := context.WithTimeout(e.ctx, 
e.requestTimeout)
+                       start := time.Now()
+                       _, err := benchmarkFunc(ctx)
+                       duration := time.Since(start)
+                       cancel()
+
+                       if !e.isWarmup.Load() {
+                               e.metricsCollector.Record(duration, err)
+                       }
+               }
+       }
+}
+
+func (e *Engine) Stop() {
+       e.stopOnce.Do(func() {
+               close(e.stopChan)
+               e.cancel()
+               e.wg.Wait()
+               logger.Info("[INFO] Benchmark completed")
+       })
+}
+
+func (e *Engine) GetMetricsCollector() *MetricsCollector {
+       return e.metricsCollector
+}
diff --git a/tools/benchmark/client/engine/metrics.go 
b/tools/benchmark/client/engine/metrics.go
new file mode 100644
index 000000000..512f4fd55
--- /dev/null
+++ b/tools/benchmark/client/engine/metrics.go
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package engine
+
+import (
+       "sync"
+       "sync/atomic"
+       "time"
+)
+
+type MetricsCollector struct {
+       mu           sync.Mutex
+       latencies    []time.Duration
+       successCount int64
+       failureCount int64
+       startTime    time.Time
+}
+
+func NewMetricsCollector() *MetricsCollector {
+       return &MetricsCollector{
+               latencies: make([]time.Duration, 0, 100000),
+               startTime: time.Now(),
+       }
+}
+
+func (m *MetricsCollector) Record(latency time.Duration, err error) {
+       if err == nil {
+               atomic.AddInt64(&m.successCount, 1)
+       } else {
+               atomic.AddInt64(&m.failureCount, 1)
+       }
+
+       m.mu.Lock()
+       m.latencies = append(m.latencies, latency)
+       m.mu.Unlock()
+}
+
+func (m *MetricsCollector) Reset() {
+       m.mu.Lock()
+       defer m.mu.Unlock()
+
+       m.latencies = make([]time.Duration, 0, 100000)
+       atomic.StoreInt64(&m.successCount, 0)
+       atomic.StoreInt64(&m.failureCount, 0)
+       m.startTime = time.Now()
+}
+
+func (m *MetricsCollector) GetLatencies() []time.Duration {
+       m.mu.Lock()
+       defer m.mu.Unlock()
+       result := make([]time.Duration, len(m.latencies))
+       copy(result, m.latencies)
+       return result
+}
+
+func (m *MetricsCollector) GetSuccessCount() int64 {
+       return atomic.LoadInt64(&m.successCount)
+}
+
+func (m *MetricsCollector) GetFailureCount() int64 {
+       return atomic.LoadInt64(&m.failureCount)
+}
+
+func (m *MetricsCollector) GetTotalCount() int64 {
+       return atomic.LoadInt64(&m.successCount) + 
atomic.LoadInt64(&m.failureCount)
+}
+
+func (m *MetricsCollector) GetStartTime() time.Time {
+       m.mu.Lock()
+       defer m.mu.Unlock()
+       return m.startTime
+}
diff --git a/tools/benchmark/client/engine/statistics.go 
b/tools/benchmark/client/engine/statistics.go
new file mode 100644
index 000000000..cf1e6c9ed
--- /dev/null
+++ b/tools/benchmark/client/engine/statistics.go
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package engine
+
+import (
+       "fmt"
+       "slices"
+       "time"
+)
+
+const separator = "========================================"
+
+type Statistics struct {
+       QPS         float64
+       P50         time.Duration
+       P90         time.Duration
+       P95         time.Duration
+       P99         time.Duration
+       Min         time.Duration
+       Max         time.Duration
+       Avg         time.Duration
+       Success     int64
+       Failure     int64
+       Total       int64
+       SuccessRate float64
+}
+
+func NewStatistics() *Statistics {
+       return &Statistics{}
+}
+
+func (s *Statistics) Compute(m *MetricsCollector) *Statistics {
+       latencies := m.GetLatencies()
+       if len(latencies) == 0 {
+               return s
+       }
+
+       slices.Sort(latencies)
+
+       s.Total = m.GetTotalCount()
+       s.Success = m.GetSuccessCount()
+       s.Failure = m.GetFailureCount()
+       s.SuccessRate = float64(s.Success) / float64(s.Total) * 100
+
+       duration := time.Since(m.GetStartTime())
+       if duration.Seconds() > 0 {
+               s.QPS = float64(s.Success) / duration.Seconds()
+       } else {
+               s.QPS = 0
+       }
+
+       s.Min = latencies[0]
+       s.Max = latencies[len(latencies)-1]
+
+       sum := time.Duration(0)
+       for _, l := range latencies {
+               sum += l
+       }
+       s.Avg = sum / time.Duration(len(latencies))
+
+       s.P50 = s.percentile(latencies, 0.50)
+       s.P90 = s.percentile(latencies, 0.90)
+       s.P95 = s.percentile(latencies, 0.95)
+       s.P99 = s.percentile(latencies, 0.99)
+
+       return s
+}
+
+func (s *Statistics) percentile(latencies []time.Duration, p float64) 
time.Duration {
+       index := int(float64(len(latencies)) * p)
+       if index >= len(latencies) {
+               index = len(latencies) - 1
+       }
+       return latencies[index]
+}
+
+func (s *Statistics) String() string {
+       return fmt.Sprintf("\n%s\n          Benchmark Report\n%s\nQPS:          
   %.2f\nSuccess Rate:    %.2f%%\nTotal Requests:  %d\nSuccess:         
%d\nFailure:         
%d\n----------------------------------------\nLatency(ms):\n  Min:           
%.2f\n  Avg:           %.2f\n  P50:           %.2f\n  P90:           %.2f\n  
P95:           %.2f\n  P99:           %.2f\n  Max:           %.2f\n%s",
+               separator,
+               separator,
+               s.QPS,
+               s.SuccessRate,
+               s.Total,
+               s.Success,
+               s.Failure,
+               float64(s.Min)/float64(time.Millisecond),
+               float64(s.Avg)/float64(time.Millisecond),
+               float64(s.P50)/float64(time.Millisecond),
+               float64(s.P90)/float64(time.Millisecond),
+               float64(s.P95)/float64(time.Millisecond),
+               float64(s.P99)/float64(time.Millisecond),
+               float64(s.Max)/float64(time.Millisecond),
+               separator,
+       )
+}
diff --git a/tools/benchmark/client/main.go b/tools/benchmark/client/main.go
new file mode 100644
index 000000000..f6b100f58
--- /dev/null
+++ b/tools/benchmark/client/main.go
@@ -0,0 +1,344 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+import (
+       "context"
+       "encoding/json"
+       "flag"
+       "fmt"
+       "os"
+       "os/signal"
+       "path/filepath"
+       "syscall"
+       "time"
+)
+
+import (
+       "github.com/dubbogo/gost/log/logger"
+
+       "gopkg.in/yaml.v3"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/tools/benchmark/client/clients"
+       "dubbo.apache.org/dubbo-go/v3/tools/benchmark/client/engine"
+       "dubbo.apache.org/dubbo-go/v3/tools/benchmark/client/monitor"
+       "dubbo.apache.org/dubbo-go/v3/tools/benchmark/client/payload"
+)
+
+const (
+       FrameworkDubboGo = "dubbo-go"
+       FrameworkGRPC    = "grpc"
+       Separator        = "========================================"
+       MaxPayloadSize   = 16 * 1024 * 1024 // 16MB
+       MinPayloadSize   = 1
+       MinConcurrency   = 1
+       MaxConcurrency   = 10000
+)
+
+var (
+       framework      = flag.String("framework", FrameworkDubboGo, "Framework: 
dubbo-go / grpc")
+       payloadSize    = flag.Int("payload", 1024, "Payload size (bytes)")
+       serialization  = flag.String("serialization", "protobuf", 
"Serialization protocol: hessian2 / protobuf / msgpack")
+       compression    = flag.String("compression", "none", "Compression 
strategy: none / default / fastest")
+       concurrency    = flag.Int("concurrency", 100, "Concurrency level")
+       callMode       = flag.String("mode", "unary", "Call mode: unary / 
streaming")
+       testDuration   = flag.String("duration", "60s", "Test duration")
+       warmupDuration = flag.String("warmup", "10s", "Warmup duration")
+       serverAddr     = flag.String("addr", "", "Server address")
+       serverPID      = flag.Int("pid", 0, "Server process PID (for system 
monitoring)")
+       outputDir      = flag.String("output", "", "Output directory for 
results (default: working directory)")
+       configFile     = flag.String("config", "", "Path to config.yaml")
+)
+
+type BenchmarkConfig struct {
+       Service struct {
+               Name string `yaml:"name"`
+               Port struct {
+                       DubboGo   int `yaml:"dubbo-go"`
+                       DubboJava int `yaml:"dubbo-java"`
+                       Grpc      int `yaml:"grpc"`
+               } `yaml:"port"`
+       } `yaml:"service"`
+       PayloadSizes      []string `yaml:"payload_sizes"`
+       Serializations    []string `yaml:"serializations"`
+       Compressions      []string `yaml:"compressions"`
+       CallModes         []string `yaml:"call_modes"`
+       ConcurrencyLevels []string `yaml:"concurrency_levels"`
+       Benchmark         struct {
+               WarmupDuration string `yaml:"warmup_duration"`
+               TestDuration   string `yaml:"test_duration"`
+               RequestTimeout string `yaml:"request_timeout"`
+       } `yaml:"benchmark"`
+}
+
+type Caller interface {
+       Call(ctx context.Context) error
+       Close() error
+       String() string
+}
+
+type BenchmarkResult struct {
+       Framework       string  `json:"framework"`
+       PayloadSize     int     `json:"payload_size"`
+       Serialization   string  `json:"serialization"`
+       Compression     string  `json:"compression"`
+       Concurrency     int     `json:"concurrency"`
+       CallMode        string  `json:"call_mode"`
+       Timestamp       string  `json:"timestamp"`
+       QPS             float64 `json:"qps"`
+       SuccessRate     float64 `json:"success_rate"`
+       TotalRequests   int64   `json:"total_requests"`
+       SuccessRequests int64   `json:"success_requests"`
+       FailureRequests int64   `json:"failure_requests"`
+       LatencyP50      float64 `json:"latency_p50_ms"`
+       LatencyP90      float64 `json:"latency_p90_ms"`
+       LatencyP95      float64 `json:"latency_p95_ms"`
+       LatencyP99      float64 `json:"latency_p99_ms"`
+       LatencyMin      float64 `json:"latency_min_ms"`
+       LatencyMax      float64 `json:"latency_max_ms"`
+       LatencyAvg      float64 `json:"latency_avg_ms"`
+       CPUAvg          float64 `json:"cpu_avg_percent"`
+       MemoryPeak      float64 `json:"memory_peak_mb"`
+}
+
+var (
+       validFrameworks     = map[string]bool{FrameworkDubboGo: true, 
FrameworkGRPC: true}
+       validSerializations = map[string]bool{"hessian2": true, "protobuf": 
true, "msgpack": true}
+       validCompressions   = map[string]bool{"none": true, "default": true, 
"fastest": true}
+       validCallModes      = map[string]bool{"unary": true, "streaming": true}
+)
+
+func validateParams() {
+       if !validFrameworks[*framework] {
+               logger.Fatalf("Invalid framework: %s. Valid values: dubbo-go, 
grpc", *framework)
+       }
+
+       if *payloadSize < MinPayloadSize || *payloadSize > MaxPayloadSize {
+               logger.Fatalf("Invalid payload size: %d. Must be between %d and 
%d bytes", *payloadSize, MinPayloadSize, MaxPayloadSize)
+       }
+
+       if *concurrency < MinConcurrency || *concurrency > MaxConcurrency {
+               logger.Fatalf("Invalid concurrency: %d. Must be between %d and 
%d", *concurrency, MinConcurrency, MaxConcurrency)
+       }
+
+       if !validSerializations[*serialization] {
+               logger.Fatalf("Invalid serialization: %s. Valid values: 
hessian2, protobuf, msgpack", *serialization)
+       }
+
+       if !validCompressions[*compression] {
+               logger.Fatalf("Invalid compression: %s. Valid values: none, 
default, fastest", *compression)
+       }
+
+       if !validCallModes[*callMode] {
+               logger.Fatalf("Invalid call mode: %s. Valid values: unary, 
streaming", *callMode)
+       }
+
+       if _, err := time.ParseDuration(*testDuration); err != nil {
+               logger.Fatalf("Invalid test duration: %v", err)
+       }
+
+       if _, err := time.ParseDuration(*warmupDuration); err != nil {
+               logger.Fatalf("Invalid warmup duration: %v", err)
+       }
+}
+
+func main() {
+       flag.Parse()
+
+       loadConfig(*configFile)
+
+       validateParams()
+
+       logger.Info(Separator)
+       logger.Info("       Dubbo-Go Benchmark Client")
+       logger.Info(Separator)
+       logger.Infof("Framework:         %s", *framework)
+       logger.Infof("Payload Size:      %d bytes", *payloadSize)
+       logger.Infof("Serialization:     %s", *serialization)
+       logger.Infof("Compression:       %s", *compression)
+       logger.Infof("Concurrency:       %d", *concurrency)
+       logger.Infof("Call Mode:         %s", *callMode)
+       logger.Infof("Warmup Duration:   %s", *warmupDuration)
+       logger.Infof("Test Duration:     %s", *testDuration)
+       if *serverAddr != "" {
+               logger.Infof("Server Address:    %s", *serverAddr)
+       }
+       if *serverPID != 0 {
+               logger.Infof("Server PID:        %d", *serverPID)
+       }
+       logger.Info(Separator)
+
+       testDur, err := time.ParseDuration(*testDuration)
+       if err != nil {
+               logger.Fatalf("Invalid test duration: %v", err)
+       }
+
+       warmupDur, err := time.ParseDuration(*warmupDuration)
+       if err != nil {
+               logger.Fatalf("Invalid warmup duration: %v", err)
+       }
+
+       pg := payload.NewPayloadGenerator()
+       data := pg.Generate(*payloadSize)
+       logger.Infof("[INFO] Payload data generated, size: %d bytes", len(data))
+
+       caller, err := createCaller(data)
+       if err != nil {
+               logger.Fatalf("Failed to create client: %v", err)
+       }
+       defer caller.Close()
+
+       var sysMonitor *monitor.SystemMonitor
+       if *serverPID != 0 {
+               sysMonitor = monitor.NewSystemMonitor(*serverPID, 1*time.Second)
+               sysMonitor.Start()
+               defer sysMonitor.Stop()
+               logger.Infof("[INFO] System monitor started, monitoring PID: 
%d", *serverPID)
+       }
+
+       benchEngine := engine.NewEngine(*concurrency, warmupDur, testDur, 
30*time.Second)
+
+       sigCh := make(chan os.Signal, 1)
+       signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
+
+       go func() {
+               sig := <-sigCh
+               logger.Infof("[INFO] Received signal %v, stopping 
benchmark...", sig)
+               benchEngine.Stop()
+       }()
+
+       logger.Info("[INFO] Starting benchmark...")
+       stats := benchEngine.Run(func(ctx context.Context) (time.Duration, 
error) {
+               start := time.Now()
+               err := caller.Call(ctx)
+               return time.Since(start), err
+       })
+
+       logger.Info(stats.String())
+
+       cpuAvg, memoryPeakBytes := 0.0, uint64(0)
+       if sysMonitor != nil {
+               cpuAvg, memoryPeakBytes = sysMonitor.GetSummary()
+               logger.Info(sysMonitor.String())
+       }
+
+       saveResults(stats, cpuAvg, float64(memoryPeakBytes)/1024/1024)
+}
+
+func loadConfig(configPath string) {
+       if configPath == "" {
+               return
+       }
+
+       data, err := os.ReadFile(configPath)
+       if err != nil {
+               logger.Warnf("[WARN] Failed to read config file: %v", err)
+               return
+       }
+
+       var config BenchmarkConfig
+       if err := yaml.Unmarshal(data, &config); err != nil {
+               logger.Warnf("[WARN] Failed to parse config file: %v", err)
+               return
+       }
+
+       logger.Infof("[INFO] Loaded config from %s", configPath)
+}
+
+func createCaller(data []byte) (Caller, error) {
+       addr := *serverAddr
+       if addr == "" {
+               switch *framework {
+               case FrameworkDubboGo:
+                       addr = "127.0.0.1:20000"
+               case FrameworkGRPC:
+                       addr = "127.0.0.1:50051"
+               default:
+                       addr = "127.0.0.1:20000"
+               }
+       }
+
+       switch *framework {
+       case FrameworkDubboGo:
+               return clients.NewDubboGoClient(addr, *serialization, 
*compression, *callMode, data)
+       case FrameworkGRPC:
+               return clients.NewGrpcClient(addr, *callMode, data)
+       default:
+               return nil, fmt.Errorf("unsupported framework: %s", *framework)
+       }
+}
+
+func saveResults(stats *engine.Statistics, cpuAvg, memoryPeak float64) {
+       result := &BenchmarkResult{
+               Framework:       *framework,
+               PayloadSize:     *payloadSize,
+               Serialization:   *serialization,
+               Compression:     *compression,
+               Concurrency:     *concurrency,
+               CallMode:        *callMode,
+               Timestamp:       time.Now().Format("2006-01-02 15:04:05"),
+               QPS:             stats.QPS,
+               SuccessRate:     stats.SuccessRate,
+               TotalRequests:   stats.Total,
+               SuccessRequests: stats.Success,
+               FailureRequests: stats.Failure,
+               LatencyP50:      float64(stats.P50) / float64(time.Millisecond),
+               LatencyP90:      float64(stats.P90) / float64(time.Millisecond),
+               LatencyP95:      float64(stats.P95) / float64(time.Millisecond),
+               LatencyP99:      float64(stats.P99) / float64(time.Millisecond),
+               LatencyMin:      float64(stats.Min) / float64(time.Millisecond),
+               LatencyMax:      float64(stats.Max) / float64(time.Millisecond),
+               LatencyAvg:      float64(stats.Avg) / float64(time.Millisecond),
+               CPUAvg:          cpuAvg,
+               MemoryPeak:      memoryPeak,
+       }
+
+       dataDir := *outputDir
+       if dataDir == "" {
+               wd, err := os.Getwd()
+               if err != nil {
+                       logger.Warnf("[WARN] Failed to get working directory: 
%v", err)
+                       return
+               }
+               dataDir = filepath.Join(wd, "data")
+       }
+
+       if mkdirErr := os.MkdirAll(dataDir, 0755); mkdirErr != nil {
+               logger.Warnf("[WARN] Failed to create data directory: %v", 
mkdirErr)
+               return
+       }
+
+       filename := fmt.Sprintf("%s_%d_%s_%s_%d_%s.json",
+               *framework, *payloadSize, *serialization, *compression, 
*concurrency, *callMode)
+       path := filepath.Join(dataDir, filename)
+
+       dataBytes, err := json.MarshalIndent(result, "", "  ")
+       if err != nil {
+               logger.Warnf("[WARN] Failed to serialize result: %v", err)
+               return
+       }
+
+       if err := os.WriteFile(path, dataBytes, 0644); err != nil {
+               logger.Warnf("[WARN] Failed to write result file: %v", err)
+               return
+       }
+
+       logger.Infof("[INFO] Test results saved to: %s", path)
+}
diff --git a/tools/benchmark/client/monitor/system_monitor.go 
b/tools/benchmark/client/monitor/system_monitor.go
new file mode 100644
index 000000000..ad608bc4c
--- /dev/null
+++ b/tools/benchmark/client/monitor/system_monitor.go
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package monitor
+
+import (
+       "fmt"
+       "sync"
+       "time"
+)
+
+import (
+       "github.com/shirou/gopsutil/v3/cpu"
+       "github.com/shirou/gopsutil/v3/mem"
+       "github.com/shirou/gopsutil/v3/process"
+)
+
+type SystemMetrics struct {
+       CPUUsage    float64
+       MemoryUsage uint64
+       Timestamp   time.Time
+}
+
+type SystemMonitor struct {
+       pid      int
+       interval time.Duration
+       metrics  []SystemMetrics
+       mu       sync.Mutex
+       stopChan chan struct{}
+       wg       sync.WaitGroup
+       stopOnce sync.Once
+       proc     *process.Process
+}
+
+func NewSystemMonitor(pid int, interval time.Duration) *SystemMonitor {
+       sm := &SystemMonitor{
+               pid:      pid,
+               interval: interval,
+               metrics:  make([]SystemMetrics, 0),
+               stopChan: make(chan struct{}),
+       }
+
+       proc, err := process.NewProcess(int32(pid))
+       if err != nil {
+               return sm
+       }
+       sm.proc = proc
+
+       return sm
+}
+
+func (sm *SystemMonitor) Start() {
+       if sm.proc == nil {
+               return
+       }
+       sm.wg.Add(1)
+       go sm.monitor()
+}
+
+func (sm *SystemMonitor) Stop() {
+       sm.stopOnce.Do(func() {
+               close(sm.stopChan)
+               sm.wg.Wait()
+       })
+}
+
+func (sm *SystemMonitor) monitor() {
+       defer sm.wg.Done()
+
+       ticker := time.NewTicker(sm.interval)
+       defer ticker.Stop()
+
+       for {
+               select {
+               case <-sm.stopChan:
+                       return
+               case <-ticker.C:
+                       metrics, err := sm.collectMetrics()
+                       if err != nil {
+                               continue
+                       }
+                       sm.mu.Lock()
+                       sm.metrics = append(sm.metrics, metrics)
+                       sm.mu.Unlock()
+               }
+       }
+}
+
+func (sm *SystemMonitor) collectMetrics() (SystemMetrics, error) {
+       metrics := SystemMetrics{
+               Timestamp: time.Now(),
+       }
+
+       cpu, err := sm.getCPUUsage()
+       if err != nil {
+               return metrics, err
+       }
+       metrics.CPUUsage = cpu
+
+       mem, err := sm.getMemoryUsage()
+       if err != nil {
+               return metrics, err
+       }
+       metrics.MemoryUsage = mem
+
+       return metrics, nil
+}
+
+func (sm *SystemMonitor) getCPUUsage() (float64, error) {
+       if sm.proc != nil {
+               cpuPercent, err := sm.proc.Percent(0)
+               if err == nil {
+                       return cpuPercent, nil
+               }
+       }
+
+       cpuPercents, err := cpu.Percent(0, false)
+       if err != nil {
+               return 0, err
+       }
+
+       if len(cpuPercents) > 0 {
+               return cpuPercents[0], nil
+       }
+
+       return 0, nil
+}
+
+func (sm *SystemMonitor) getMemoryUsage() (uint64, error) {
+       if sm.proc != nil {
+               memInfo, err := sm.proc.MemoryInfo()
+               if err == nil {
+                       return memInfo.RSS, nil
+               }
+       }
+
+       virtualMem, err := mem.VirtualMemory()
+       if err != nil {
+               return 0, err
+       }
+
+       return virtualMem.Used, nil
+}
+
+func (sm *SystemMonitor) GetMetrics() []SystemMetrics {
+       sm.mu.Lock()
+       defer sm.mu.Unlock()
+       result := make([]SystemMetrics, len(sm.metrics))
+       copy(result, sm.metrics)
+       return result
+}
+
+func (sm *SystemMonitor) GetSummary() (avgCPU float64, maxMemory uint64) {
+       sm.mu.Lock()
+       defer sm.mu.Unlock()
+
+       if len(sm.metrics) == 0 {
+               return 0, 0
+       }
+
+       var totalCPU float64
+       maxMemory = 0
+
+       for _, m := range sm.metrics {
+               totalCPU += m.CPUUsage
+               if m.MemoryUsage > maxMemory {
+                       maxMemory = m.MemoryUsage
+               }
+       }
+
+       return totalCPU / float64(len(sm.metrics)), maxMemory
+}
+
+func (sm *SystemMonitor) String() string {
+       avgCPU, maxMemory := sm.GetSummary()
+       return fmt.Sprintf(`
+System Resource Usage:
+  Avg CPU Usage:   %.2f%%
+  Memory Peak:     %.2f MB
+`, avgCPU, float64(maxMemory)/1024/1024)
+}
diff --git a/tools/benchmark/client/payload/payload.go 
b/tools/benchmark/client/payload/payload.go
new file mode 100644
index 000000000..99462c655
--- /dev/null
+++ b/tools/benchmark/client/payload/payload.go
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package payload
+
+import (
+       "crypto/rand"
+       "sync"
+)
+
+type PayloadGenerator struct {
+       payloads sync.Map
+}
+
+func NewPayloadGenerator() *PayloadGenerator {
+       return &PayloadGenerator{}
+}
+
+func (pg *PayloadGenerator) Generate(size int) []byte {
+       if cached, ok := pg.payloads.Load(size); ok {
+               return cached.([]byte)
+       }
+
+       data := make([]byte, size)
+       _, err := rand.Read(data)
+       if err != nil {
+               for i := range data {
+                       data[i] = byte(i % 256)
+               }
+       }
+
+       pg.payloads.Store(size, data)
+       return data
+}
+
+func (pg *PayloadGenerator) GetCachedSize(size int) ([]byte, bool) {
+       data, ok := pg.payloads.Load(size)
+       if !ok {
+               return nil, false
+       }
+       return data.([]byte), true
+}
+
+func (pg *PayloadGenerator) Clear() {
+       pg.payloads.Range(func(key, value any) bool {
+               pg.payloads.Delete(key)
+               return true
+       })
+}
diff --git a/tools/benchmark/config.yaml b/tools/benchmark/config.yaml
new file mode 100644
index 000000000..e52554cda
--- /dev/null
+++ b/tools/benchmark/config.yaml
@@ -0,0 +1,55 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+service:
+  name: BenchmarkService
+  port:
+    dubbo-go: 20000
+    dubbo-java: 20001
+    grpc: 50051
+
+payload_sizes:
+  - 128
+  - 1024
+  - 16384
+  - 1048576
+
+serializations:
+  - hessian2
+  - protobuf
+  - msgpack
+
+compressions:
+  - none
+  - default
+  - fastest
+
+call_modes:
+  - unary
+  - streaming
+
+concurrency_levels:
+  - 50
+  - 100
+  - 500
+  - 1000
+  - 2000
+
+benchmark:
+  warmup_duration: 10s
+  test_duration: 60s
+  request_timeout: 30s
diff --git a/tools/benchmark/proto/benchmark.pb.go 
b/tools/benchmark/proto/benchmark.pb.go
new file mode 100644
index 000000000..3386a041d
--- /dev/null
+++ b/tools/benchmark/proto/benchmark.pb.go
@@ -0,0 +1,194 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+//     protoc-gen-go v1.36.11
+//     protoc        v7.35.1
+// source: benchmark.proto
+
+package benchmark
+
+import (
+       protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+       protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+       reflect "reflect"
+       sync "sync"
+       unsafe "unsafe"
+)
+
+const (
+       // Verify that this generated code is sufficiently up-to-date.
+       _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+       // Verify that runtime/protoimpl is sufficiently up-to-date.
+       _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type BenchmarkRequest struct {
+       state         protoimpl.MessageState `protogen:"open.v1"`
+       Payload       []byte                 
`protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"`
+       unknownFields protoimpl.UnknownFields
+       sizeCache     protoimpl.SizeCache
+}
+
+func (x *BenchmarkRequest) Reset() {
+       *x = BenchmarkRequest{}
+       mi := &file_benchmark_proto_msgTypes[0]
+       ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+       ms.StoreMessageInfo(mi)
+}
+
+func (x *BenchmarkRequest) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BenchmarkRequest) ProtoMessage() {}
+
+func (x *BenchmarkRequest) ProtoReflect() protoreflect.Message {
+       mi := &file_benchmark_proto_msgTypes[0]
+       if x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use BenchmarkRequest.ProtoReflect.Descriptor instead.
+func (*BenchmarkRequest) Descriptor() ([]byte, []int) {
+       return file_benchmark_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *BenchmarkRequest) GetPayload() []byte {
+       if x != nil {
+               return x.Payload
+       }
+       return nil
+}
+
+type BenchmarkResponse struct {
+       state         protoimpl.MessageState `protogen:"open.v1"`
+       Payload       []byte                 
`protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"`
+       unknownFields protoimpl.UnknownFields
+       sizeCache     protoimpl.SizeCache
+}
+
+func (x *BenchmarkResponse) Reset() {
+       *x = BenchmarkResponse{}
+       mi := &file_benchmark_proto_msgTypes[1]
+       ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+       ms.StoreMessageInfo(mi)
+}
+
+func (x *BenchmarkResponse) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BenchmarkResponse) ProtoMessage() {}
+
+func (x *BenchmarkResponse) ProtoReflect() protoreflect.Message {
+       mi := &file_benchmark_proto_msgTypes[1]
+       if x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use BenchmarkResponse.ProtoReflect.Descriptor instead.
+func (*BenchmarkResponse) Descriptor() ([]byte, []int) {
+       return file_benchmark_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *BenchmarkResponse) GetPayload() []byte {
+       if x != nil {
+               return x.Payload
+       }
+       return nil
+}
+
+var File_benchmark_proto protoreflect.FileDescriptor
+
+const file_benchmark_proto_rawDesc = "" +
+       "\n" +
+       "\x0fbenchmark.proto\x12\tbenchmark\",\n" +
+       "\x10BenchmarkRequest\x12\x18\n" +
+       "\apayload\x18\x01 \x01(\fR\apayload\"-\n" +
+       "\x11BenchmarkResponse\x12\x18\n" +
+       "\apayload\x18\x01 \x01(\fR\apayload2\xa7\x01\n" +
+       "\x10BenchmarkService\x12F\n" +
+       
"\tUnaryCall\x12\x1b.benchmark.BenchmarkRequest\x1a\x1c.benchmark.BenchmarkResponse\x12K\n"
 +
+       "\n" +
+       
"StreamCall\x12\x1b.benchmark.BenchmarkRequest\x1a\x1c.benchmark.BenchmarkResponse(\x010\x01Bj\n"
 +
+       
"\x1aorg.apache.dubbo.benchmarkB\x0eBenchmarkProtoZ<dubbo.apache.org/dubbo-go/v3/tools/benchmark/proto;benchmarkb\x06proto3"
+
+var (
+       file_benchmark_proto_rawDescOnce sync.Once
+       file_benchmark_proto_rawDescData []byte
+)
+
+func file_benchmark_proto_rawDescGZIP() []byte {
+       file_benchmark_proto_rawDescOnce.Do(func() {
+               file_benchmark_proto_rawDescData = 
protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_benchmark_proto_rawDesc),
 len(file_benchmark_proto_rawDesc)))
+       })
+       return file_benchmark_proto_rawDescData
+}
+
+var file_benchmark_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_benchmark_proto_goTypes = []any{
+       (*BenchmarkRequest)(nil),  // 0: benchmark.BenchmarkRequest
+       (*BenchmarkResponse)(nil), // 1: benchmark.BenchmarkResponse
+}
+var file_benchmark_proto_depIdxs = []int32{
+       0, // 0: benchmark.BenchmarkService.UnaryCall:input_type -> 
benchmark.BenchmarkRequest
+       0, // 1: benchmark.BenchmarkService.StreamCall:input_type -> 
benchmark.BenchmarkRequest
+       1, // 2: benchmark.BenchmarkService.UnaryCall:output_type -> 
benchmark.BenchmarkResponse
+       1, // 3: benchmark.BenchmarkService.StreamCall:output_type -> 
benchmark.BenchmarkResponse
+       2, // [2:4] is the sub-list for method output_type
+       0, // [0:2] is the sub-list for method input_type
+       0, // [0:0] is the sub-list for extension type_name
+       0, // [0:0] is the sub-list for extension extendee
+       0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_benchmark_proto_init() }
+func file_benchmark_proto_init() {
+       if File_benchmark_proto != nil {
+               return
+       }
+       type x struct{}
+       out := protoimpl.TypeBuilder{
+               File: protoimpl.DescBuilder{
+                       GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+                       RawDescriptor: 
unsafe.Slice(unsafe.StringData(file_benchmark_proto_rawDesc), 
len(file_benchmark_proto_rawDesc)),
+                       NumEnums:      0,
+                       NumMessages:   2,
+                       NumExtensions: 0,
+                       NumServices:   1,
+               },
+               GoTypes:           file_benchmark_proto_goTypes,
+               DependencyIndexes: file_benchmark_proto_depIdxs,
+               MessageInfos:      file_benchmark_proto_msgTypes,
+       }.Build()
+       File_benchmark_proto = out.File
+       file_benchmark_proto_goTypes = nil
+       file_benchmark_proto_depIdxs = nil
+}
diff --git a/tools/benchmark/proto/benchmark.proto 
b/tools/benchmark/proto/benchmark.proto
new file mode 100644
index 000000000..7ef873716
--- /dev/null
+++ b/tools/benchmark/proto/benchmark.proto
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package benchmark;
+
+option go_package = 
"dubbo.apache.org/dubbo-go/v3/tools/benchmark/proto;benchmark";
+option java_package = "org.apache.dubbo.benchmark";
+option java_outer_classname = "BenchmarkProto";
+
+message BenchmarkRequest {
+  bytes payload = 1;
+}
+
+message BenchmarkResponse {
+  bytes payload = 1;
+}
+
+service BenchmarkService {
+  rpc UnaryCall(BenchmarkRequest) returns (BenchmarkResponse);
+  rpc StreamCall(stream BenchmarkRequest) returns (stream BenchmarkResponse);
+}
diff --git a/tools/benchmark/proto/benchmark.triple.go 
b/tools/benchmark/proto/benchmark.triple.go
new file mode 100644
index 000000000..5d69913f5
--- /dev/null
+++ b/tools/benchmark/proto/benchmark.triple.go
@@ -0,0 +1,209 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Code generated by protoc-gen-go-triple. DO NOT EDIT.
+
+//nolint:staticcheck
+package benchmark
+
+import (
+       "context"
+       "net/http"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3"
+       "dubbo.apache.org/dubbo-go/v3/client"
+       "dubbo.apache.org/dubbo-go/v3/common"
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+       "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+       "dubbo.apache.org/dubbo-go/v3/server"
+)
+
+const (
+       BenchmarkServiceName = "benchmark.BenchmarkService"
+)
+
+const (
+       BenchmarkServiceUnaryCallProcedure  = 
"/benchmark.BenchmarkService/UnaryCall"
+       BenchmarkServiceStreamCallProcedure = 
"/benchmark.BenchmarkService/StreamCall"
+)
+
+type TripleBenchmarkService interface {
+       UnaryCall(ctx context.Context, req *BenchmarkRequest, opts 
...client.CallOption) (*BenchmarkResponse, error)
+       StreamCall(ctx context.Context, opts ...client.CallOption) 
(TripleBenchmarkService_StreamCallClient, error)
+}
+
+func NewTripleBenchmarkService(cli *client.Client, opts 
...client.ReferenceOption) (TripleBenchmarkService, error) {
+       conn, err := cli.DialWithInfo("benchmark.BenchmarkService", 
&TripleBenchmarkService_ClientInfo, opts...)
+       if err != nil {
+               return nil, err
+       }
+       return &TripleBenchmarkServiceImpl{
+               conn: conn,
+       }, nil
+}
+
+func SetTripleConsumerService(srv common.RPCService) {
+       dubbo.SetConsumerServiceWithInfo(srv, 
&TripleBenchmarkService_ClientInfo)
+}
+
+type TripleBenchmarkServiceImpl struct {
+       conn *client.Connection
+}
+
+func (c *TripleBenchmarkServiceImpl) UnaryCall(ctx context.Context, req 
*BenchmarkRequest, opts ...client.CallOption) (*BenchmarkResponse, error) {
+       resp := new(BenchmarkResponse)
+       if err := c.conn.CallUnary(ctx, []any{req}, resp, "UnaryCall", 
opts...); err != nil {
+               return nil, err
+       }
+       return resp, nil
+}
+
+func (c *TripleBenchmarkServiceImpl) StreamCall(ctx context.Context, opts 
...client.CallOption) (TripleBenchmarkService_StreamCallClient, error) {
+       stream, err := c.conn.CallBidiStream(ctx, "StreamCall", opts...)
+       if err != nil {
+               return nil, err
+       }
+       rawStream := stream.(*triple_protocol.BidiStreamForClient)
+       return &TripleBenchmarkServiceStreamCallClient{BidiStreamForClient: 
rawStream}, nil
+}
+
+type TripleBenchmarkService_StreamCallClient interface {
+       Send(*BenchmarkRequest) error
+       Recv() bool
+       ResponseHeader() http.Header
+       ResponseTrailer() http.Header
+       Msg() *BenchmarkResponse
+       Err() error
+       Conn() (triple_protocol.StreamingClientConn, error)
+       Close() error
+}
+
+type TripleBenchmarkServiceStreamCallClient struct {
+       *triple_protocol.BidiStreamForClient
+       msg *BenchmarkResponse
+       err error
+}
+
+func (cli *TripleBenchmarkServiceStreamCallClient) Send(msg *BenchmarkRequest) 
error {
+       return cli.BidiStreamForClient.Send(msg)
+}
+
+func (cli *TripleBenchmarkServiceStreamCallClient) Recv() bool {
+       cli.msg = new(BenchmarkResponse)
+       cli.err = cli.BidiStreamForClient.Receive(cli.msg)
+       return cli.err == nil
+}
+
+func (cli *TripleBenchmarkServiceStreamCallClient) Msg() *BenchmarkResponse {
+       return cli.msg
+}
+
+func (cli *TripleBenchmarkServiceStreamCallClient) Err() error {
+       return cli.err
+}
+
+func (cli *TripleBenchmarkServiceStreamCallClient) Conn() 
(triple_protocol.StreamingClientConn, error) {
+       return cli.BidiStreamForClient.Conn()
+}
+
+func (cli *TripleBenchmarkServiceStreamCallClient) Close() error {
+       return cli.BidiStreamForClient.CloseResponse()
+}
+
+var TripleBenchmarkService_ClientInfo = client.ClientInfo{
+       InterfaceName: "benchmark.BenchmarkService",
+       MethodNames:   []string{"UnaryCall", "StreamCall"},
+       ConnectionInjectFunc: func(dubboCliRaw any, conn *client.Connection) {
+               dubboCli := dubboCliRaw.(*TripleBenchmarkServiceImpl)
+               dubboCli.conn = conn
+       },
+}
+
+type TripleBenchmarkServiceHandler interface {
+       UnaryCall(context.Context, *BenchmarkRequest) (*BenchmarkResponse, 
error)
+       StreamCall(context.Context, TripleBenchmarkService_StreamCallServer) 
error
+}
+
+func RegisterTripleBenchmarkServiceHandler(srv *server.Server, hdlr 
TripleBenchmarkServiceHandler, opts ...server.ServiceOption) error {
+       return srv.Register(hdlr, &TripleBenchmarkService_ServiceInfo, opts...)
+}
+
+func SetTripleProviderService(srv common.RPCService) {
+       dubbo.SetProviderServiceWithInfo(srv, 
&TripleBenchmarkService_ServiceInfo)
+}
+
+type TripleBenchmarkService_StreamCallServer interface {
+       Send(*BenchmarkResponse) error
+       Recv() (*BenchmarkRequest, error)
+       ResponseHeader() http.Header
+       ResponseTrailer() http.Header
+       Conn() triple_protocol.StreamingHandlerConn
+}
+
+type TripleBenchmarkServiceStreamCallServer struct {
+       *triple_protocol.BidiStream
+}
+
+func (g *TripleBenchmarkServiceStreamCallServer) Send(msg *BenchmarkResponse) 
error {
+       return g.BidiStream.Send(msg)
+}
+
+func (g *TripleBenchmarkServiceStreamCallServer) Recv() (*BenchmarkRequest, 
error) {
+       req := new(BenchmarkRequest)
+       if err := g.BidiStream.Receive(req); err != nil {
+               return nil, err
+       }
+       return req, nil
+}
+
+var TripleBenchmarkService_ServiceInfo = server.ServiceInfo{
+       InterfaceName: "benchmark.BenchmarkService",
+       ServiceType:   (*TripleBenchmarkServiceHandler)(nil),
+       Methods: []server.MethodInfo{
+               {
+                       Name: "UnaryCall",
+                       Type: constant.CallUnary,
+                       ReqInitFunc: func() any {
+                               return new(BenchmarkRequest)
+                       },
+                       MethodFunc: func(ctx context.Context, args []any, 
handler any) (any, error) {
+                               req := args[0].(*BenchmarkRequest)
+                               res, err := 
handler.(TripleBenchmarkServiceHandler).UnaryCall(ctx, req)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               return triple_protocol.NewResponse(res), nil
+                       },
+               },
+               {
+                       Name: "StreamCall",
+                       Type: constant.CallBidiStream,
+                       StreamInitFunc: func(baseStream any) any {
+                               return 
&TripleBenchmarkServiceStreamCallServer{baseStream.(*triple_protocol.BidiStream)}
+                       },
+                       MethodFunc: func(ctx context.Context, args []any, 
handler any) (any, error) {
+                               stream := 
args[0].(TripleBenchmarkService_StreamCallServer)
+                               if err := 
handler.(TripleBenchmarkServiceHandler).StreamCall(ctx, stream); err != nil {
+                                       return nil, err
+                               }
+                               return nil, nil
+                       },
+               },
+       },
+}
diff --git a/tools/benchmark/proto/benchmark_grpc.pb.go 
b/tools/benchmark/proto/benchmark_grpc.pb.go
new file mode 100644
index 000000000..e50e14735
--- /dev/null
+++ b/tools/benchmark/proto/benchmark_grpc.pb.go
@@ -0,0 +1,170 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.6.2
+// - protoc             v7.35.1
+// source: benchmark.proto
+
+package benchmark
+
+import (
+       context "context"
+       grpc "google.golang.org/grpc"
+       codes "google.golang.org/grpc/codes"
+       status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.64.0 or later.
+const _ = grpc.SupportPackageIsVersion9
+
+const (
+       BenchmarkService_UnaryCall_FullMethodName  = 
"/benchmark.BenchmarkService/UnaryCall"
+       BenchmarkService_StreamCall_FullMethodName = 
"/benchmark.BenchmarkService/StreamCall"
+)
+
+// BenchmarkServiceClient is the client API for BenchmarkService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please 
refer to 
https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type BenchmarkServiceClient interface {
+       UnaryCall(ctx context.Context, in *BenchmarkRequest, opts 
...grpc.CallOption) (*BenchmarkResponse, error)
+       StreamCall(ctx context.Context, opts ...grpc.CallOption) 
(grpc.BidiStreamingClient[BenchmarkRequest, BenchmarkResponse], error)
+}
+
+type benchmarkServiceClient struct {
+       cc grpc.ClientConnInterface
+}
+
+func NewBenchmarkServiceClient(cc grpc.ClientConnInterface) 
BenchmarkServiceClient {
+       return &benchmarkServiceClient{cc}
+}
+
+func (c *benchmarkServiceClient) UnaryCall(ctx context.Context, in 
*BenchmarkRequest, opts ...grpc.CallOption) (*BenchmarkResponse, error) {
+       cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+       out := new(BenchmarkResponse)
+       err := c.cc.Invoke(ctx, BenchmarkService_UnaryCall_FullMethodName, in, 
out, cOpts...)
+       if err != nil {
+               return nil, err
+       }
+       return out, nil
+}
+
+func (c *benchmarkServiceClient) StreamCall(ctx context.Context, opts 
...grpc.CallOption) (grpc.BidiStreamingClient[BenchmarkRequest, 
BenchmarkResponse], error) {
+       cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+       stream, err := c.cc.NewStream(ctx, 
&BenchmarkService_ServiceDesc.Streams[0], 
BenchmarkService_StreamCall_FullMethodName, cOpts...)
+       if err != nil {
+               return nil, err
+       }
+       x := &grpc.GenericClientStream[BenchmarkRequest, 
BenchmarkResponse]{ClientStream: stream}
+       return x, nil
+}
+
+// This type alias is provided for backwards compatibility with existing code 
that references the prior non-generic stream type by name.
+type BenchmarkService_StreamCallClient = 
grpc.BidiStreamingClient[BenchmarkRequest, BenchmarkResponse]
+
+// BenchmarkServiceServer is the server API for BenchmarkService service.
+// All implementations must embed UnimplementedBenchmarkServiceServer
+// for forward compatibility.
+type BenchmarkServiceServer interface {
+       UnaryCall(context.Context, *BenchmarkRequest) (*BenchmarkResponse, 
error)
+       StreamCall(grpc.BidiStreamingServer[BenchmarkRequest, 
BenchmarkResponse]) error
+       mustEmbedUnimplementedBenchmarkServiceServer()
+}
+
+// UnimplementedBenchmarkServiceServer must be embedded to have
+// forward compatible implementations.
+//
+// NOTE: this should be embedded by value instead of pointer to avoid a nil
+// pointer dereference when methods are called.
+type UnimplementedBenchmarkServiceServer struct{}
+
+func (UnimplementedBenchmarkServiceServer) UnaryCall(context.Context, 
*BenchmarkRequest) (*BenchmarkResponse, error) {
+       return nil, status.Error(codes.Unimplemented, "method UnaryCall not 
implemented")
+}
+func (UnimplementedBenchmarkServiceServer) 
StreamCall(grpc.BidiStreamingServer[BenchmarkRequest, BenchmarkResponse]) error 
{
+       return status.Error(codes.Unimplemented, "method StreamCall not 
implemented")
+}
+func (UnimplementedBenchmarkServiceServer) 
mustEmbedUnimplementedBenchmarkServiceServer() {}
+func (UnimplementedBenchmarkServiceServer) testEmbeddedByValue()               
           {}
+
+// UnsafeBenchmarkServiceServer may be embedded to opt out of forward 
compatibility for this service.
+// Use of this interface is not recommended, as added methods to 
BenchmarkServiceServer will
+// result in compilation errors.
+type UnsafeBenchmarkServiceServer interface {
+       mustEmbedUnimplementedBenchmarkServiceServer()
+}
+
+func RegisterBenchmarkServiceServer(s grpc.ServiceRegistrar, srv 
BenchmarkServiceServer) {
+       // If the following call panics, it indicates 
UnimplementedBenchmarkServiceServer was
+       // embedded by pointer and is nil.  This will cause panics if an
+       // unimplemented method is ever invoked, so we test this at 
initialization
+       // time to prevent it from happening at runtime later due to I/O.
+       if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
+               t.testEmbeddedByValue()
+       }
+       s.RegisterService(&BenchmarkService_ServiceDesc, srv)
+}
+
+func _BenchmarkService_UnaryCall_Handler(srv interface{}, ctx context.Context, 
dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) 
(interface{}, error) {
+       in := new(BenchmarkRequest)
+       if err := dec(in); err != nil {
+               return nil, err
+       }
+       if interceptor == nil {
+               return srv.(BenchmarkServiceServer).UnaryCall(ctx, in)
+       }
+       info := &grpc.UnaryServerInfo{
+               Server:     srv,
+               FullMethod: BenchmarkService_UnaryCall_FullMethodName,
+       }
+       handler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
+               return srv.(BenchmarkServiceServer).UnaryCall(ctx, 
req.(*BenchmarkRequest))
+       }
+       return interceptor(ctx, in, info, handler)
+}
+
+func _BenchmarkService_StreamCall_Handler(srv interface{}, stream 
grpc.ServerStream) error {
+       return 
srv.(BenchmarkServiceServer).StreamCall(&grpc.GenericServerStream[BenchmarkRequest,
 BenchmarkResponse]{ServerStream: stream})
+}
+
+// This type alias is provided for backwards compatibility with existing code 
that references the prior non-generic stream type by name.
+type BenchmarkService_StreamCallServer = 
grpc.BidiStreamingServer[BenchmarkRequest, BenchmarkResponse]
+
+// BenchmarkService_ServiceDesc is the grpc.ServiceDesc for BenchmarkService 
service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var BenchmarkService_ServiceDesc = grpc.ServiceDesc{
+       ServiceName: "benchmark.BenchmarkService",
+       HandlerType: (*BenchmarkServiceServer)(nil),
+       Methods: []grpc.MethodDesc{
+               {
+                       MethodName: "UnaryCall",
+                       Handler:    _BenchmarkService_UnaryCall_Handler,
+               },
+       },
+       Streams: []grpc.StreamDesc{
+               {
+                       StreamName:    "StreamCall",
+                       Handler:       _BenchmarkService_StreamCall_Handler,
+                       ServerStreams: true,
+                       ClientStreams: true,
+               },
+       },
+       Metadata: "benchmark.proto",
+}
diff --git a/tools/benchmark/scripts/gen_code.sh 
b/tools/benchmark/scripts/gen_code.sh
new file mode 100755
index 000000000..7d46fb58b
--- /dev/null
+++ b/tools/benchmark/scripts/gen_code.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+set -e
+
+BASE_DIR=$(cd "$(dirname "$0")/.." && pwd)
+PROJECT_ROOT=$(cd "$BASE_DIR/../.." && pwd)
+PROTO_DIR="$BASE_DIR/proto"
+OUT_DIR="$PROTO_DIR"
+PLUGIN_SOURCE_DIR="$PROJECT_ROOT/tools/protoc-gen-go-triple"
+
+mkdir -p "$OUT_DIR"
+
+CLEANUP_DIR=$(mktemp -d)
+cleanup() {
+    rm -rf "$CLEANUP_DIR"
+}
+trap cleanup EXIT
+
+echo "[INFO] Building protoc-gen-go-triple plugin in temp directory..."
+cd "$PLUGIN_SOURCE_DIR"
+go build -o "$CLEANUP_DIR/protoc-gen-go-triple" .
+cd -
+
+echo "[INFO] Generating protobuf code..."
+protoc --proto_path="$PROTO_DIR" --go_out="$OUT_DIR" 
--go_opt=paths=source_relative "benchmark.proto"
+
+echo "[INFO] Generating gRPC code..."
+protoc --proto_path="$PROTO_DIR" \
+  --go-grpc_out="$OUT_DIR" \
+  --go-grpc_opt=paths=source_relative \
+  "benchmark.proto"
+
+echo "[INFO] Generating triple code using protoc-gen-go-triple..."
+protoc --proto_path="$PROTO_DIR" \
+  --plugin=protoc-gen-go-triple="$CLEANUP_DIR/protoc-gen-go-triple" \
+  --go-triple_out="$OUT_DIR" \
+  --go-triple_opt=paths=source_relative \
+  "benchmark.proto"
+
+echo "[INFO] Code generation completed"
+ls -la "$OUT_DIR"
diff --git a/tools/benchmark/scripts/run_all.sh 
b/tools/benchmark/scripts/run_all.sh
new file mode 100755
index 000000000..bdcc538f6
--- /dev/null
+++ b/tools/benchmark/scripts/run_all.sh
@@ -0,0 +1,178 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+set -e
+
+BASE_DIR=$(cd "$(dirname "$0")/.." && pwd)
+LOG_DIR="$BASE_DIR/logs"
+REPORT_DIR="$BASE_DIR/report"
+DATA_DIR="$BASE_DIR/data"
+SEPARATOR="========================================"
+
+mkdir -p "$LOG_DIR"
+mkdir -p "$REPORT_DIR"
+mkdir -p "$DATA_DIR"
+
+cleanup_server() {
+    local pid=$1
+    if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
+        kill "$pid" 2>/dev/null || true
+        sleep 2
+        if kill -0 "$pid" 2>/dev/null; then
+            kill -9 "$pid" 2>/dev/null || true
+        fi
+    fi
+}
+
+echo "$SEPARATOR"
+echo "   Dubbo-Go Benchmark - Full Test Suite"
+echo "$SEPARATOR"
+
+echo "[INFO] Checking environment dependencies..."
+
+if ! command -v go > /dev/null 2>&1; then
+    echo "[ERROR] Go not installed, please install Go 1.25+"
+    exit 1
+fi
+
+echo "[INFO] Environment check passed"
+
+wait_for_port() {
+    local port=$1
+    local timeout=${2:-30}
+    local elapsed=0
+    while [ $elapsed -lt $timeout ]; do
+        if nc -z localhost "$port" 2>/dev/null; then
+            return 0
+        fi
+        sleep 1
+        elapsed=$((elapsed + 1))
+    done
+    return 1
+}
+
+echo ""
+echo "[INFO] Compiling Dubbo-Go server..."
+cd "$BASE_DIR/server/dubbo-go"
+go build -o benchmark-dubbo-go main.go
+
+echo "[INFO] Compiling gRPC server..."
+cd "$BASE_DIR/server/grpc"
+go build -o benchmark-grpc main.go
+
+echo ""
+echo "[INFO] Compiling benchmark client..."
+cd "$BASE_DIR/client"
+go build -o benchmark-client main.go
+
+echo ""
+echo "[INFO] Starting full benchmark suite..."
+
+FRAMEWORKS=("dubbo-go" "grpc")
+PAYLOADS=("128" "1024" "16384" "1048576")
+SERIALIZATIONS=("protobuf")
+COMPRESSIONS=("none")
+CONCURRENCY=("50" "100")
+CALL_MODES=("unary")
+
+for framework in "${FRAMEWORKS[@]}"; do
+    echo ""
+    echo "[INFO] ==== Testing framework: $framework ===="
+    
+    case "$framework" in
+        dubbo-go)
+            SERVER_BIN="$BASE_DIR/server/dubbo-go/benchmark-dubbo-go"
+            SERVER_PORT=20000
+            ;;
+        grpc)
+            SERVER_BIN="$BASE_DIR/server/grpc/benchmark-grpc"
+            SERVER_PORT=50051
+            ;;
+        *)
+            echo "[WARNING] Skipping unknown framework: $framework"
+            continue
+            ;;
+    esac
+
+    for payload in "${PAYLOADS[@]}"; do
+        for serialization in "${SERIALIZATIONS[@]}"; do
+            for compression in "${COMPRESSIONS[@]}"; do
+                for concurrency in "${CONCURRENCY[@]}"; do
+                    for mode in "${CALL_MODES[@]}"; do
+                        echo ""
+                        echo 
"--------------------------------------------------------"
+                        echo "Test case: $framework | $payload bytes | 
$serialization | $compression | $concurrency concurrency | $mode"
+                        echo 
"--------------------------------------------------------"
+
+                        
LOG_FILE="$LOG_DIR/${framework}_${payload}_${serialization}_${compression}_${concurrency}_${mode}.log"
+
+                        echo "[INFO] Starting server..."
+                        case "$framework" in
+                            dubbo-go)
+                                "$SERVER_BIN" --serialization "$serialization" 
--compression "$compression" --port "$SERVER_PORT" > "$LOG_FILE.server.log" 
2>&1 &
+                                ;;
+                            grpc)
+                                "$SERVER_BIN" --port "$SERVER_PORT" > 
"$LOG_FILE.server.log" 2>&1 &
+                                ;;
+                            *)
+                                echo "[ERROR] Unsupported framework: 
$framework"
+                                exit 1
+                                ;;
+                        esac
+                        SERVER_PID=$!
+
+                        trap "cleanup_server $SERVER_PID" EXIT INT TERM
+
+                        echo "[INFO] Waiting for server to be ready on port 
$SERVER_PORT..."
+                        if ! wait_for_port "$SERVER_PORT" 30; then
+                            echo "[ERROR] Server failed to start within 30 
seconds"
+                            cleanup_server "$SERVER_PID"
+                            trap - EXIT INT TERM
+                            continue
+                        fi
+                        echo "[INFO] Server is ready"
+
+                        echo "[INFO] Starting benchmark..."
+                        "$BASE_DIR/client/benchmark-client" \
+                            --framework "$framework" \
+                            --payload "$payload" \
+                            --serialization "$serialization" \
+                            --compression "$compression" \
+                            --concurrency "$concurrency" \
+                            --mode "$mode" \
+                            --pid "$SERVER_PID" \
+                            --output "$DATA_DIR" \
+                            > "$LOG_FILE" 2>&1
+
+                        echo "[INFO] Test case completed, log saved to 
$LOG_FILE"
+
+                        cleanup_server "$SERVER_PID"
+                        trap - EXIT INT TERM
+                    done
+                done
+            done
+        done
+    done
+done
+
+echo ""
+echo "$SEPARATOR"
+echo "   Benchmark completed!"
+echo "$SEPARATOR"
+echo "Log location: $LOG_DIR/"
+echo "Data location: $DATA_DIR/"
diff --git a/tools/benchmark/scripts/run_single.sh 
b/tools/benchmark/scripts/run_single.sh
new file mode 100755
index 000000000..f302cb29f
--- /dev/null
+++ b/tools/benchmark/scripts/run_single.sh
@@ -0,0 +1,139 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+set -e
+
+BASE_DIR=$(cd "$(dirname "$0")/.." && pwd)
+LOG_DIR="$BASE_DIR/logs"
+SEPARATOR="========================================"
+
+mkdir -p "$LOG_DIR"
+
+cleanup() {
+    echo "[INFO] Cleaning up resources..."
+    if [ -n "$SERVER_PID" ] && kill -0 "$SERVER_PID" 2>/dev/null; then
+        kill "$SERVER_PID" 2>/dev/null || true
+        sleep 2
+        if kill -0 "$SERVER_PID" 2>/dev/null; then
+            kill -9 "$SERVER_PID" 2>/dev/null || true
+        fi
+    fi
+}
+
+trap cleanup EXIT INT TERM
+
+FRAMEWORK="${1:-dubbo-go}"
+PAYLOAD="${2:-1024}"
+SERIALIZATION="${3:-protobuf}"
+COMPRESSION="${4:-none}"
+CONCURRENCY="${5:-100}"
+CALL_MODE="${6:-unary}"
+
+wait_for_port() {
+    local port=$1
+    local timeout=${2:-30}
+    local elapsed=0
+    while [ $elapsed -lt $timeout ]; do
+        if nc -z localhost "$port" 2>/dev/null; then
+            return 0
+        fi
+        sleep 1
+        elapsed=$((elapsed + 1))
+    done
+    return 1
+}
+
+echo "$SEPARATOR"
+echo "   Dubbo-Go Benchmark - Single Test"
+echo "$SEPARATOR"
+echo "Framework:         $FRAMEWORK"
+echo "Payload Size:      $PAYLOAD bytes"
+echo "Serialization:     $SERIALIZATION"
+echo "Compression:       $COMPRESSION"
+echo "Concurrency:       $CONCURRENCY"
+echo "Call Mode:         $CALL_MODE"
+echo "$SEPARATOR"
+
+echo "[INFO] Compiling server..."
+case "$FRAMEWORK" in
+    dubbo-go)
+        cd "$BASE_DIR/server/dubbo-go"
+        go build -o benchmark-dubbo-go main.go
+        SERVER_BIN="$BASE_DIR/server/dubbo-go/benchmark-dubbo-go"
+        SERVER_PORT=20000
+        ;;
+    grpc)
+        cd "$BASE_DIR/server/grpc"
+        go build -o benchmark-grpc main.go
+        SERVER_BIN="$BASE_DIR/server/grpc/benchmark-grpc"
+        SERVER_PORT=50051
+        ;;
+    *)
+        echo "[ERROR] Unsupported framework: $FRAMEWORK"
+        exit 1
+        ;;
+esac
+
+echo "[INFO] Compiling client..."
+cd "$BASE_DIR/client"
+go build -o benchmark-client main.go
+
+LOG_FILE="$LOG_DIR/${FRAMEWORK}_${PAYLOAD}_${SERIALIZATION}_${COMPRESSION}_${CONCURRENCY}_${CALL_MODE}.log"
+
+echo ""
+echo "[INFO] Starting server..."
+case "$FRAMEWORK" in
+    dubbo-go)
+        "$SERVER_BIN" --serialization "$SERIALIZATION" --compression 
"$COMPRESSION" --port "$SERVER_PORT" > "$LOG_FILE.server.log" 2>&1 &
+        ;;
+    grpc)
+        "$SERVER_BIN" --port "$SERVER_PORT" > "$LOG_FILE.server.log" 2>&1 &
+        ;;
+    *)
+        echo "[ERROR] Unsupported framework: $FRAMEWORK"
+        exit 1
+        ;;
+esac
+SERVER_PID=$!
+echo "[INFO] Server PID: $SERVER_PID"
+
+echo "[INFO] Waiting for server to be ready on port $SERVER_PORT..."
+if ! wait_for_port "$SERVER_PORT" 30; then
+    echo "[ERROR] Server failed to start within 30 seconds"
+    kill "$SERVER_PID" 2>/dev/null || true
+    exit 1
+fi
+echo "[INFO] Server is ready"
+
+echo ""
+echo "[INFO] Starting benchmark..."
+"$BASE_DIR/client/benchmark-client" \
+    --framework "$FRAMEWORK" \
+    --payload "$PAYLOAD" \
+    --serialization "$SERIALIZATION" \
+    --compression "$COMPRESSION" \
+    --concurrency "$CONCURRENCY" \
+    --mode "$CALL_MODE" \
+    --pid "$SERVER_PID" \
+    --output "$BASE_DIR/data"
+
+echo ""
+echo "$SEPARATOR"
+echo "   Test completed!"
+echo "$SEPARATOR"
+echo "Log location: $LOG_FILE"
diff --git a/tools/benchmark/server/dubbo-go/main.go 
b/tools/benchmark/server/dubbo-go/main.go
new file mode 100644
index 000000000..c353a4689
--- /dev/null
+++ b/tools/benchmark/server/dubbo-go/main.go
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+import (
+       "context"
+       "flag"
+       "io"
+       "os"
+       "os/signal"
+       "syscall"
+)
+
+import (
+       "github.com/dubbogo/gost/log/logger"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/graceful_shutdown"
+       _ "dubbo.apache.org/dubbo-go/v3/imports"
+       "dubbo.apache.org/dubbo-go/v3/protocol"
+       "dubbo.apache.org/dubbo-go/v3/protocol/triple"
+       "dubbo.apache.org/dubbo-go/v3/server"
+       benchmark "dubbo.apache.org/dubbo-go/v3/tools/benchmark/proto"
+)
+
+const separator = "========================================"
+
+var (
+       serialization = flag.String("serialization", "protobuf", "Serialization 
protocol: hessian2 / protobuf / msgpack")
+       compression   = flag.String("compression", "none", "Compression 
strategy: none / default / fastest")
+       port          = flag.Int("port", 20000, "Server port")
+)
+
+type BenchmarkServiceImpl struct {
+       benchmark.TripleBenchmarkServiceHandler
+}
+
+func (s *BenchmarkServiceImpl) UnaryCall(ctx context.Context, req 
*benchmark.BenchmarkRequest) (*benchmark.BenchmarkResponse, error) {
+       return &benchmark.BenchmarkResponse{Payload: req.Payload}, nil
+}
+
+func (s *BenchmarkServiceImpl) StreamCall(ctx context.Context, stream 
benchmark.TripleBenchmarkService_StreamCallServer) error {
+       for {
+               req, err := stream.Recv()
+               if err != nil {
+                       if err == io.EOF {
+                               return nil
+                       }
+                       return err
+               }
+               if err := stream.Send(&benchmark.BenchmarkResponse{Payload: 
req.Payload}); err != nil {
+                       return err
+               }
+       }
+}
+
+func main() {
+       flag.Parse()
+
+       logger.Info(separator)
+       logger.Info("    Dubbo-Go Benchmark Server")
+       logger.Info(separator)
+       logger.Infof("[INFO] Serialization: %s", *serialization)
+       logger.Infof("[INFO] Compression:   %s", *compression)
+       logger.Infof("[INFO] Port:          %d", *port)
+
+       srv, err := server.NewServer(
+               server.WithServerProtocol(
+                       protocol.WithTriple(
+                               triple.WithMaxServerRecvMsgSize("16MB"),
+                               triple.WithMaxServerSendMsgSize("16MB"),
+                       ),
+                       protocol.WithPort(*port),
+                       protocol.WithParams(map[string]string{
+                               "serialization": *serialization,
+                               "compression":   *compression,
+                       }),
+               ),
+       )
+       if err != nil {
+               logger.Fatalf("Failed to create server: %v", err)
+       }
+
+       if err := benchmark.RegisterTripleBenchmarkServiceHandler(srv, 
&BenchmarkServiceImpl{}); err != nil {
+               logger.Fatalf("Failed to register service: %v", err)
+       }
+
+       go func() {
+               if err := srv.Serve(); err != nil {
+                       logger.Fatalf("Failed to start server: %v", err)
+               }
+       }()
+
+       logger.Infof("[INFO] Server started, listening on: 127.0.0.1:%d", *port)
+
+       sig := make(chan os.Signal, 1)
+       signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
+       <-sig
+
+       logger.Info("[INFO] Stopping server...")
+       if err := graceful_shutdown.Shutdown(context.Background()); err != nil {
+               logger.Errorf("Failed to stop server: %v", err)
+       }
+       logger.Info("[INFO] Server stopped")
+       os.Exit(0)
+}
diff --git a/tools/benchmark/server/dubbo-java/pom.xml 
b/tools/benchmark/server/dubbo-java/pom.xml
new file mode 100644
index 000000000..5f9b54795
--- /dev/null
+++ b/tools/benchmark/server/dubbo-java/pom.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
https://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.apache.dubbo</groupId>
+    <artifactId>dubbo-java-benchmark</artifactId>
+    <version>1.0.0</version>
+    <packaging>jar</packaging>
+
+    <name>Dubbo-Java Benchmark Server</name>
+    <description>Dubbo-Java performance benchmark server</description>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <dubbo.version>3.2.0</dubbo.version>
+        <spring-boot.version>2.7.18</spring-boot.version>
+    </properties>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>${spring-boot.version}</version>
+        <relativePath/>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-spring-boot-starter</artifactId>
+            <version>${dubbo.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo</artifactId>
+            <version>${dubbo.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protobuf-java</artifactId>
+            <version>3.21.7</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.30</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.11.0</version>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>3.5.1</version>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <transformers>
+                                <transformer 
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                                    
<mainClass>org.apache.dubbo.benchmark.BenchmarkServer</mainClass>
+                                </transformer>
+                            </transformers>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git 
a/tools/benchmark/server/dubbo-java/src/main/java/org/apache/dubbo/benchmark/BenchmarkRequest.java
 
b/tools/benchmark/server/dubbo-java/src/main/java/org/apache/dubbo/benchmark/BenchmarkRequest.java
new file mode 100644
index 000000000..cddab5611
--- /dev/null
+++ 
b/tools/benchmark/server/dubbo-java/src/main/java/org/apache/dubbo/benchmark/BenchmarkRequest.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.benchmark;
+
+public class BenchmarkRequest {
+    private byte[] payload;
+
+    public BenchmarkRequest() {
+    }
+
+    public BenchmarkRequest(byte[] payload) {
+        this.payload = payload;
+    }
+
+    public byte[] getPayload() {
+        return payload;
+    }
+
+    public void setPayload(byte[] payload) {
+        this.payload = payload;
+    }
+}
diff --git 
a/tools/benchmark/server/dubbo-java/src/main/java/org/apache/dubbo/benchmark/BenchmarkResponse.java
 
b/tools/benchmark/server/dubbo-java/src/main/java/org/apache/dubbo/benchmark/BenchmarkResponse.java
new file mode 100644
index 000000000..15c3e6be9
--- /dev/null
+++ 
b/tools/benchmark/server/dubbo-java/src/main/java/org/apache/dubbo/benchmark/BenchmarkResponse.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.benchmark;
+
+public class BenchmarkResponse {
+    private byte[] payload;
+
+    public BenchmarkResponse() {
+    }
+
+    public BenchmarkResponse(byte[] payload) {
+        this.payload = payload;
+    }
+
+    public byte[] getPayload() {
+        return payload;
+    }
+
+    public void setPayload(byte[] payload) {
+        this.payload = payload;
+    }
+}
diff --git 
a/tools/benchmark/server/dubbo-java/src/main/java/org/apache/dubbo/benchmark/BenchmarkServer.java
 
b/tools/benchmark/server/dubbo-java/src/main/java/org/apache/dubbo/benchmark/BenchmarkServer.java
new file mode 100644
index 000000000..816fb8efe
--- /dev/null
+++ 
b/tools/benchmark/server/dubbo-java/src/main/java/org/apache/dubbo/benchmark/BenchmarkServer.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.benchmark;
+
+import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@EnableDubbo
+public class BenchmarkServer {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(BenchmarkServer.class);
+
+    public static void main(String[] args) {
+        logger.info("========================================");
+        logger.info("    Dubbo-Java Benchmark Server");
+        logger.info("========================================");
+        logger.info("Dubbo-Java server starting...");
+        logger.info("Server listening on: 127.0.0.1:20001");
+        SpringApplication.run(BenchmarkServer.class, args);
+        logger.info("Server started, waiting for requests...");
+    }
+}
diff --git 
a/tools/benchmark/server/dubbo-java/src/main/java/org/apache/dubbo/benchmark/BenchmarkService.java
 
b/tools/benchmark/server/dubbo-java/src/main/java/org/apache/dubbo/benchmark/BenchmarkService.java
new file mode 100644
index 000000000..ca846b06c
--- /dev/null
+++ 
b/tools/benchmark/server/dubbo-java/src/main/java/org/apache/dubbo/benchmark/BenchmarkService.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.benchmark;
+
+public interface BenchmarkService {
+    BenchmarkResponse unaryCall(BenchmarkRequest request);
+}
diff --git 
a/tools/benchmark/server/dubbo-java/src/main/java/org/apache/dubbo/benchmark/BenchmarkServiceImpl.java
 
b/tools/benchmark/server/dubbo-java/src/main/java/org/apache/dubbo/benchmark/BenchmarkServiceImpl.java
new file mode 100644
index 000000000..bf425a96f
--- /dev/null
+++ 
b/tools/benchmark/server/dubbo-java/src/main/java/org/apache/dubbo/benchmark/BenchmarkServiceImpl.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.benchmark;
+
+import org.apache.dubbo.config.annotation.DubboService;
+
+@DubboService
+public class BenchmarkServiceImpl implements BenchmarkService {
+
+    @Override
+    public BenchmarkResponse unaryCall(BenchmarkRequest request) {
+        return new BenchmarkResponse(request.getPayload());
+    }
+}
diff --git 
a/tools/benchmark/server/dubbo-java/src/main/resources/application.properties 
b/tools/benchmark/server/dubbo-java/src/main/resources/application.properties
new file mode 100644
index 000000000..37f11013e
--- /dev/null
+++ 
b/tools/benchmark/server/dubbo-java/src/main/resources/application.properties
@@ -0,0 +1,7 @@
+server.port=20001
+
+dubbo.application.name=dubbo-java-benchmark
+dubbo.protocol.name=dubbo
+dubbo.protocol.port=20001
+dubbo.registry.address=N/A
+dubbo.scan.base-packages=org.apache.dubbo.benchmark
diff --git a/tools/benchmark/server/grpc/main.go 
b/tools/benchmark/server/grpc/main.go
new file mode 100644
index 000000000..1dffac54c
--- /dev/null
+++ b/tools/benchmark/server/grpc/main.go
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+import (
+       "context"
+       "flag"
+       "fmt"
+       "io"
+       "net"
+       "os"
+       "os/signal"
+       "syscall"
+)
+
+import (
+       "github.com/dubbogo/gost/log/logger"
+
+       "google.golang.org/grpc"
+)
+
+import (
+       benchmark "dubbo.apache.org/dubbo-go/v3/tools/benchmark/proto"
+)
+
+const separator = "========================================"
+
+var (
+       port = flag.Int("port", 50051, "Server port")
+)
+
+type benchmarkServiceImpl struct {
+       benchmark.UnimplementedBenchmarkServiceServer
+}
+
+func (s *benchmarkServiceImpl) UnaryCall(ctx context.Context, req 
*benchmark.BenchmarkRequest) (*benchmark.BenchmarkResponse, error) {
+       return &benchmark.BenchmarkResponse{Payload: req.Payload}, nil
+}
+
+func (s *benchmarkServiceImpl) StreamCall(stream 
benchmark.BenchmarkService_StreamCallServer) error {
+       for {
+               req, err := stream.Recv()
+               if err != nil {
+                       if err == io.EOF {
+                               return nil
+                       }
+                       return err
+               }
+               if err := stream.Send(&benchmark.BenchmarkResponse{Payload: 
req.Payload}); err != nil {
+                       return err
+               }
+       }
+}
+
+func main() {
+       flag.Parse()
+
+       logger.Info(separator)
+       logger.Info("      gRPC Benchmark Server")
+       logger.Info(separator)
+       logger.Infof("[INFO] Port:          %d", *port)
+
+       lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
+       if err != nil {
+               logger.Fatalf("Failed to listen: %v", err)
+       }
+
+       s := grpc.NewServer()
+       benchmark.RegisterBenchmarkServiceServer(s, &benchmarkServiceImpl{})
+
+       go func() {
+               if err := s.Serve(lis); err != nil {
+                       logger.Fatalf("Failed to start server: %v", err)
+               }
+       }()
+
+       logger.Infof("[INFO] Server started, listening on: 127.0.0.1:%d", *port)
+
+       sig := make(chan os.Signal, 1)
+       signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
+       <-sig
+
+       logger.Info("[INFO] Stopping server...")
+       s.GracefulStop()
+       logger.Info("[INFO] Server stopped")
+}

Reply via email to