This commit is contained in:
2026-02-11 10:22:09 +08:00
parent 2cf0d55afa
commit ee2b3a80ce
44 changed files with 3213 additions and 15 deletions

2
.idea/misc.xml generated
View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@@ -1,11 +1,11 @@
-----BEGIN PRIVATE KEY-----
1120cf8793ccb6df2a4a4f371503e9699d1512d2e35d73daa3202c20c8e11731
92cbe1d3631be230ee9541ee877985a90ad2b501b089e2f0a5a6f1b99580aaec
-----END PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
6b68d579030462d7a0232b65a96c19a27bc98fd12ba8e5b09fdc83237ee54191ce8ff77d630341209d26bcd04640cf9e95f96af08718da3d258cef5e6e99bd08
c13154e64419e5febe4c749d2070dea70aa83519ceac2a39da4efbcd9a9485121b202ffa9cc6a7822c046ec959d0a8ba738a5f0010f8863523ed6a386a837be9
-----END PUBLIC KEY-----
-----BEGIN ADDRESS-----
0xfffecbb1ef05e897e8d7f9da10fa13255c5c7b17
0x1664cc33e0c6e2c7573b9c2ff8438862ecd8dce8
-----END ADDRESS-----
-----BEGIN CRYPTO TYPE-----
1

View File

@@ -1,11 +1,11 @@
-----BEGIN PRIVATE KEY-----
23230366ba1af4d9fe798a4891302e6f4d765f2cdb4e47836ceac4a3d5f50967
391db7ce3e7f627656f44db9ec8bd3f2b8626537f90d464d6a87298abac18b32
-----END PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
8bd59280cc6deee3de64d88c45227cf1342a6603607e30099371a0b5ab469e832dc2b72a00f7c3acbc5b40fc6a0fc298ae8545467e67dab4d3037b129c608ba9
46c2de937ba38b9aa93efa9685ea846b54c0c38dda02725a9ecc46c3dbd8f9ccec849fa3f0c656031e5e3c6c572216f9864e591f1b94e7288451337e1cdb04bc
-----END PUBLIC KEY-----
-----BEGIN ADDRESS-----
0x863a9a841c4242c7cab7ab3d5399f41ae21d05f9
0xcfb8fd63efa74f85ae85cc8b1b90b6cab37527d2
-----END ADDRESS-----
-----BEGIN CRYPTO TYPE-----
1

View File

@@ -1,11 +1,11 @@
-----BEGIN PRIVATE KEY-----
3855d3f52955a2ff799d52996fa0828d077d8dbb19242e6bd1d7b3a6f8dfbf29
3a84aba1875141cc011b2202f802fa8f7929dd371c00909af78ef267bbff29da
-----END PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
aeb5629ca59d24e78f0aab53a03405fc6814316a1bdac4fba56385e8639b10d8ab04a53a7b7d94a5138f51ee02de7a7481ff8dc350c1b5d015dfa95273f48025
72141f6b0d2147a91d994109b01885995b32f31d1c1b2b1ef3dcc6ec86f92e462568ad0c5f1bfb02afbb01bc682b15eb85dc2af7b61443e3feee23005ade12fd
-----END PUBLIC KEY-----
-----BEGIN ADDRESS-----
0xdb52dabfe568e15331d302f4d9a411d6993c3606
0x8931c1ede9b32a0e8d740707008a156af2adf985
-----END ADDRESS-----
-----BEGIN CRYPTO TYPE-----
1

View File

@@ -1,11 +1,11 @@
-----BEGIN PRIVATE KEY-----
e9c890670f4af89b804ea94e4068f604170d6c39f428bc04b62e8e2b5d05fdf2
19b62893e08eee9432c5a1f9703722634c6f12cf6ef84d49038eb672e0a72a1f
-----END PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
f7e50297ef82600b324685265cae5b3e9030fd3c8d45b643a1c4316ecfae282b1a241c3f1d42d1d129a24d66f636dcb17b3e0a4ca34b3cb6475f774e1cb0b83a
229e8d0b4d5519540fce3a030947a4e80ace4a8cfc73cc751abc82acf5e31f4a666bc7a9c8a3f64877be59b176e1cd1b5caf0fcc4e258cba8b122c2a1573faee
-----END PUBLIC KEY-----
-----BEGIN ADDRESS-----
0x7843803067240dd872e50a26b254c83bc77d77ed
0x90e1523ceb879f91c04dcf40453b82276ceb680a
-----END ADDRESS-----
-----BEGIN CRYPTO TYPE-----
1

View File

@@ -6,6 +6,12 @@ plugins {
group = 'org.example'
version = '1.0-SNAPSHOT'
// 设置 Java 版本兼容性
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
repositories {
mavenCentral()
}
@@ -27,5 +33,39 @@ test {
}
application {
mainClass = 'com.org.fisco.AccountGenerator'
mainClass = 'com.org.fisco.TPSTest'
}
// 创建 Fat JAR包含所有依赖的可执行jar
tasks.register('fatJar', Jar) {
archiveClassifier = 'all'
archiveFileName = 'tps-test.jar'
manifest {
attributes(
'Main-Class': 'com.org.fisco.TPSTest',
'Implementation-Title': 'FISCO BCOS TPS Test Tool',
'Implementation-Version': version
)
}
// 包含编译后的类
from sourceSets.main.output
// 包含所有运行时依赖
from {
configurations.runtimeClasspath.collect {
it.isDirectory() ? it : zipTree(it)
}
}
// 排除签名文件
exclude 'META-INF/*.SF'
exclude 'META-INF/*.DSA'
exclude 'META-INF/*.RSA'
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
// 让 build 任务依赖 fatJar
build.dependsOn fatJar

View File

@@ -0,0 +1,607 @@
# FISCO BCOS TPS压力测试指南
> **文档版本**: v2.0
> **更新日期**: 2026-02-10
> **适用版本**: FISCO BCOS 2.x / 3.x
---
## 📋 目录
1. [测试工具介绍](#测试工具介绍)
2. [快速开始](#快速开始)
3. [测试参数配置](#测试参数配置)
4. [运行测试](#运行测试)
5. [结果分析](#结果分析)
6. [常见问题排查](#常见问题排查)
7. [性能优化建议](#性能优化建议)
---
## 测试工具介绍
### 🎯 TPSTest.java
本项目提供的 `TPSTest.java` 是一个完整的TPS压测工具具有以下特性
**核心功能:**
- ✅ 自动连接FISCO BCOS节点
- ✅ 使用 ParallelTransfer 合约进行并行转账测试
- ✅ 支持多线程并发压测
- ✅ 实时监控TPS、成功率
- ✅ 自动生成详细测试报告
- ✅ 支持QPS限流控制
**测试原理:**
```
多线程并发 → 发送转账交易 → 统计响应时间 → 计算TPS和延迟
```
**文件位置:**
```
src/main/java/com/org/fisco/TPSTest.java
```
---
## 快速开始
### 前提条件
1. **合约已部署**
- 合约地址在代码第284行设置
- 默认使用:`0x06ac2fe406f1ae06494946ee281d58f1c79c39e4`
2. **账户已初始化**
- 使用 `fisco/console/init_accounts.sh` 脚本初始化账户余额
- 或手动在控制台初始化至少100个账户
3. **SDK配置正确**
- 配置文件:`src/main/resources/config.toml`
- 确保能连接到你的链节点
### 5分钟快速测试
```bash
cd /Users/kiro/IdeaProjects/contract
# 1. 编译项目
./gradlew build
# 2. 直接运行测试
./gradlew run
```
测试会自动:
1. 连接到链节点
2. 初始化合约对象
3. 生成测试账户
4. 开始压测
5. 输出测试报告
---
## 测试参数配置
### 🔧 核心参数说明
`TPSTest.java``main` 方法中第277-281行配置
```java
tester.setTestParams(
threadCount, // 并发线程数
totalTransactions, // 总交易数
qpsLimit // QPS限制0表示不限制
);
```
### 参数详解
#### 1. 并发线程数 (threadCount)
**作用:** 控制同时发送交易的线程数量
**推荐值:**
| 测试场景 | 推荐值 | 说明 |
|---------|--------|------|
| 基准测试 | 1 | 测试单笔交易延迟 |
| 初步压测 | 50-100 | 找到基本TPS水平 |
| 寻找峰值 | 100-200 | 逐步增加找峰值 |
| 极限压测 | 200-500 | 测试系统极限 |
**⚠️ 注意:**
- 并发数过高会导致成功率下降
- 并发数过低无法达到TPS峰值
- **建议从小到大逐步测试**
#### 2. 总交易数 (totalTransactions)
**作用:** 本次测试发送的交易总数
**推荐值:**
| 测试类型 | 推荐值 | 测试时长(估算) |
|---------|--------|----------------|
| 快速验证 | 1,000 | 1-5秒 |
| 基础测试 | 10,000 | 10-30秒 |
| 标准测试 | 50,000 | 1-2分钟 |
| 长期测试 | 100,000+ | 5分钟以上 |
**原则:**
- ✅ 测试时长至少30秒以上才准确
- ✅ 交易数太少会受启动开销影响
- ✅ 交易数太多会耗时过长
#### 3. QPS限制 (qpsLimit)
**作用:** 限制每秒发送的交易数
**设置建议:**
- `0`:不限制,全力压测(推荐)
- `5000`:温和测试,适合生产环境验证
- `10000+`:根据节点能力设置上限
---
## 运行测试
### 方法1使用默认参数运行
```bash
cd /Users/kiro/IdeaProjects/contract
./gradlew run
```
### 方法2修改参数后运行
编辑 `src/main/java/com/org/fisco/TPSTest.java`
```java
// 第277-281行
tester.setTestParams(
100, // 改为你想要的并发数
10000, // 改为你想要的交易总数
0 // 0表示不限速
);
```
然后运行:
```bash
./gradlew build && ./gradlew run
```
### 观察实时输出
测试运行时会显示:
```
========================================
FISCO BCOS TPS压力测试工具
========================================
连接FISCO BCOS节点成功
当前区块高度: 12345
使用已部署的合约地址: 0x06ac...
合约对象初始化完成
生成测试账户列表...
已生成 100 个测试账户
账户列表生成完成,账户余额已通过 init_accounts.sh 脚本初始化
[3/3] 开始压力测试...
测试配置:
- 并发线程数: 100
- 总交易数: 10000
- QPS限制: 无限制
- 预热交易数: 100
正在预热 (100 笔交易)...
预热完成!
开始正式压测...
实时TPS监控 (每5秒更新):
当前进度: 2145/10000 | 实时TPS: 675.64 | 成功率: 99.87%
当前进度: 4523/10000 | 实时TPS: 682.31 | 成功率: 99.91%
...
```
---
## 结果分析
### 📊 测试报告解读
测试完成后会自动生成报告(同时保存到文件):
```
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 15:30:00
结束时间: 2026-02-10 15:32:15
测试时长: 135.45 秒
并发线程数: 100
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 9987
失败交易: 13
成功率: 99.87%
性能指标:
★ TPS (每秒交易数): 675.64
平均延迟: 148.23 ms
中位数延迟: 125 ms
P95延迟: 287 ms
P99延迟: 456 ms
报告时间: 2026-02-10 15:32:15
========================================
```
### 📈 核心指标说明
#### 1. TPS每秒交易数
**含义:** 每秒成功处理的交易数量
**评判标准:**
| TPS范围 | 评价 | 说明 |
|---------|------|------|
| > 1000 | 优秀 ✅ | 性能良好 |
| 500-1000 | 良好 👍 | 基本满足需求 |
| 100-500 | 一般 ⚠️ | 需要优化 |
| < 100 | 较差 | 存在严重问题 |
**影响因素:**
- 节点配置CPU内存磁盘
- 网络延迟
- 并发线程数
- 节点 config.ini 配置
#### 2. 成功率
**含义:** 成功交易数 / 总交易数
**评判标准:**
- 99%健康状态
- 95-99%压力过大需降低并发
- < 95%存在严重问题
**低成功率原因:**
- 并发数设置过高
- 交易池容量不足
- 节点资源不足
- 账户余额不足
#### 3. 延迟指标
**平均延迟:** 所有交易的平均响应时间
**P95延迟** 95%的交易在此时间内完成
**P99延迟** 99%的交易在此时间内完成
**评判标准:**
| 指标 | 优秀 | 良好 | 一般 | 需优化 |
|------|------|------|------|--------|
| 平均延迟 | <100ms | 100-300ms | 300-500ms | >500ms |
| P99延迟 | <500ms | 500-1000ms | 1-2s | >2s |
---
## 常见问题排查
### ❌ 问题1TPS很低<100
**可能原因及解决方案:**
1. **网络延迟过高**
```bash
# 测试网络延迟
ping -c 10 121.196.226.157
```
- 延迟 > 100ms考虑在云服务器上直接运行测试
- 延迟 > 50msTPS会受明显影响
2. **节点配置未优化**
SSH到云服务器检查 `config.ini`
```bash
cd ~/fisco/nodes/*/node0
cat config.ini | grep -A 3 "\[tx_execute\]"
cat config.ini | grep -A 3 "\[consensus\]"
```
确认配置:
```ini
[tx_execute]
enable_parallel=true # 必须为true
[consensus]
max_trans_num_per_block=1000 # 建议≥1000
```
3. **日志级别过低**
```ini
[log]
level=error # 改为error减少IO开销
```
### ❌ 问题2成功率低<99%
**排查步骤:**
1. **检查错误日志**
测试运行时会输出错误信息:
```
交易失败 - Status: 18, Message: ...
交易异常: ContractException - ...
```
2. **降低并发数**
如果成功率 < 99%,说明并发过高:
```java
// 从当前并发数降低50%
tester.setTestParams(
50, // 从100降到50
10000,
0
);
```
3. **检查账户余额**
```bash
cd fisco/console
bash start.sh
# 在控制台执行
call ParallelTransfer 0x06ac... balanceOf "user_000000"
```
### ❌ 问题3程序运行时资源耗尽
**现象:** 出现大量线程创建失败错误
**原因:** 之前的bug每笔交易创建新合约对象已修复
**确认修复:** 检查代码第29行是否有
```java
private ParallelTransfer contract; // 复用合约对象
```
### ❌ 问题4程序一直不退出
**原因:** SDK后台线程持续运行
**解决:** 已在代码第318行添加
```java
System.exit(0);
```
如果仍然卡住,按 `Ctrl+C` 强制终止。
---
## 性能优化建议
### 🎯 找到准确TPS的方法
**错误做法 ❌:**
- 用最高并发数跑一次就认为是TPS
- 忽略成功率指标
- 测试时间过短(<10秒
**正确做法 ✅:**
#### 阶段1基准测试
```java
tester.setTestParams(1, 100, 0); // 单线程
```
记录:平均延迟 = X ms
#### 阶段2二分法找最佳并发
逐步测试找到成功率≥99%的最大并发数:
| 轮次 | 并发数 | 交易数 | 观察 |
|------|--------|--------|------|
| 测试1 | 50 | 5000 | 成功率≥99% |
| 测试2 | 100 | 5000 | 成功率≥99% |
| 测试3 | 200 | 5000 | 成功率≥99% |
| 测试4 | 400 | 5000 | 成功率<99%则停止 |
**结论:** 成功率≥99%的最大并发数 = 最佳并发数
#### 阶段3峰值测试
```java
tester.setTestParams(
[最佳并发数], // 从阶段2得到
50000, // 大批量测试
0
);
```
**这就是你链的真实TPS**
### 🔧 节点优化Checklist
#### 云服务器配置
SSH到服务器编辑 `config.ini`
```ini
[tx_execute]
enable_parallel=true # ✅ 开启并行
[consensus]
max_trans_num_per_block=1000 # ✅ 每块至少1000笔
[tx_pool]
limit=150000 # ✅ 交易池容量
[log]
level=error # ✅ 降低日志级别
```
重启节点:
```bash
cd ~/fisco/nodes/*/
bash stop_all.sh
bash start_all.sh
```
#### 系统优化
```bash
# 增加文件描述符
ulimit -n 65535
# 检查磁盘类型必须是SSD
lsblk -d -o name,rota
# rota=0 表示SSD
```
### 📊 并发数与TPS的关系
**理论公式:**
```
TPS = 并发数 / 平均延迟(秒)
```
**示例:**
- 平均延迟 = 100ms = 0.1秒
- 并发数 = 100
- 理论TPS = 100 / 0.1 = **1000**
**实际调优:**
| 并发数 | TPS | 成功率 | 决策 |
|--------|-----|--------|------|
| 50 | 400 | 100% | ⬆️ 继续增加 |
| 100 | 700 | 99.8% | ⬆️ 可以继续 |
| 200 | 850 | 99.2% | ⬆️ 接近最佳 |
| 400 | 870 | 97% | ❌ 过高,回退 |
**最佳并发数 = 200**
---
## 测试结果记录模板
建议每次测试记录:
```
测试日期: 2026-02-10
测试轮次: 第X次
测试参数:
- 并发线程数:
- 总交易数:
- QPS限制:
测试环境:
- 节点数量: 4个
- 网络延迟: XXms
- enable_parallel: true/false
- max_trans_num_per_block: XXX
测试结果:
- TPS:
- 成功率:
- 平均延迟:
- P99延迟:
问题记录:
优化措施:
下次改进:
```
---
## 快速参考
### 常用命令
```bash
# 编译运行测试
cd /Users/kiro/IdeaProjects/contract
./gradlew build && ./gradlew run
# 查看最近的测试报告
ls -lt tps_test_report_*.txt | head -5
cat tps_test_report_*.txt
# 测试网络延迟
ping -c 10 121.196.226.157
# 检查节点配置SSH到服务器
ssh root@121.196.226.157
cd ~/fisco/nodes/*/node0
cat config.ini | grep -E "enable_parallel|max_trans_num_per_block|limit|level"
```
### 推荐测试流程
```bash
# 1. 基准测试修改代码为1线程100笔
./gradlew run
# 2. 初步压测修改代码为100线程10000笔
./gradlew run
# 3. 根据成功率调整并发数
# 成功率≥99% → 增加并发
# 成功率<99% → 减少并发
# 4. 峰值测试用最佳并发数跑50000笔
./gradlew run
```
---
## 常见TPS参考值
| 区块链 | 单链TPS | 备注 |
|--------|---------|------|
| FISCO BCOS v2.x | 500-2000 | enable_parallel=true |
| FISCO BCOS v3.x | 2000-5000 | 性能优化版 |
| Hyperledger Fabric | 1000-3000 | 企业级联盟链 |
| 以太坊 | 15-30 | 公链 |
**你的目标:** 根据节点配置,达到 **500-1000 TPS** 即为良好水平。
---
## 总结
### ✅ 正确的测试姿势
1. **从小到大测试**1线程 → 50线程 → 100线程 → 200线程
2. **关注成功率**必须≥99%,否则降低并发
3. **测试足够久**至少30秒以上
4. **记录每次结果**:对比优化前后差异
### ⚠️ 常见误区
1. ❌ 用最高并发测出来的数字就是TPS
2. ❌ 忽略成功率指标
3. ❌ 测试时间太短
4. ❌ 不检查节点配置
5. ❌ 网络延迟过高还在本地测试
### 🎯 核心原则
**准确的TPS = 在成功率≥99%的前提下能持续达到的最高TPS**
---
**祝测试顺利!** 🚀
有问题请查看"常见问题排查"章节,或检查测试报告中的错误信息。

View File

@@ -0,0 +1,742 @@
# 服务器部署运行指南
> TPS测试工具服务器部署和使用说明
---
## 📦 打包部署包
### 1. 在本地打包
```bash
cd /Users/kiro/IdeaProjects/contract
# 清理并打包(使用 fatJar 任务)
./gradlew clean fatJar
# 查看生成的 jar 文件
ls -lh build/libs/tps-test.jar
```
**输出:** `build/libs/tps-test.jar` (约 25MB包含所有依赖
**注意:** 必须使用 `./gradlew fatJar` 命令打包这样才会生成包含所有依赖的可执行jar文件。
### 2. 准备部署文件
需要上传到服务器的文件:
```
部署包/
├── tps-test.jar # 可执行jar必需
└── config.toml # 链连接配置(必需)
```
从本地复制配置文件:
```bash
# 复制配置文件到 build 目录
cp src/main/resources/config.toml build/libs/
```
---
## 🚀 上传到服务器
### 方法1使用 SCP 上传
```bash
# 1. 创建本地部署目录
cd /Users/kiro/IdeaProjects/contract
mkdir -p deploy
cp build/libs/tps-test.jar deploy/
cp src/main/resources/config.toml deploy/
# 2. 上传到服务器
scp -r deploy/* root@121.196.226.157:~/tps-test/
# 如果需要上传到第二台服务器
scp -r deploy/* root@8.137.93.11:~/tps-test/
```
### 方法2使用 rsync 上传(推荐)
```bash
# 自动创建目录并上传
rsync -avz --progress \
build/libs/tps-test.jar \
src/main/resources/config.toml \
root@121.196.226.157:~/tps-test/
```
---
## ⚙️ 服务器端配置
### 1. SSH 登录到服务器
```bash
ssh root@121.196.226.157
```
### 2. 检查 Java 环境
```bash
# 检查 Java 版本(需要 JDK 11+
java -version
# 如果没有安装,安装 OpenJDK
# Ubuntu/Debian
sudo apt update && sudo apt install -y openjdk-11-jdk
# CentOS/RHEL
sudo yum install -y java-11-openjdk
```
### 3. 验证文件
```bash
cd ~/tps-test
ls -lh
# 应该看到:
# tps-test.jar (约 30-40MB)
# config.toml
```
### 4. 修改配置文件(如需要)
```bash
# 编辑配置文件,确保连接到本地节点
vim config.toml
```
**如果在服务器上运行,建议使用本地地址:**
```toml
[network]
peers=["127.0.0.1:20200"] # 使用本地节点,延迟最低
```
---
## 🎯 运行测试
### 基本用法
```bash
cd ~/tps-test
# 查看帮助
java -jar tps-test.jar --help
# 使用默认参数100线程10000笔交易
java -jar tps-test.jar -c 0x06ac2fe406f1ae06494946ee281d58f1c79c39e4
```
### 命令行参数说明
| 参数 | 简写 | 说明 | 默认值 |
|------|------|------|--------|
| `--threads` | `-t` | 并发线程数 | 100 |
| `--transactions` | `-n` | 总交易数 | 10000 |
| `--qps` | `-q` | QPS限制0表示不限 | 0 |
| `--contract` | `-c` | **合约地址(必填)** | 无 |
| `--accounts` | `-a` | 测试账户数 | 100 |
| `--help` | `-h` | 显示帮助 | - |
### 常用测试场景
#### 场景1快速验证1000笔
```bash
java -jar tps-test.jar \
-t 50 \
-n 1000 \
-c 0x06ac2fe406f1ae06494946ee281d58f1c79c39e4
```
#### 场景2标准压测10000笔
```bash
java -jar tps-test.jar \
-t 100 \
-n 10000 \
-c 0x06ac2fe406f1ae06494946ee281d58f1c79c39e4
```
#### 场景3大规模压测50000笔
```bash
java -jar tps-test.jar \
-t 200 \
-n 50000 \
-c 0x06ac2fe406f1ae06494946ee281d58f1c79c39e4
```
#### 场景4极限压测100000笔
```bash
java -jar tps-test.jar \
-t 500 \
-n 100000 \
-c 0x06ac2fe406f1ae06494946ee281d58f1c79c39e4
```
#### 场景5限速测试
```bash
# 限制 QPS 为 5000
java -jar tps-test.jar \
-t 100 \
-n 50000 \
-q 5000 \
-c 0x06ac2fe406f1ae06494946ee281d58f1c79c39e4
```
---
## 📊 后台运行和日志管理
### 1. 后台运行测试
```bash
# 使用 nohup 后台运行,输出重定向到日志文件
nohup java -jar tps-test.jar \
-t 200 \
-n 100000 \
-c 0x06ac2fe406f1ae06494946ee281d58f1c79c39e4 \
> tps_test.log 2>&1 &
# 查看进程
ps aux | grep tps-test
# 实时查看日志
tail -f tps_test.log
```
### 2. 使用 screen推荐
```bash
# 安装 screen如果没有
sudo apt install screen # Ubuntu/Debian
sudo yum install screen # CentOS/RHEL
# 创建新会话
screen -S tps-test
# 运行测试
java -jar tps-test.jar -t 200 -n 100000 -c 0x06ac...
# 断开会话按键Ctrl+A然后按 D
# 重新连接screen -r tps-test
# 查看所有会话screen -ls
```
### 3. 查看测试报告
```bash
# 测试完成后,会生成报告文件
ls -lt tps_test_report_*.txt | head -5
# 查看最新报告
cat $(ls -t tps_test_report_*.txt | head -1)
```
---
## 🔧 批量测试脚本
创建一个自动化测试脚本:
```bash
# 创建测试脚本
cat > run_tps_tests.sh << 'EOF'
#!/bin/bash
# TPS 自动化测试脚本
CONTRACT="0x06ac2fe406f1ae06494946ee281d58f1c79c39e4"
JAR="tps-test.jar"
echo "======================================"
echo " FISCO BCOS TPS 自动化测试"
echo "======================================"
echo ""
# 测试配置数组(线程数 交易数 描述)
tests=(
"50:5000:快速验证"
"100:10000:基础压测"
"200:10000:中等压测"
"400:10000:高并发压测"
)
# 循环执行测试
for test in "${tests[@]}"; do
IFS=':' read -r threads txs desc <<< "$test"
echo ""
echo "======================================"
echo "测试: $desc"
echo "并发数: $threads, 交易数: $txs"
echo "======================================"
echo ""
java -jar $JAR -t $threads -n $txs -c $CONTRACT
echo ""
echo "等待10秒后开始下一轮测试..."
sleep 10
done
echo ""
echo "======================================"
echo "所有测试完成!"
echo "======================================"
# 汇总报告
echo ""
echo "测试报告列表:"
ls -lt tps_test_report_*.txt | head -10
EOF
# 给脚本添加执行权限
chmod +x run_tps_tests.sh
# 运行自动化测试
./run_tps_tests.sh
```
---
## 📈 分阶段找准确TPS的脚本
基于文档中推荐的测试方法:
```bash
cat > find_optimal_tps.sh << 'EOF'
#!/bin/bash
# 二分法找最佳TPS脚本
CONTRACT="0x06ac2fe406f1ae06494946ee281d58f1c79c39e4"
JAR="tps-test.jar"
echo "======================================"
echo " 寻找最佳 TPS 配置"
echo "======================================"
echo ""
# 阶段1基准测试
echo "[阶段1] 基准测试(单线程)"
java -jar $JAR -t 1 -n 100 -c $CONTRACT
echo ""
read -p "按 Enter 继续..."
# 阶段2逐步增加并发
threads_list=(50 100 200 400)
for threads in "${threads_list[@]}"; do
echo ""
echo "======================================"
echo "[阶段2] 测试 $threads 线程"
echo "======================================"
echo ""
java -jar $JAR -t $threads -n 5000 -c $CONTRACT
echo ""
read -p "成功率是否 ≥99%(y/n): " answer
if [ "$answer" != "y" ]; then
echo "成功率低于99%,建议使用上一个并发数"
last_good=$((threads / 2))
echo "建议最佳并发数: $last_good"
echo ""
read -p "是否用最佳并发数运行峰值测试?(y/n): " peak_test
if [ "$peak_test" = "y" ]; then
echo ""
echo "======================================"
echo "[阶段3] 峰值测试"
echo "======================================"
echo ""
java -jar $JAR -t $last_good -n 50000 -c $CONTRACT
fi
break
fi
done
echo ""
echo "======================================"
echo "测试完成!"
echo "======================================"
EOF
chmod +x find_optimal_tps.sh
./find_optimal_tps.sh
```
---
## 🔍 监控和诊断
### 1. 实时监控测试进程
```bash
# 监控 CPU 和内存
top -p $(pgrep -f tps-test.jar)
# 监控网络连接
watch -n 1 'netstat -antp | grep 20200'
```
### 2. 查看节点日志
```bash
# 查看节点日志
tail -f ~/fisco/nodes/*/node0/log/log* | grep -E "ERROR|TPS"
# 查看交易池状态
cd ~/fisco/console
bash start.sh
# 执行getPendingTxSize
```
### 3. 系统资源监控
```bash
# 整体系统监控
htop
# 磁盘 IO
iostat -x 1
# 网络流量
iftop -i eth0
```
---
## ⚠️ 常见问题
### 问题1找不到或无法加载主类
**错误信息:**
```
Error: Could not find or load main class com.org.fisco.TPSTest
```
**原因:** jar文件打包不正确缺少依赖类
**解决:**
```bash
# 1. 必须使用 fatJar 任务打包
cd /Users/kiro/IdeaProjects/contract
./gradlew clean fatJar
# 2. 验证jar文件可以运行
java -jar build/libs/tps-test.jar --help
# 3. 重新上传到服务器
scp build/libs/tps-test.jar root@服务器IP:~/tps-test/
```
**注意:** 不要使用 `./gradlew build`,必须使用 `./gradlew fatJar`
### 问题2找不到 config.toml
**错误信息:**
```
错误: 找不到配置文件 config.toml
```
**解决:**
```bash
# 确保 config.toml 在当前目录
cd ~/tps-test
ls config.toml
# 或者从 console 复制
cp ~/fisco/console/conf/config.toml .
```
### 问题3连接节点失败
**错误信息:**
```
连接FISCO BCOS节点失败
```
**解决:**
```bash
# 1. 检查节点是否运行
ps aux | grep fisco-bcos
# 2. 检查端口是否监听
netstat -tlnp | grep 20200
# 3. 测试连接
telnet 127.0.0.1 20200
# 4. 修改 config.toml 使用正确的地址
vim config.toml
```
### 问题4内存不足
**错误信息:**
```
java.lang.OutOfMemoryError
```
**解决:**
```bash
# 增加 JVM 内存
java -Xmx4g -Xms2g -jar tps-test.jar -t 200 -n 50000 -c 0x06ac...
```
### 问题5程序卡住不动
**排查:**
```bash
# 1. 查看是否有错误日志
tail -100 tps_test.log
# 2. 检查网络连接
netstat -antp | grep 20200
# 3. 检查节点是否正常
cd ~/fisco/nodes/*/node0
tail -50 log/log*
```
---
## 🎯 最佳实践
### 1. 在服务器上测试的优势
**延迟更低**:本地网络延迟通常 < 1ms
**TPS更高**网络不是瓶颈
**结果更准**排除网络抖动影响
### 2. 推荐的测试流程
```bash
# 第一步:快速验证
java -jar tps-test.jar -t 50 -n 1000 -c 0x06ac...
# 第二步:基础测试
java -jar tps-test.jar -t 100 -n 10000 -c 0x06ac...
# 第三步:根据成功率调整
# 如果成功率 ≥ 99%,增加并发到 200
# 如果成功率 < 99%,保持或降低并发
# 第四步:峰值测试
java -jar tps-test.jar -t [最佳并发] -n 50000 -c 0x06ac...
```
### 3. 参数选择建议
| 节点配置 | 推荐并发数 | 推荐交易数 |
|---------|----------|----------|
| 2C4G | 50-100 | 10000 |
| 4C8G | 100-200 | 50000 |
| 8C16G | 200-500 | 100000 |
---
## 📝 测试记录模板
建议每次测试记录
```bash
# 创建测试记录文件
cat > test_record_$(date +%Y%m%d).md << 'EOF'
# TPS测试记录
## 测试日期
2026-02-10
## 测试环境
- 服务器: 121.196.226.157
- 节点配置: 4C8G SSD
- enable_parallel: true
- max_trans_num_per_block: 1000
## 测试结果
### 测试1
- 命令: java -jar tps-test.jar -t 100 -n 10000 -c 0x06ac...
- TPS:
- 成功率:
- 平均延迟:
### 测试2
- 命令:
- TPS:
- 成功率:
- 平均延迟:
## 结论
最佳并发数:
峰值TPS:
## 优化建议
EOF
vim test_record_$(date +%Y%m%d).md
```
---
## 🔄 更新部署
当代码有更新时
```bash
# 本地重新打包
cd /Users/kiro/IdeaProjects/contract
./gradlew clean fatJar
# 验证jar可以运行
java -jar build/libs/tps-test.jar --help
# 上传到服务器(覆盖旧版本)
scp build/libs/tps-test.jar root@121.196.226.157:~/tps-test/
# 服务器上重新运行测试
ssh root@121.196.226.157
cd ~/tps-test
java -jar tps-test.jar -t 100 -n 10000 -c 0x06ac...
```
---
## 📞 快速命令参考
```bash
# 本地打包
cd /Users/kiro/IdeaProjects/contract
./gradlew clean fatJar
# 验证打包(本地测试)
java -jar build/libs/tps-test.jar --help
# 上传到服务器
scp build/libs/tps-test.jar src/main/resources/config.toml root@121.196.226.157:~/tps-test/
# SSH到服务器运行
ssh root@121.196.226.157
cd ~/tps-test
# 测试帮助
java -jar tps-test.jar --help
# 运行测试
java -jar tps-test.jar -t 100 -n 10000 -c 0x06ac2fe406f1ae06494946ee281d58f1c79c39e4
# 查看报告
cat $(ls -t tps_test_report_*.txt | head -1)
```
---
## 🎓 完整部署示例
### 从零开始的完整流程
```bash
# ========================================
# 第一步:在本地打包
# ========================================
cd /Users/kiro/IdeaProjects/contract
# 清理并打包
./gradlew clean fatJar
# 验证jar文件
java -jar build/libs/tps-test.jar --help
# 应该显示帮助信息,如果报错说明打包有问题
# ========================================
# 第二步:准备部署文件
# ========================================
mkdir -p deploy
cp build/libs/tps-test.jar deploy/
cp src/main/resources/config.toml deploy/
# 查看文件
ls -lh deploy/
# 应该看到:
# tps-test.jar (约 25MB)
# config.toml
# ========================================
# 第三步:上传到服务器
# ========================================
# 方式1使用 scp
scp deploy/tps-test.jar deploy/config.toml root@121.196.226.157:~/tps-test/
# 方式2使用 rsync推荐
rsync -avz --progress deploy/* root@121.196.226.157:~/tps-test/
# ========================================
# 第四步SSH到服务器配置
# ========================================
ssh root@121.196.226.157
# 进入目录
cd ~/tps-test
# 检查文件
ls -lh
# 应该看到 tps-test.jar 和 config.toml
# 检查Java版本需要JDK 11+
java -version
# 编辑配置文件,使用本地节点地址
vim config.toml
# 修改为peers=["127.0.0.1:20200"]
# 测试jar文件
java -jar tps-test.jar --help
# 应该显示帮助信息
# ========================================
# 第五步:运行测试
# ========================================
# 快速验证1000笔
java -jar tps-test.jar -t 50 -n 1000 -c 0x06ac2fe406f1ae06494946ee281d58f1c79c39e4
# 如果上面的测试成功,运行正式测试
java -jar tps-test.jar -t 100 -n 10000 -c 0x06ac2fe406f1ae06494946ee281d58f1c79c39e4
# 查看生成的报告
cat $(ls -t tps_test_report_*.txt | head -1)
```
---
## 🔍 验证清单
部署后请按此清单验证
- [ ] jar文件大小约25MB太小说明没打包依赖
- [ ] 本地能运行 `java -jar build/libs/tps-test.jar --help`
- [ ] 服务器上能显示帮助信息
- [ ] config.toml 配置了正确的节点地址
- [ ] 能连接到节点显示区块高度
- [ ] 测试能正常运行并生成报告
---
**祝测试顺利!** 🚀

View File

@@ -0,0 +1,252 @@
package org.com.fisco;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.fisco.bcos.sdk.abi.FunctionReturnDecoder;
import org.fisco.bcos.sdk.abi.TypeReference;
import org.fisco.bcos.sdk.abi.datatypes.Bool;
import org.fisco.bcos.sdk.abi.datatypes.Event;
import org.fisco.bcos.sdk.abi.datatypes.Function;
import org.fisco.bcos.sdk.abi.datatypes.Type;
import org.fisco.bcos.sdk.abi.datatypes.Utf8String;
import org.fisco.bcos.sdk.abi.datatypes.generated.Uint256;
import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple1;
import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2;
import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple3;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.contract.Contract;
import org.fisco.bcos.sdk.crypto.CryptoSuite;
import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.eventsub.EventCallback;
import org.fisco.bcos.sdk.model.CryptoType;
import org.fisco.bcos.sdk.model.TransactionReceipt;
import org.fisco.bcos.sdk.model.callback.TransactionCallback;
import org.fisco.bcos.sdk.transaction.model.exception.ContractException;
@SuppressWarnings("unchecked")
public class ParallelTransfer extends Contract {
public static final String[] BINARY_ARRAY = {"608060405234801561001057600080fd5b5061067f806100206000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806335ee5f871461005c5780638a42ebe9146100d95780639b80b05014610164575b600080fd5b34801561006857600080fd5b506100c3600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610235565b6040518082815260200191505060405180910390f35b3480156100e557600080fd5b5061014a600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001909291905050506102a9565b604051808215151515815260200191505060405180910390f35b34801561017057600080fd5b5061021b600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001909291905050506103c9565b604051808215151515815260200191505060405180910390f35b600080826040518082805190602001908083835b60208310151561026e5780518252602082019150602081019050602083039250610249565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020549050919050565b6000816000846040518082805190602001908083835b6020831015156102e457805182526020820191506020810190506020830392506102bf565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020819055507fedf5e4fbc41240253887c57b73bdead5653cd408f92653efbb6cb02835878f1d83836040518080602001838152602001828103825284818151815260200191508051906020019080838360005b83811015610384578082015181840152602081019050610369565b50505050905090810190601f1680156103b15780820380516001836020036101000a031916815260200191505b50935050505060405180910390a16001905092915050565b6000816000856040518082805190602001908083835b60208310151561040457805182526020820191506020810190506020830392506103df565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020541015151561044557600080fd5b816000856040518082805190602001908083835b60208310151561047e5780518252602082019150602081019050602083039250610459565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902060008282540392505081905550816000846040518082805190602001908083835b6020831015156104f757805182526020820191506020810190506020830392506104d2565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020600082825401925050819055507f0330d309c76066247312f39e9d58dd5b00d4746f169284ac6e3835f6ea07484b848484604051808060200180602001848152602001838103835286818151815260200191508051906020019080838360005b838110156105a557808201518184015260208101905061058a565b50505050905090810190601f1680156105d25780820380516001836020036101000a031916815260200191505b50838103825285818151815260200191508051906020019080838360005b8381101561060b5780820151818401526020810190506105f0565b50505050905090810190601f1680156106385780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a16001905093925050505600a165627a7a723058201e9804ebdeb9c0397abfc6f7eeadb97d2565b57eb91245f4864623800f25aa2e0029"};
public static final String BINARY = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", BINARY_ARRAY);
public static final String[] SM_BINARY_ARRAY = {"608060405234801561001057600080fd5b5061067f806100206000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063612d2bff1461005c578063cd93c25d1461012d578063f2f4ee6d146101aa575b600080fd5b34801561006857600080fd5b50610113600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929080359060200190929190505050610235565b604051808215151515815260200191505060405180910390f35b34801561013957600080fd5b50610194600480360381019080803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506104bf565b6040518082815260200191505060405180910390f35b3480156101b657600080fd5b5061021b600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929080359060200190929190505050610533565b604051808215151515815260200191505060405180910390f35b6000816000856040518082805190602001908083835b602083101515610270578051825260208201915060208101905060208303925061024b565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902054101515156102b157600080fd5b816000856040518082805190602001908083835b6020831015156102ea57805182526020820191506020810190506020830392506102c5565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902060008282540392505081905550816000846040518082805190602001908083835b602083101515610363578051825260208201915060208101905060208303925061033e565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020600082825401925050819055507fc2a2916bcd9b97e315313bf3748b5c215a3a399633f7d1cde7b55db8e500c784848484604051808060200180602001848152602001838103835286818151815260200191508051906020019080838360005b838110156104115780820151818401526020810190506103f6565b50505050905090810190601f16801561043e5780820380516001836020036101000a031916815260200191505b50838103825285818151815260200191508051906020019080838360005b8381101561047757808201518184015260208101905061045c565b50505050905090810190601f1680156104a45780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a1600190509392505050565b600080826040518082805190602001908083835b6020831015156104f857805182526020820191506020810190506020830392506104d3565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020549050919050565b6000816000846040518082805190602001908083835b60208310151561056e5780518252602082019150602081019050602083039250610549565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020819055507f0596d2b9710318c05b80b92422c73d44ef236e2d1e4f7c6f9122213d2d21216083836040518080602001838152602001828103825284818151815260200191508051906020019080838360005b8381101561060e5780820151818401526020810190506105f3565b50505050905090810190601f16801561063b5780820380516001836020036101000a031916815260200191505b50935050505060405180910390a160019050929150505600a165627a7a72305820e98be5dd9ae36682f9e427b573d5a836e23a6a087c94d68f7bc42e7e432559840029"};
public static final String SM_BINARY = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", SM_BINARY_ARRAY);
public static final String[] ABI_ARRAY = {"[{\"constant\":true,\"inputs\":[{\"name\":\"user\",\"type\":\"string\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"user\",\"type\":\"string\"},{\"name\":\"balance\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"string\"},{\"name\":\"to\",\"type\":\"string\"},{\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"from\",\"type\":\"string\"},{\"indexed\":false,\"name\":\"to\",\"type\":\"string\"},{\"indexed\":false,\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"TransferEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"user\",\"type\":\"string\"},{\"indexed\":false,\"name\":\"balance\",\"type\":\"uint256\"}],\"name\":\"SetEvent\",\"type\":\"event\"}]"};
public static final String ABI = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", ABI_ARRAY);
public static final String FUNC_BALANCEOF = "balanceOf";
public static final String FUNC_SET = "set";
public static final String FUNC_TRANSFER = "transfer";
public static final Event TRANSFEREVENT_EVENT = new Event("TransferEvent",
Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {}, new TypeReference<Utf8String>() {}, new TypeReference<Uint256>() {}));
;
public static final Event SETEVENT_EVENT = new Event("SetEvent",
Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {}, new TypeReference<Uint256>() {}));
;
protected ParallelTransfer(String contractAddress, Client client, CryptoKeyPair credential) {
super(getBinary(client.getCryptoSuite()), contractAddress, client, credential);
}
public static String getBinary(CryptoSuite cryptoSuite) {
return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY);
}
public BigInteger balanceOf(String user) throws ContractException {
final Function function = new Function(FUNC_BALANCEOF,
Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user)),
Arrays.<TypeReference<?>>asList(new TypeReference<Uint256>() {}));
return executeCallWithSingleValueReturn(function, BigInteger.class);
}
public TransactionReceipt set(String user, BigInteger balance) {
final Function function = new Function(
FUNC_SET,
Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user),
new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(balance)),
Collections.<TypeReference<?>>emptyList());
return executeTransaction(function);
}
public byte[] set(String user, BigInteger balance, TransactionCallback callback) {
final Function function = new Function(
FUNC_SET,
Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user),
new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(balance)),
Collections.<TypeReference<?>>emptyList());
return asyncExecuteTransaction(function, callback);
}
public String getSignedTransactionForSet(String user, BigInteger balance) {
final Function function = new Function(
FUNC_SET,
Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user),
new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(balance)),
Collections.<TypeReference<?>>emptyList());
return createSignedTransaction(function);
}
public Tuple2<String, BigInteger> getSetInput(TransactionReceipt transactionReceipt) {
String data = transactionReceipt.getInput().substring(10);
final Function function = new Function(FUNC_SET,
Arrays.<Type>asList(),
Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {}, new TypeReference<Uint256>() {}));
List<Type> results = FunctionReturnDecoder.decode(data, function.getOutputParameters());
return new Tuple2<String, BigInteger>(
(String) results.get(0).getValue(),
(BigInteger) results.get(1).getValue()
);
}
public Tuple1<Boolean> getSetOutput(TransactionReceipt transactionReceipt) {
String data = transactionReceipt.getOutput();
final Function function = new Function(FUNC_SET,
Arrays.<Type>asList(),
Arrays.<TypeReference<?>>asList(new TypeReference<Bool>() {}));
List<Type> results = FunctionReturnDecoder.decode(data, function.getOutputParameters());
return new Tuple1<Boolean>(
(Boolean) results.get(0).getValue()
);
}
public TransactionReceipt transfer(String from, String to, BigInteger amount) {
final Function function = new Function(
FUNC_TRANSFER,
Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(from),
new org.fisco.bcos.sdk.abi.datatypes.Utf8String(to),
new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(amount)),
Collections.<TypeReference<?>>emptyList());
return executeTransaction(function);
}
public byte[] transfer(String from, String to, BigInteger amount, TransactionCallback callback) {
final Function function = new Function(
FUNC_TRANSFER,
Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(from),
new org.fisco.bcos.sdk.abi.datatypes.Utf8String(to),
new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(amount)),
Collections.<TypeReference<?>>emptyList());
return asyncExecuteTransaction(function, callback);
}
public String getSignedTransactionForTransfer(String from, String to, BigInteger amount) {
final Function function = new Function(
FUNC_TRANSFER,
Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(from),
new org.fisco.bcos.sdk.abi.datatypes.Utf8String(to),
new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(amount)),
Collections.<TypeReference<?>>emptyList());
return createSignedTransaction(function);
}
public Tuple3<String, String, BigInteger> getTransferInput(TransactionReceipt transactionReceipt) {
String data = transactionReceipt.getInput().substring(10);
final Function function = new Function(FUNC_TRANSFER,
Arrays.<Type>asList(),
Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {}, new TypeReference<Utf8String>() {}, new TypeReference<Uint256>() {}));
List<Type> results = FunctionReturnDecoder.decode(data, function.getOutputParameters());
return new Tuple3<String, String, BigInteger>(
(String) results.get(0).getValue(),
(String) results.get(1).getValue(),
(BigInteger) results.get(2).getValue()
);
}
public Tuple1<Boolean> getTransferOutput(TransactionReceipt transactionReceipt) {
String data = transactionReceipt.getOutput();
final Function function = new Function(FUNC_TRANSFER,
Arrays.<Type>asList(),
Arrays.<TypeReference<?>>asList(new TypeReference<Bool>() {}));
List<Type> results = FunctionReturnDecoder.decode(data, function.getOutputParameters());
return new Tuple1<Boolean>(
(Boolean) results.get(0).getValue()
);
}
public List<TransferEventEventResponse> getTransferEventEvents(TransactionReceipt transactionReceipt) {
List<Contract.EventValuesWithLog> valueList = extractEventParametersWithLog(TRANSFEREVENT_EVENT, transactionReceipt);
ArrayList<TransferEventEventResponse> responses = new ArrayList<TransferEventEventResponse>(valueList.size());
for (Contract.EventValuesWithLog eventValues : valueList) {
TransferEventEventResponse typedResponse = new TransferEventEventResponse();
typedResponse.log = eventValues.getLog();
typedResponse.from = (String) eventValues.getNonIndexedValues().get(0).getValue();
typedResponse.to = (String) eventValues.getNonIndexedValues().get(1).getValue();
typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(2).getValue();
responses.add(typedResponse);
}
return responses;
}
public void subscribeTransferEventEvent(String fromBlock, String toBlock, List<String> otherTopics, EventCallback callback) {
String topic0 = eventEncoder.encode(TRANSFEREVENT_EVENT);
subscribeEvent(ABI,BINARY,topic0,fromBlock,toBlock,otherTopics,callback);
}
public void subscribeTransferEventEvent(EventCallback callback) {
String topic0 = eventEncoder.encode(TRANSFEREVENT_EVENT);
subscribeEvent(ABI,BINARY,topic0,callback);
}
public List<SetEventEventResponse> getSetEventEvents(TransactionReceipt transactionReceipt) {
List<Contract.EventValuesWithLog> valueList = extractEventParametersWithLog(SETEVENT_EVENT, transactionReceipt);
ArrayList<SetEventEventResponse> responses = new ArrayList<SetEventEventResponse>(valueList.size());
for (Contract.EventValuesWithLog eventValues : valueList) {
SetEventEventResponse typedResponse = new SetEventEventResponse();
typedResponse.log = eventValues.getLog();
typedResponse.user = (String) eventValues.getNonIndexedValues().get(0).getValue();
typedResponse.balance = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue();
responses.add(typedResponse);
}
return responses;
}
public void subscribeSetEventEvent(String fromBlock, String toBlock, List<String> otherTopics, EventCallback callback) {
String topic0 = eventEncoder.encode(SETEVENT_EVENT);
subscribeEvent(ABI,BINARY,topic0,fromBlock,toBlock,otherTopics,callback);
}
public void subscribeSetEventEvent(EventCallback callback) {
String topic0 = eventEncoder.encode(SETEVENT_EVENT);
subscribeEvent(ABI,BINARY,topic0,callback);
}
public static ParallelTransfer load(String contractAddress, Client client, CryptoKeyPair credential) {
return new ParallelTransfer(contractAddress, client, credential);
}
public static ParallelTransfer deploy(Client client, CryptoKeyPair credential) throws ContractException {
return deploy(ParallelTransfer.class, client, credential, getBinary(client.getCryptoSuite()), "");
}
public static class TransferEventEventResponse {
public TransactionReceipt.Logs log;
public String from;
public String to;
public BigInteger amount;
}
public static class SetEventEventResponse {
public TransactionReceipt.Logs log;
public String user;
public BigInteger balance;
}
}

View File

@@ -0,0 +1,436 @@
package com.org.fisco;
import org.fisco.bcos.sdk.BcosSDK;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.model.TransactionReceipt;
import org.com.fisco.ParallelTransfer; // 导入ParallelTransfer合约类
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* FISCO BCOS TPS压力测试工具
*
* 使用方法:
* 1. 先部署合约: TPSTest.deployContract()
* 2. 初始化账户: TPSTest.initAccounts()
* 3. 运行压测: TPSTest.runStressTest()
*/
public class TPSTest {
private BcosSDK sdk;
private Client client;
private String contractAddress;
private ParallelTransfer contract; // 复用合约对象,避免每次都创建
// 测试配置
private int threadCount = 20; // 并发线程数
private int totalTransactions = 100000; // 总交易数
private int qpsLimit = 0; // QPS限制0表示不限制
private int warmupTransactions = 100; // 预热交易数
// 账户池
private List<String> accountPool = new ArrayList<>();
private AtomicInteger accountIndex = new AtomicInteger(0);
public TPSTest(String configFile) throws Exception {
this.sdk = BcosSDK.build(configFile);
this.client = sdk.getClient(1); // v2.x使用群组ID数字默认群组1
System.out.println("连接FISCO BCOS节点成功");
System.out.println("当前区块高度: " + client.getBlockNumber());
}
/**
* 设置测试参数
*/
public void setTestParams(int threadCount, int totalTransactions, int qpsLimit) {
this.threadCount = threadCount;
this.totalTransactions = totalTransactions;
this.qpsLimit = qpsLimit;
}
/**
* 步骤1: 部署压测合约
*/
public String deployContract() throws Exception {
System.out.println("\n[1/3] 部署ParallelTransfer合约...");
CryptoKeyPair keyPair = client.getCryptoSuite().getCryptoKeyPair();
// 注意: 需要先使用控制台编译合约生成Java类
// 这里假设已经生成了ParallelTransfer.java
// ParallelTransfer contract = ParallelTransfer.deploy(client, keyPair);
// this.contractAddress = contract.getContractAddress();
// 如果手动已经部署,可以直接设置地址
this.contractAddress = "0x06ac2fe406f1ae06494946ee281d58f1c79c39e4";
System.out.println("合约部署成功!");
System.out.println("合约地址: " + contractAddress);
return contractAddress;
}
/**
* 步骤2: 初始化测试账户
*/
public void initAccounts(int accountCount) {
System.out.println("\n[2/3] 初始化测试账户...");
System.out.println("生成 " + accountCount + " 个测试账户...");
for (int i = 0; i < accountCount; i++) {
accountPool.add("user_" + String.format("%06d", i));
}
System.out.println("账户初始化完成! 账户数: " + accountPool.size());
}
/**
* 生成账户列表(不初始化余额,用于已通过脚本初始化的场景)
*/
public void generateAccountList(int accountCount) {
for (int i = 0; i < accountCount; i++) {
accountPool.add("user_" + String.format("%06d", i));
}
System.out.println("已生成 " + accountPool.size() + " 个测试账户");
}
/**
* 步骤3: 运行压力测试
*/
public TPSTestResult runStressTest() throws Exception {
System.out.println("\n[3/3] 开始压力测试...");
System.out.println("测试配置:");
System.out.println(" - 并发线程数: " + threadCount);
System.out.println(" - 总交易数: " + totalTransactions);
System.out.println(" - QPS限制: " + (qpsLimit > 0 ? qpsLimit : "无限制"));
System.out.println(" - 预热交易数: " + warmupTransactions);
TPSTestResult result = new TPSTestResult(threadCount, qpsLimit);
// 预热
if (warmupTransactions > 0) {
System.out.println("\n正在预热 (" + warmupTransactions + " 笔交易)...");
runTestPhase(warmupTransactions, result, true);
System.out.println("预热完成!");
}
// 正式测试
System.out.println("\n开始正式压测...");
System.out.println("实时TPS监控 (每5秒更新):");
// 重置统计
TPSTestResult finalResult = new TPSTestResult(threadCount, qpsLimit);
final int finalTotalTx = totalTransactions;
// 启动监控线程
ScheduledExecutorService monitor = Executors.newScheduledThreadPool(1);
monitor.scheduleAtFixedRate(() -> {
System.out.printf(" 当前进度: %d/%d | 实时TPS: %.2f | 成功率: %.2f%%\n",
finalResult.getTotalTransactions(), finalTotalTx,
finalResult.getRealtimeTPS(), finalResult.calculateSuccessRate());
}, 5, 5, TimeUnit.SECONDS);
// 执行测试
runTestPhase(totalTransactions, finalResult, false);
// 停止监控
monitor.shutdown();
finalResult.markEnd();
return finalResult;
}
/**
* 执行测试阶段
*/
private void runTestPhase(int txCount, TPSTestResult result, boolean isWarmup) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
CountDownLatch latch = new CountDownLatch(txCount);
// QPS限流器
Semaphore rateLimiter = qpsLimit > 0 ? new Semaphore(qpsLimit) : null;
if (qpsLimit > 0) {
// 启动令牌补充线程
ScheduledExecutorService refiller = Executors.newScheduledThreadPool(1);
refiller.scheduleAtFixedRate(() -> {
int available = rateLimiter.availablePermits();
if (available < qpsLimit) {
rateLimiter.release(qpsLimit - available);
}
}, 0, 1, TimeUnit.SECONDS);
}
Random random = new Random();
// 提交所有交易任务
for (int i = 0; i < txCount; i++) {
executor.submit(() -> {
try {
// QPS限流
if (rateLimiter != null) {
rateLimiter.acquire();
}
long startTime = System.currentTimeMillis();
// 随机选择两个账户进行转账
String fromAccount = getRandomAccount();
String toAccount = getRandomAccount();
int amount = random.nextInt(100) + 1;
// 发送交易
boolean success = sendTransferTransaction(fromAccount, toAccount, amount);
long endTime = System.currentTimeMillis();
long latency = endTime - startTime;
if (!isWarmup) {
if (success) {
result.recordSuccess(latency);
} else {
result.recordFailure("交易执行失败");
}
}
} catch (Exception e) {
if (!isWarmup) {
result.recordFailure(e.getMessage());
}
} finally {
latch.countDown();
}
});
}
// 等待所有交易完成
latch.await();
executor.shutdown();
executor.awaitTermination(10, TimeUnit.MINUTES);
}
/**
* 初始化合约对象(只调用一次)
*/
private void initContract() throws Exception {
CryptoKeyPair keyPair = client.getCryptoSuite().getCryptoKeyPair();
this.contract = ParallelTransfer.load(contractAddress, client, keyPair);
System.out.println("合约对象初始化完成");
}
/**
* 发送转账交易复用contract对象
*/
private boolean sendTransferTransaction(String from, String to, int amount) {
try {
TransactionReceipt receipt = contract.transfer(from, to, BigInteger.valueOf(amount));
if (!receipt.isStatusOK()) {
System.err.println("交易失败 - Status: " + receipt.getStatus() +
", Message: " + receipt.getMessage());
}
return receipt.isStatusOK();
} catch (Exception e) {
System.err.println("交易异常: " + e.getClass().getSimpleName() + " - " + e.getMessage());
return false;
}
}
/**
* 随机获取一个账户
*/
private String getRandomAccount() {
int index = accountIndex.getAndIncrement() % accountPool.size();
return accountPool.get(index);
}
/**
* 关闭连接
*/
public void close() {
// SDK 2.x不需要显式关闭会自动清理资源
// 如果需要可以让JVM自动回收
}
/**
* 打印使用帮助
*/
private static void printUsage() {
System.out.println("用法: java -jar tps-test.jar [选项]");
System.out.println();
System.out.println("选项:");
System.out.println(" -t, --threads <数量> 并发线程数 (默认: 100)");
System.out.println(" -n, --transactions <数量> 总交易数 (默认: 10000)");
System.out.println(" -q, --qps <限制> QPS限制0表示不限制 (默认: 0)");
System.out.println(" -c, --contract <地址> 合约地址 (必填)");
System.out.println(" -a, --accounts <数量> 测试账户数 (默认: 100)");
System.out.println(" -h, --help 显示此帮助信息");
System.out.println();
System.out.println("示例:");
System.out.println(" # 使用默认参数");
System.out.println(" java -jar tps-test.jar -c 0x06ac2fe406f1ae06494946ee281d58f1c79c39e4");
System.out.println();
System.out.println(" # 自定义参数");
System.out.println(" java -jar tps-test.jar -t 200 -n 50000 -c 0x06ac2fe406f1ae06494946ee281d58f1c79c39e4");
System.out.println();
System.out.println(" # 使用 gradlew 运行");
System.out.println(" ./gradlew run --args=\"-t 200 -n 50000 -c 0x06ac...\"");
}
/**
* 主测试流程(支持命令行参数)
*/
public static void main(String[] args) {
TPSTest tester = null;
try {
// 解析命令行参数
int threadCount = 100; // 默认并发数
int totalTransactions = 10000; // 默认交易总数
int qpsLimit = 0; // 默认不限速
String contractAddress = null; // 合约地址(必填)
int accountCount = 100; // 默认账户数
// 解析参数
for (int i = 0; i < args.length; i++) {
String arg = args[i];
if (arg.equals("-h") || arg.equals("--help")) {
printUsage();
return;
}
if (i + 1 < args.length) {
String value = args[i + 1];
switch (arg) {
case "-t":
case "--threads":
threadCount = Integer.parseInt(value);
i++;
break;
case "-n":
case "--transactions":
totalTransactions = Integer.parseInt(value);
i++;
break;
case "-q":
case "--qps":
qpsLimit = Integer.parseInt(value);
i++;
break;
case "-c":
case "--contract":
contractAddress = value;
i++;
break;
case "-a":
case "--accounts":
accountCount = Integer.parseInt(value);
i++;
break;
default:
System.err.println("未知参数: " + arg);
printUsage();
System.exit(1);
}
}
}
// 验证必填参数
if (contractAddress == null || contractAddress.isEmpty()) {
System.err.println("错误: 必须指定合约地址 (-c 或 --contract)");
System.err.println();
printUsage();
System.exit(1);
}
// 验证参数范围
if (threadCount <= 0 || threadCount > 10000) {
System.err.println("错误: 并发线程数必须在 1-10000 之间");
System.exit(1);
}
if (totalTransactions <= 0) {
System.err.println("错误: 交易总数必须大于 0");
System.exit(1);
}
System.out.println("========================================");
System.out.println(" FISCO BCOS TPS压力测试工具");
System.out.println("========================================\n");
System.out.println("测试参数:");
System.out.println(" 并发线程数: " + threadCount);
System.out.println(" 总交易数: " + totalTransactions);
System.out.println(" QPS限制: " + (qpsLimit > 0 ? qpsLimit : "无限制"));
System.out.println(" 合约地址: " + contractAddress);
System.out.println(" 测试账户数: " + accountCount);
System.out.println();
// 1. 初始化支持从当前目录或resources目录读取配置
String configFile = "config.toml";
if (!new java.io.File(configFile).exists()) {
configFile = "src/main/resources/config.toml";
}
if (!new java.io.File(configFile).exists()) {
System.err.println("错误: 找不到配置文件 config.toml");
System.err.println("请确保当前目录或 src/main/resources/ 目录下有 config.toml 文件");
System.exit(1);
}
tester = new TPSTest(configFile);
// 2. 设置测试参数
tester.setTestParams(threadCount, totalTransactions, qpsLimit);
// 3. 设置合约地址
tester.contractAddress = contractAddress;
System.out.println("使用合约地址: " + tester.contractAddress);
// 4. 初始化合约对象(重要:只创建一次,避免资源泄漏)
tester.initContract();
// 5. 生成测试账户列表(账户余额已通过脚本初始化)
System.out.println("\n生成测试账户列表...");
tester.generateAccountList(accountCount);
System.out.println("账户列表生成完成,账户余额应已通过 init_accounts.sh 脚本初始化");
// 6. 运行压测
TPSTestResult result = tester.runStressTest();
// 7. 输出报告
System.out.println("\n" + result.generateReport());
// 8. 保存报告到文件
String reportFile = "tps_test_report_" + System.currentTimeMillis() + ".txt";
java.nio.file.Files.write(
java.nio.file.Paths.get(reportFile),
result.generateReport().getBytes()
);
System.out.println("测试报告已保存到: " + reportFile);
} catch (NumberFormatException e) {
System.err.println("错误: 参数格式不正确");
System.err.println(e.getMessage());
printUsage();
System.exit(1);
} catch (Exception e) {
System.err.println("测试失败: " + e.getMessage());
e.printStackTrace();
System.exit(1);
} finally {
if (tester != null) {
tester.close();
}
// 强制退出程序避免SDK的后台线程一直运行
System.out.println("\n测试完成退出程序...");
System.exit(0);
}
}
}

View File

@@ -0,0 +1,184 @@
package com.org.fisco;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
* TPS测试结果统计类
*/
public class TPSTestResult {
private long startTime;
private long endTime;
private int threadCount;
private int qpsLimit;
// 交易统计
private AtomicInteger totalTransactions = new AtomicInteger(0);
private AtomicInteger successTransactions = new AtomicInteger(0);
private AtomicInteger failedTransactions = new AtomicInteger(0);
// 延迟统计
private List<Long> latencies = Collections.synchronizedList(new ArrayList<>());
private AtomicLong totalLatency = new AtomicLong(0);
// 错误信息
private List<String> errors = Collections.synchronizedList(new ArrayList<>());
public TPSTestResult(int threadCount, int qpsLimit) {
this.threadCount = threadCount;
this.qpsLimit = qpsLimit;
this.startTime = System.currentTimeMillis();
}
/**
* 记录成功交易
*/
public void recordSuccess(long latency) {
totalTransactions.incrementAndGet();
successTransactions.incrementAndGet();
latencies.add(latency);
totalLatency.addAndGet(latency);
}
/**
* 记录失败交易
*/
public void recordFailure(String errorMsg) {
totalTransactions.incrementAndGet();
failedTransactions.incrementAndGet();
if (errors.size() < 100) { // 只保存前100条错误
errors.add(errorMsg);
}
}
/**
* 标记测试结束
*/
public void markEnd() {
this.endTime = System.currentTimeMillis();
}
/**
* 计算TPS
*/
public double calculateTPS() {
if (endTime == 0) {
endTime = System.currentTimeMillis();
}
double duration = (endTime - startTime) / 1000.0;
return duration > 0 ? successTransactions.get() / duration : 0;
}
/**
* 计算实时TPS
*/
public double getRealtimeTPS() {
long currentTime = System.currentTimeMillis();
double duration = (currentTime - startTime) / 1000.0;
return duration > 0 ? successTransactions.get() / duration : 0;
}
/**
* 计算成功率
*/
public double calculateSuccessRate() {
int total = totalTransactions.get();
return total > 0 ? (successTransactions.get() * 100.0 / total) : 0;
}
/**
* 计算平均延迟
*/
public double calculateAverageLatency() {
int count = successTransactions.get();
return count > 0 ? totalLatency.get() / (double)count : 0;
}
/**
* 计算百分位延迟
*/
public long calculatePercentileLatency(int percentile) {
if (latencies.isEmpty()) {
return 0;
}
List<Long> sortedLatencies = new ArrayList<>(latencies);
Collections.sort(sortedLatencies);
int index = (int)Math.ceil(sortedLatencies.size() * percentile / 100.0) - 1;
index = Math.max(0, Math.min(index, sortedLatencies.size() - 1));
return sortedLatencies.get(index);
}
/**
* 获取总交易数
*/
public int getTotalTransactions() {
return totalTransactions.get();
}
/**
* 生成测试报告
*/
public String generateReport() {
StringBuilder report = new StringBuilder();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
double duration = (endTime - startTime) / 1000.0;
double tps = calculateTPS();
double successRate = calculateSuccessRate();
double avgLatency = calculateAverageLatency();
report.append("========================================\n");
report.append(" FISCO BCOS TPS测试报告\n");
report.append("========================================\n\n");
report.append("测试配置:\n");
report.append(" 开始时间: ").append(sdf.format(new Date(startTime))).append("\n");
report.append(" 结束时间: ").append(sdf.format(new Date(endTime))).append("\n");
report.append(" 测试时长: ").append(String.format("%.2f", duration)).append("\n");
report.append(" 并发线程数: ").append(threadCount).append("\n");
report.append(" QPS限制: ").append(qpsLimit > 0 ? qpsLimit : "无限制").append("\n");
report.append("\n");
report.append("交易统计:\n");
report.append(" 总交易数: ").append(totalTransactions.get()).append("\n");
report.append(" 成功交易: ").append(successTransactions.get()).append("\n");
report.append(" 失败交易: ").append(failedTransactions.get()).append("\n");
report.append(" 成功率: ").append(String.format("%.2f%%", successRate)).append("\n");
report.append("\n");
report.append("性能指标:\n");
report.append(" ★ TPS (每秒交易数): ").append(String.format("%.2f", tps)).append("\n");
report.append(" 平均延迟: ").append(String.format("%.2f", avgLatency)).append(" ms\n");
if (!latencies.isEmpty()) {
report.append(" 中位数延迟: ").append(calculatePercentileLatency(50)).append(" ms\n");
report.append(" P95延迟: ").append(calculatePercentileLatency(95)).append(" ms\n");
report.append(" P99延迟: ").append(calculatePercentileLatency(99)).append(" ms\n");
}
report.append("\n");
report.append("报告时间: ").append(sdf.format(new Date())).append("\n");
report.append("========================================\n");
// 如果有错误显示前10条
if (!errors.isEmpty()) {
report.append("\n错误示例 (前10条):\n");
int count = Math.min(10, errors.size());
for (int i = 0; i < count; i++) {
report.append(" ").append(i + 1).append(". ").append(errors.get(i)).append("\n");
}
}
return report.toString();
}
}

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<!-- 关闭SDK的EventSubscribe日志 -->
<Logger name="org.fisco.bcos.sdk.eventsub" level="ERROR" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<!-- 将SDK其他日志设置为WARN级别 -->
<Logger name="org.fisco.bcos.sdk" level="WARN" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<!-- 应用程序日志保持INFO -->
<Logger name="com.org.fisco" level="INFO" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<Root level="WARN">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:04:09
结束时间: 2026-02-10 14:05:33
测试时长: 83.62 秒
并发线程数: 100
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 10000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 119.59
平均延迟: 827.52 ms
中位数延迟: 651 ms
P95延迟: 1503 ms
P99延迟: 4310 ms
报告时间: 2026-02-10 14:05:33
========================================

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:06:06
结束时间: 2026-02-10 14:06:54
测试时长: 48.66 秒
并发线程数: 500
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 10000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 205.51
平均延迟: 1553.64 ms
中位数延迟: 940 ms
P95延迟: 3028 ms
P99延迟: 16673 ms
报告时间: 2026-02-10 14:06:54
========================================

View File

@@ -0,0 +1,38 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:07:12
结束时间: 2026-02-10 14:07:49
测试时长: 37.26 秒
并发线程数: 1000
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 9611
失败交易: 389
成功率: 96.11%
性能指标:
★ TPS (每秒交易数): 257.98
平均延迟: 2229.50 ms
中位数延迟: 1436 ms
P95延迟: 5189 ms
P99延迟: 24093 ms
报告时间: 2026-02-10 14:07:50
========================================
错误示例 (前10条):
1. 交易执行失败
2. 交易执行失败
3. 交易执行失败
4. 交易执行失败
5. 交易执行失败
6. 交易执行失败
7. 交易执行失败
8. 交易执行失败
9. 交易执行失败
10. 交易执行失败

View File

@@ -0,0 +1,38 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:08:12
结束时间: 2026-02-10 14:08:45
测试时长: 33.02 秒
并发线程数: 600
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 9963
失败交易: 37
成功率: 99.63%
性能指标:
★ TPS (每秒交易数): 301.69
平均延迟: 1378.41 ms
中位数延迟: 838 ms
P95延迟: 2297 ms
P99延迟: 21355 ms
报告时间: 2026-02-10 14:08:45
========================================
错误示例 (前10条):
1. 交易执行失败
2. 交易执行失败
3. 交易执行失败
4. 交易执行失败
5. 交易执行失败
6. 交易执行失败
7. 交易执行失败
8. 交易执行失败
9. 交易执行失败
10. 交易执行失败

View File

@@ -0,0 +1,38 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:09:10
结束时间: 2026-02-10 14:09:44
测试时长: 33.79 秒
并发线程数: 500
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 9974
失败交易: 26
成功率: 99.74%
性能指标:
★ TPS (每秒交易数): 295.14
平均延迟: 1494.69 ms
中位数延迟: 823 ms
P95延迟: 2672 ms
P99延迟: 20214 ms
报告时间: 2026-02-10 14:09:44
========================================
错误示例 (前10条):
1. 交易执行失败
2. 交易执行失败
3. 交易执行失败
4. 交易执行失败
5. 交易执行失败
6. 交易执行失败
7. 交易执行失败
8. 交易执行失败
9. 交易执行失败
10. 交易执行失败

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:09:59
结束时间: 2026-02-10 14:10:51
测试时长: 51.05 秒
并发线程数: 400
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 10000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 195.90
平均延迟: 1424.86 ms
中位数延迟: 765 ms
P95延迟: 1565 ms
P99延迟: 19399 ms
报告时间: 2026-02-10 14:10:51
========================================

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:11:09
结束时间: 2026-02-10 14:11:47
测试时长: 37.77 秒
并发线程数: 450
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 10000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 264.80
平均延迟: 1437.83 ms
中位数延迟: 748 ms
P95延迟: 4032 ms
P99延迟: 14454 ms
报告时间: 2026-02-10 14:11:47
========================================

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:12:06
结束时间: 2026-02-10 14:12:36
测试时长: 29.63 秒
并发线程数: 500
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 10000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 337.52
平均延迟: 1453.46 ms
中位数延迟: 963 ms
P95延迟: 1863 ms
P99延迟: 20871 ms
报告时间: 2026-02-10 14:12:36
========================================

View File

@@ -0,0 +1,38 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:12:45
结束时间: 2026-02-10 14:13:17
测试时长: 32.47 秒
并发线程数: 500
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 9973
失败交易: 27
成功率: 99.73%
性能指标:
★ TPS (每秒交易数): 307.19
平均延迟: 1366.54 ms
中位数延迟: 739 ms
P95延迟: 2044 ms
P99延迟: 19454 ms
报告时间: 2026-02-10 14:13:17
========================================
错误示例 (前10条):
1. 交易执行失败
2. 交易执行失败
3. 交易执行失败
4. 交易执行失败
5. 交易执行失败
6. 交易执行失败
7. 交易执行失败
8. 交易执行失败
9. 交易执行失败
10. 交易执行失败

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:13:30
结束时间: 2026-02-10 14:13:57
测试时长: 26.30 秒
并发线程数: 500
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 10000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 380.26
平均延迟: 1285.29 ms
中位数延迟: 881 ms
P95延迟: 2683 ms
P99延迟: 15799 ms
报告时间: 2026-02-10 14:13:57
========================================

View File

@@ -0,0 +1,38 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:14:17
结束时间: 2026-02-10 14:14:49
测试时长: 32.00 秒
并发线程数: 500
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 9948
失败交易: 52
成功率: 99.48%
性能指标:
★ TPS (每秒交易数): 310.87
平均延迟: 1362.70 ms
中位数延迟: 870 ms
P95延迟: 1553 ms
P99延迟: 21603 ms
报告时间: 2026-02-10 14:14:49
========================================
错误示例 (前10条):
1. 交易执行失败
2. 交易执行失败
3. 交易执行失败
4. 交易执行失败
5. 交易执行失败
6. 交易执行失败
7. 交易执行失败
8. 交易执行失败
9. 交易执行失败
10. 交易执行失败

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:15:18
结束时间: 2026-02-10 14:15:45
测试时长: 27.54 秒
并发线程数: 450
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 10000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 363.17
平均延迟: 1137.05 ms
中位数延迟: 755 ms
P95延迟: 1664 ms
P99延迟: 13455 ms
报告时间: 2026-02-10 14:15:45
========================================

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:15:55
结束时间: 2026-02-10 14:16:39
测试时长: 44.96 秒
并发线程数: 450
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 10000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 222.42
平均延迟: 1618.69 ms
中位数延迟: 817 ms
P95延迟: 6077 ms
P99延迟: 20877 ms
报告时间: 2026-02-10 14:16:40
========================================

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:16:51
结束时间: 2026-02-10 14:17:38
测试时长: 47.00 秒
并发线程数: 450
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 10000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 212.76
平均延迟: 1825.84 ms
中位数延迟: 885 ms
P95延迟: 5084 ms
P99延迟: 16504 ms
报告时间: 2026-02-10 14:17:38
========================================

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:17:49
结束时间: 2026-02-10 14:18:29
测试时长: 40.11 秒
并发线程数: 450
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 10000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 249.33
平均延迟: 1341.90 ms
中位数延迟: 738 ms
P95延迟: 3098 ms
P99延迟: 12218 ms
报告时间: 2026-02-10 14:18:29
========================================

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:23:37
结束时间: 2026-02-10 14:29:00
测试时长: 323.22 秒
并发线程数: 400
QPS限制: 无限制
交易统计:
总交易数: 100000
成功交易: 100000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 309.38
平均延迟: 1289.31 ms
中位数延迟: 782 ms
P95延迟: 2880 ms
P99延迟: 13821 ms
报告时间: 2026-02-10 14:29:00
========================================

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:29:13
结束时间: 2026-02-10 14:34:55
测试时长: 342.83 秒
并发线程数: 400
QPS限制: 无限制
交易统计:
总交易数: 100000
成功交易: 100000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 291.69
平均延迟: 1336.06 ms
中位数延迟: 772 ms
P95延迟: 4855 ms
P99延迟: 11606 ms
报告时间: 2026-02-10 14:34:56
========================================

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:35:06
结束时间: 2026-02-10 14:40:29
测试时长: 322.86 秒
并发线程数: 400
QPS限制: 无限制
交易统计:
总交易数: 100000
成功交易: 100000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 309.73
平均延迟: 1272.72 ms
中位数延迟: 767 ms
P95延迟: 2771 ms
P99延迟: 12284 ms
报告时间: 2026-02-10 14:40:29
========================================

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:41:15
结束时间: 2026-02-10 14:45:15
测试时长: 240.15 秒
并发线程数: 500
QPS限制: 无限制
交易统计:
总交易数: 100000
成功交易: 100000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 416.41
平均延迟: 1170.71 ms
中位数延迟: 772 ms
P95延迟: 1779 ms
P99延迟: 12080 ms
报告时间: 2026-02-10 14:45:15
========================================

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:45:27
结束时间: 2026-02-10 14:49:48
测试时长: 260.41 秒
并发线程数: 500
QPS限制: 无限制
交易统计:
总交易数: 100000
成功交易: 100000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 384.01
平均延迟: 1241.56 ms
中位数延迟: 757 ms
P95延迟: 2237 ms
P99延迟: 13599 ms
报告时间: 2026-02-10 14:49:48
========================================

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:49:59
结束时间: 2026-02-10 14:50:44
测试时长: 45.36 秒
并发线程数: 500
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 10000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 220.48
平均延迟: 1668.52 ms
中位数延迟: 829 ms
P95延迟: 3114 ms
P99延迟: 17204 ms
报告时间: 2026-02-10 14:50:44
========================================

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:50:54
结束时间: 2026-02-10 14:51:36
测试时长: 41.70 秒
并发线程数: 500
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 10000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 239.84
平均延迟: 1534.05 ms
中位数延迟: 806 ms
P95延迟: 4673 ms
P99延迟: 15583 ms
报告时间: 2026-02-10 14:51:36
========================================

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:51:52
结束时间: 2026-02-10 14:52:17
测试时长: 24.52 秒
并发线程数: 600
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 10000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 407.90
平均延迟: 1313.38 ms
中位数延迟: 805 ms
P95延迟: 2667 ms
P99延迟: 16736 ms
报告时间: 2026-02-10 14:52:17
========================================

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:52:37
结束时间: 2026-02-10 14:53:03
测试时长: 25.28 秒
并发线程数: 600
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 10000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 395.65
平均延迟: 1393.95 ms
中位数延迟: 884 ms
P95延迟: 2074 ms
P99延迟: 17573 ms
报告时间: 2026-02-10 14:53:03
========================================

View File

@@ -0,0 +1,38 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:53:19
结束时间: 2026-02-10 14:54:00
测试时长: 40.41 秒
并发线程数: 1000
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 9396
失败交易: 604
成功率: 93.96%
性能指标:
★ TPS (每秒交易数): 232.53
平均延迟: 1836.32 ms
中位数延迟: 869 ms
P95延迟: 7908 ms
P99延迟: 22325 ms
报告时间: 2026-02-10 14:54:00
========================================
错误示例 (前10条):
1. 交易执行失败
2. 交易执行失败
3. 交易执行失败
4. 交易执行失败
5. 交易执行失败
6. 交易执行失败
7. 交易执行失败
8. 交易执行失败
9. 交易执行失败
10. 交易执行失败

View File

@@ -0,0 +1,38 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:54:24
结束时间: 2026-02-10 14:54:57
测试时长: 32.47 秒
并发线程数: 800
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 9988
失败交易: 12
成功率: 99.88%
性能指标:
★ TPS (每秒交易数): 307.64
平均延迟: 1746.19 ms
中位数延迟: 916 ms
P95延迟: 3013 ms
P99延迟: 25522 ms
报告时间: 2026-02-10 14:54:57
========================================
错误示例 (前10条):
1. 交易执行失败
2. 交易执行失败
3. 交易执行失败
4. 交易执行失败
5. 交易执行失败
6. 交易执行失败
7. 交易执行失败
8. 交易执行失败
9. 交易执行失败
10. 交易执行失败

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:55:09
结束时间: 2026-02-10 14:55:29
测试时长: 20.70 秒
并发线程数: 600
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 10000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 483.14
平均延迟: 1142.64 ms
中位数延迟: 775 ms
P95延迟: 1565 ms
P99延迟: 12320 ms
报告时间: 2026-02-10 14:55:29
========================================

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:55:47
结束时间: 2026-02-10 14:56:14
测试时长: 27.47 秒
并发线程数: 600
QPS限制: 无限制
交易统计:
总交易数: 10000
成功交易: 10000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 364.07
平均延迟: 1467.61 ms
中位数延迟: 809 ms
P95延迟: 2798 ms
P99延迟: 22015 ms
报告时间: 2026-02-10 14:56:14
========================================

View File

@@ -0,0 +1,38 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 14:58:44
结束时间: 2026-02-10 15:03:19
测试时长: 275.23 秒
并发线程数: 500
QPS限制: 无限制
交易统计:
总交易数: 100000
成功交易: 99822
失败交易: 178
成功率: 99.82%
性能指标:
★ TPS (每秒交易数): 362.68
平均延迟: 1299.76 ms
中位数延迟: 807 ms
P95延迟: 2194 ms
P99延迟: 14605 ms
报告时间: 2026-02-10 15:03:19
========================================
错误示例 (前10条):
1. 交易执行失败
2. 交易执行失败
3. 交易执行失败
4. 交易执行失败
5. 交易执行失败
6. 交易执行失败
7. 交易执行失败
8. 交易执行失败
9. 交易执行失败
10. 交易执行失败

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 15:04:54
结束时间: 2026-02-10 15:09:44
测试时长: 290.01 秒
并发线程数: 400
QPS限制: 无限制
交易统计:
总交易数: 100000
成功交易: 100000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 344.81
平均延迟: 1146.03 ms
中位数延迟: 755 ms
P95延迟: 1997 ms
P99延迟: 10785 ms
报告时间: 2026-02-10 15:09:44
========================================

View File

@@ -0,0 +1,26 @@
========================================
FISCO BCOS TPS测试报告
========================================
测试配置:
开始时间: 2026-02-10 15:09:55
结束时间: 2026-02-10 15:13:58
测试时长: 243.54 秒
并发线程数: 500
QPS限制: 无限制
交易统计:
总交易数: 100000
成功交易: 100000
失败交易: 0
成功率: 100.00%
性能指标:
★ TPS (每秒交易数): 410.61
平均延迟: 1198.27 ms
中位数延迟: 780 ms
P95延迟: 2089 ms
P99延迟: 10839 ms
报告时间: 2026-02-10 15:13:58
========================================