性能测试
This commit is contained in:
107
README.md
107
README.md
@@ -19,7 +19,61 @@ make
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 测试
|
## REDIS 对比测试
|
||||||
|
### 数据口径(2026-03-07 大 key 5轮复测)
|
||||||
|
- 参数:`requests=1000000 pipeline=128 keyspace=1000000 value-size=256`
|
||||||
|
- 轮次:每个策略 `5` 轮,按场景剔除 `1` 个异常轮次后取 `4` 轮均值
|
||||||
|
- kvstore 源数据:`test-redis/results/hash_bench_fair_summary_20260307_062549.csv`
|
||||||
|
- redis 源数据:`test-redis/results/redis_bigkey_summary_20260307_063158.csv`
|
||||||
|
- 去异常结果:
|
||||||
|
- `test-redis/results/hash_bench_fair_trimmed_20260307_062549.csv`
|
||||||
|
- `test-redis/results/redis_bigkey_trimmed_20260307_063158.csv`
|
||||||
|
|
||||||
|
### kvstore 协议开销(基线:nopersist,去异常后)
|
||||||
|
| 策略 | set 均值QPS | set 均值us/op | get 均值QPS | get 均值us/op |
|
||||||
|
|---|---:|---:|---:|---:|
|
||||||
|
| nopersist | 150084.25 | 6.67 | 163760.25 | 6.11 |
|
||||||
|
| persist_no | 140206.50 | 7.13 | 164554.25 | 6.08 |
|
||||||
|
| persist_everysec | 133105.75 | 7.52 | 163358.25 | 6.12 |
|
||||||
|
|
||||||
|
| 相对 nopersist 的开销 | set QPS 变化 | set us/op 变化 | get QPS 变化 | get us/op 变化 |
|
||||||
|
|---|---:|---:|---:|---:|
|
||||||
|
| persist_no | -6.58% | +6.90% | +0.48% | -0.49% |
|
||||||
|
| persist_everysec | -11.31% | +12.74% | -0.25% | +0.16% |
|
||||||
|
|
||||||
|
### Redis 协议开销(基线:none,去异常后)
|
||||||
|
| 策略 | set 均值QPS | set 均值us/op | get 均值QPS | get 均值us/op |
|
||||||
|
|---|---:|---:|---:|---:|
|
||||||
|
| none | 207470.00 | 4.82 | 217642.50 | 4.59 |
|
||||||
|
| aof_no | 143399.50 | 6.98 | 214023.50 | 4.68 |
|
||||||
|
| aof_everysec | 141893.00 | 7.05 | 208713.75 | 4.79 |
|
||||||
|
|
||||||
|
| 相对 none 的开销 | set QPS 变化 | set us/op 变化 | get QPS 变化 | get us/op 变化 |
|
||||||
|
|---|---:|---:|---:|---:|
|
||||||
|
| aof_no | -30.88% | +44.81% | -1.66% | +1.96% |
|
||||||
|
| aof_everysec | -31.61% | +46.27% | -4.10% | +4.36% |
|
||||||
|
|
||||||
|
结论:本轮数据下,持久化开销仍主要体现在 `set`,`get` 相对更稳;Redis 的 AOF 写路径开销显著高于无持久化。
|
||||||
|
|
||||||
|
## 调用开销
|
||||||
|
### gprof Flat Profile(Top 12,按 self time)
|
||||||
|
|
||||||
|
| 排名 | 函数 | self time % | self seconds | calls |
|
||||||
|
|---:|---|---:|---:|---:|
|
||||||
|
| 1 | `rbtree_node_get_key` | 58.34 | 0.56 | 103209091 |
|
||||||
|
| 2 | `rbtree_search` | 7.29 | 0.07 | 1874362 |
|
||||||
|
| 3 | `kvs_keycmp` | 5.73 | 0.06 | 74287566 |
|
||||||
|
| 4 | `ascii_casecmp` | 3.13 | 0.03 | 21490996 |
|
||||||
|
| 5 | `task_init` | 3.13 | 0.03 | 1397974 |
|
||||||
|
| 6 | `mp_page_create` | 3.13 | 0.03 | 23556 |
|
||||||
|
| 7 | `need` | 2.08 | 0.02 | 14042759 |
|
||||||
|
| 8 | `parse_i64` | 2.08 | 0.02 | 7029783 |
|
||||||
|
| 9 | `mp_page_alloc` | 2.08 | 0.02 | 5122487 |
|
||||||
|
| 10 | `rbtree_node_size` | 2.08 | 0.02 | 1860739 |
|
||||||
|
| 11 | `submit_write` | 2.08 | 0.02 | 1394599 |
|
||||||
|
| 12 | `rbtree_insert` | 2.08 | 0.02 | 926531 |
|
||||||
|
|
||||||
|
## 其他测试
|
||||||
### 测试1:性能测试
|
### 测试1:性能测试
|
||||||
测试条件:
|
测试条件:
|
||||||
1. 不启用持久化。
|
1. 不启用持久化。
|
||||||
@@ -162,57 +216,6 @@ average qps:777838
|
|||||||
ALL TESTS PASSED.
|
ALL TESTS PASSED.
|
||||||
```
|
```
|
||||||
|
|
||||||
## REDIS 对比测试
|
|
||||||
### 数据口径(2026-03-06 09:00:30)
|
|
||||||
- 轮次:3 轮(取均值)
|
|
||||||
- 参数:requests=1000000 pipeline=128 keyspace=1000000 value-size=32
|
|
||||||
- 数据来源:`test-redis/results/hash_bench_summary_20260306_090030.csv`
|
|
||||||
|
|
||||||
### 仅看 mypool 与 Redis
|
|
||||||
|
|
||||||
| 系统 | 场景 | set 均值QPS | set 均值us/op | get 均值QPS | get 均值us/op |
|
|
||||||
|---|---|---:|---:|---:|---:|
|
|
||||||
| kvstore (mypool) | none | 165554.00 | 6.04 | 169509.33 | 5.91 |
|
|
||||||
| kvstore (mypool) | incremental(oplog_sync=none) | 168248.67 | 5.96 | 181076.67 | 5.53 |
|
|
||||||
| kvstore (mypool) | incremental(oplog_sync=every_sec) | 164801.67 | 6.08 | 178469.33 | 5.60 |
|
|
||||||
| redis | none | 221558.00 | 4.52 | 254807.33 | 3.92 |
|
|
||||||
| redis | aof_no | 177826.67 | 5.63 | 256099.00 | 3.91 |
|
|
||||||
| redis | aof_everysec | 179159.67 | 5.59 | 243906.00 | 4.11 |
|
|
||||||
| redis | aof_always | 66807.33 | 14.97 | 236824.67 | 4.23 |
|
|
||||||
|
|
||||||
### oplog 与 AOF 安全性级别
|
|
||||||
1. `oplog_sync=none` 时,kvstore 仅异步写入,不做周期 fsync,安全级别仍接近 Redis `aof_no`。
|
|
||||||
2. `oplog_sync=every_sec` 时,kvstore 每秒执行一次“flush + 每个 uring worker 提交 fsync(drain) 并等待回调”,可提供接近 Redis `aof_everysec` 的周期性落盘保证(仍可能丢失最近 1 秒窗口)。
|
|
||||||
3. 与 Redis 相比,当前 kvstore 仍缺少 AOF 尾部校验/截断等恢复增强机制,崩溃恢复鲁棒性上略弱于 Redis AOF 体系。
|
|
||||||
|
|
||||||
### 落盘性能退化(写路径,set)
|
|
||||||
1. kvstore(mypool):`none 165554.00 -> incremental(oplog_sync=none) 168248.67`,变化 `+1.63%`(本轮无退化,属抖动范围)。
|
|
||||||
2. kvstore(mypool):`none 165554.00 -> incremental(oplog_sync=every_sec) 164801.67`,退化 `0.45%`。
|
|
||||||
3. redis:`none 221558.00 -> aof_no 177826.67`,退化 `19.74%`。
|
|
||||||
4. redis:`none 221558.00 -> aof_everysec 179159.67`,退化 `19.14%`。
|
|
||||||
5. redis:`none 221558.00 -> aof_always 66807.33`,退化 `69.85%`。
|
|
||||||
6. 对应 set 平均时延(us/op)变化:kvstore every_sec `6.04 -> 6.08`(`+0.61%`),redis aof_no `4.52 -> 5.63`(`+24.72%`),redis aof_everysec `4.52 -> 5.59`(`+23.69%`),redis aof_always `4.52 -> 14.97`(`+231.51%`)。
|
|
||||||
|
|
||||||
结论:本轮下 kvstore(mypool) 的 `every_sec` 持久化性能代价远低于 Redis AOF 系列,同时安全性目标已从 `aof_no` 抬升到接近 `aof_everysec` 的级别。
|
|
||||||
|
|
||||||
## 调用开销
|
|
||||||
### gprof Flat Profile(Top 12,按 self time)
|
|
||||||
|
|
||||||
| 排名 | 函数 | self time % | self seconds | calls |
|
|
||||||
|---:|---|---:|---:|---:|
|
|
||||||
| 1 | `rbtree_node_get_key` | 58.34 | 0.56 | 103209091 |
|
|
||||||
| 2 | `rbtree_search` | 7.29 | 0.07 | 1874362 |
|
|
||||||
| 3 | `kvs_keycmp` | 5.73 | 0.06 | 74287566 |
|
|
||||||
| 4 | `ascii_casecmp` | 3.13 | 0.03 | 21490996 |
|
|
||||||
| 5 | `task_init` | 3.13 | 0.03 | 1397974 |
|
|
||||||
| 6 | `mp_page_create` | 3.13 | 0.03 | 23556 |
|
|
||||||
| 7 | `need` | 2.08 | 0.02 | 14042759 |
|
|
||||||
| 8 | `parse_i64` | 2.08 | 0.02 | 7029783 |
|
|
||||||
| 9 | `mp_page_alloc` | 2.08 | 0.02 | 5122487 |
|
|
||||||
| 10 | `rbtree_node_size` | 2.08 | 0.02 | 1860739 |
|
|
||||||
| 11 | `submit_write` | 2.08 | 0.02 | 1394599 |
|
|
||||||
| 12 | `rbtree_insert` | 2.08 | 0.02 | 926531 |
|
|
||||||
|
|
||||||
## 项目收获
|
## 项目收获
|
||||||
#### reactor网络模型,用户态网络缓冲区的写法。
|
#### reactor网络模型,用户态网络缓冲区的写法。
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
<config>
|
<config>
|
||||||
<server>
|
<server>
|
||||||
<ip>192.168.220.134</ip>
|
<ip>127.0.0.1</ip>
|
||||||
<port>8888</port>
|
<port>8888</port>
|
||||||
<mode>master</mode> <!-- master / slave -->
|
<mode>master</mode>
|
||||||
|
|
||||||
|
|
||||||
<!-- 仅当 mode=slave 时使用 -->
|
|
||||||
<replica>disable</replica>
|
<replica>disable</replica>
|
||||||
<master>
|
<master>
|
||||||
<ip>192.168.220.134</ip>
|
<ip>192.168.220.134</ip>
|
||||||
@@ -14,22 +14,22 @@
|
|||||||
</server>
|
</server>
|
||||||
|
|
||||||
<log>
|
<log>
|
||||||
<level>INFO</level> <!-- DEBUG / INFO / ERROR -->
|
<level>INFO</level>
|
||||||
</log>
|
</log>
|
||||||
|
|
||||||
<persistence>
|
<persistence>
|
||||||
<type>none</type> <!-- incremental / none -->
|
<type>incremental</type>
|
||||||
<dir>data</dir> <!-- 所有持久化文件所在目录 -->
|
<dir>data/persist_no_20260307_053744_r1_a1</dir>
|
||||||
|
|
||||||
<wal>kvs_oplog.db</wal>
|
<wal>kvs_oplog.db</wal>
|
||||||
<oplog_sync>none</oplog_sync> <!-- none / every_sec -->
|
<oplog_sync>none</oplog_sync>
|
||||||
<array>kvs_array.db</array>
|
<array>kvs_array.db</array>
|
||||||
<rbtree>kvs_rbtree.db</rbtree>
|
<rbtree>kvs_rbtree.db</rbtree>
|
||||||
<hash>kvs_hash.db</hash>
|
<hash>kvs_hash.db</hash>
|
||||||
</persistence>
|
</persistence>
|
||||||
|
|
||||||
<memory>
|
<memory>
|
||||||
<allocator>mypool</allocator> <!-- jemalloc / malloc / mypool -->
|
<allocator>mypool</allocator>
|
||||||
<leakage>disable</leakage> <!-- enable/disable-->
|
<leakage>disable</leakage>
|
||||||
</memory>
|
</memory>
|
||||||
</config>
|
</config>
|
||||||
@@ -75,7 +75,7 @@ static int parse_env_int(const char *name, int defv, int minv, int maxv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int default_worker_nr(void) {
|
static int default_worker_nr(void) {
|
||||||
int n = 3;
|
int n = 2;
|
||||||
return parse_env_int("KVS_URING_WORKERS", n, 1, IOURING_MAX_WORKERS);
|
return parse_env_int("KVS_URING_WORKERS", n, 1, IOURING_MAX_WORKERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,184 +1,106 @@
|
|||||||
## `bench` 程序使用说明(命令 + 参数解释)
|
## run_bench.hash.sh 使用指南
|
||||||
|
|
||||||
### 1) 快速查看帮助
|
- 脚本:`test-redis/run_bench.hash.sh`
|
||||||
|
- 默认策略:`persist_no` / `persist_everysec` / `nopersist`
|
||||||
|
- 测试模式:`set` + `prefill+get`
|
||||||
|
- 默认参数:`REQ=1000000 KEYSPACE=1000000 PIPE=128 VSIZE=32 ROUNDS=5 RETRIES=3`
|
||||||
|
|
||||||
|
### 运行示例
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./test-redis/bench --help
|
# 默认运行(5轮)
|
||||||
|
./test-redis/run_bench.hash.sh
|
||||||
|
|
||||||
|
# 指定大 key 参数(示例)
|
||||||
|
ROUNDS=5 REQ=1000000 KEYSPACE=1000000 PIPE=128 VSIZE=256 RETRIES=3 ./test-redis/run_bench.hash.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2) 命令模板
|
### 常用环境变量
|
||||||
|
|
||||||
```bash
|
| 变量 | 默认值 | 说明 |
|
||||||
./test-redis/bench \
|
|
||||||
--host 127.0.0.1 \
|
|
||||||
--port 8888 \
|
|
||||||
--mode mixed \
|
|
||||||
--requests 1000000 \
|
|
||||||
--pipeline 64 \
|
|
||||||
--keyspace 100000 \
|
|
||||||
--value-size 32 \
|
|
||||||
--set-ratio 50 \
|
|
||||||
--set-cmd RSET \
|
|
||||||
--get-cmd RGET \
|
|
||||||
--key-prefix bench:key: \
|
|
||||||
--seed 12345 \
|
|
||||||
--verify-get
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3) 参数解释(对应 `bench.c`)
|
|
||||||
|
|
||||||
| 参数 | 默认值 | 说明 |
|
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `--host <ip>` | `127.0.0.1` | 目标服务 IP |
|
| `ROUNDS` | `5` | 每个策略的轮次 |
|
||||||
| `--port <port>` | `6379` | 目标服务端口 |
|
| `REQ` | `1000000` | 单次 bench 请求数 |
|
||||||
| `--mode <set\|get\|mixed>` | `mixed` | 压测模式:纯写/纯读/读写混合 |
|
| `KEYSPACE` | `1000000` | key 空间大小 |
|
||||||
| `--requests <n>` | `1000000` | 总请求数(不是每秒) |
|
| `PIPE` | `128` | pipeline 深度 |
|
||||||
| `--pipeline <n>` | `64` | pipeline 批量深度 |
|
| `VSIZE` | `32` | value 大小(字节) |
|
||||||
| `--keyspace <n>` | `100000` | key 空间大小,key 随机落在 `[0, keyspace)` |
|
| `RETRIES` | `3` | 单轮失败重试次数 |
|
||||||
| `--value-size <n>` | `32` | value 字节长度 |
|
| `SEED` | `12345` | 随机种子基数 |
|
||||||
| `--set-ratio <0..100>` | `50` | `mixed` 下 SET 比例,GET 比例是 `100-set-ratio` |
|
| `ALLOC` | `mypool` | allocator |
|
||||||
| `--set-cmd <cmd>` | `SET` | 写命令名(如 `SET`/`RSET`) |
|
| `KV_PORT` | `8888` | kvstore 端口 |
|
||||||
| `--get-cmd <cmd>` | `GET` | 读命令名(如 `GET`/`RGET`) |
|
| `SET_CMD` / `GET_CMD` | `RSET` / `RGET` | 压测命令 |
|
||||||
| `--key-prefix <prefix>` | `bench:key:` | key 前缀 |
|
|
||||||
| `--seed <n>` | 当前时间 | 随机种子;固定后可复现实验 |
|
|
||||||
| `--verify-get` | 关闭 | 开启后校验 GET 返回内容是否与写入值一致 |
|
|
||||||
| `--help` / `-h` | - | 打印帮助 |
|
|
||||||
|
|
||||||
|
## 大Key持久化协议复测(覆盖版)
|
||||||
|
|
||||||
## 命令
|
- 时间口径:2026-03-07(本次重测)
|
||||||
|
- 参数:`requests=1000000 pipeline=128 keyspace=1000000 value-size=256`
|
||||||
|
- 轮次:每种策略 `5` 轮
|
||||||
|
- 去异常规则:每个场景按 `qps` 对 `5` 轮做中位数偏差,剔除偏差最大 `1` 轮,再对剩余 `4` 轮取均值
|
||||||
|
- kvstore 源数据:`results/hash_bench_fair_summary_20260307_062549.csv`
|
||||||
|
- redis 源数据:`results/redis_bigkey_summary_20260307_063158.csv`
|
||||||
|
- kvstore 去异常结果:`results/hash_bench_fair_trimmed_20260307_062549.csv`
|
||||||
|
- redis 去异常结果:`results/redis_bigkey_trimmed_20260307_063158.csv`
|
||||||
|
|
||||||
```bash
|
## kvstore 原始5轮
|
||||||
# kvstore 写(RSET)
|
|
||||||
./test-redis/bench --host 127.0.0.1 --port 8888 --mode set --set-cmd RSET --get-cmd RGET --requests 3000000 --pipeline 128 --keyspace 1000000 --value-size 32 --key-prefix bench:ts:set:
|
|
||||||
|
|
||||||
# kvstore 读(RGET)
|
| 策略 | 模式 | Round1 | Round2 | Round3 | Round4 | Round5 | 原始均值QPS | 原始均值us/op |
|
||||||
./test-redis/bench --host 127.0.0.1 --port 8888 --mode get --set-cmd RSET --get-cmd RGET --requests 3000000 --pipeline 128 --keyspace 1000000 --value-size 32 --verify-get --key-prefix bench:ts:get:
|
|---|---|---:|---:|---:|---:|---:|---:|---:|
|
||||||
|
| persist_no | set | 139895.00 | 138768.00 | 138867.00 | 143296.00 | 144388.00 | 141042.80 | 7.09 |
|
||||||
|
| persist_no | get | 163764.00 | 164079.00 | 166415.00 | 163959.00 | 147881.00 | 161219.60 | 6.21 |
|
||||||
|
| persist_everysec | set | 133067.00 | 126140.00 | 133430.00 | 139786.00 | 141145.00 | 134713.60 | 7.43 |
|
||||||
|
| persist_everysec | get | 162076.00 | 165415.00 | 162180.00 | 163762.00 | 158226.00 | 162331.80 | 6.16 |
|
||||||
|
| nopersist | set | 157950.00 | 143109.00 | 135043.00 | 152045.00 | 147233.00 | 147076.00 | 6.82 |
|
||||||
|
| nopersist | get | 163381.00 | 169356.00 | 155890.00 | 164754.00 | 157550.00 | 162186.20 | 6.17 |
|
||||||
|
|
||||||
|
## kvstore 去异常后(4轮均值)
|
||||||
|
|
||||||
# kvstore 写(HSET)
|
| 策略 | 模式 | 剔除轮次 | 剔除QPS | 去异常均值QPS | 去异常均值us/op |
|
||||||
./test-redis/bench --host 127.0.0.1 --port 8888 --mode set --set-cmd HSET --get-cmd HGET --requests 3000000 --pipeline 128 --keyspace 1000000 --value-size 32 --key-prefix bench:ts:set:
|
|---|---|---:|---:|---:|---:|
|
||||||
|
| persist_no | set | 5 | 144388.00 | 140206.50 | 7.13 |
|
||||||
|
| persist_no | get | 5 | 147881.00 | 164554.25 | 6.08 |
|
||||||
|
| persist_everysec | set | 5 | 141145.00 | 133105.75 | 7.52 |
|
||||||
|
| persist_everysec | get | 5 | 158226.00 | 163358.25 | 6.12 |
|
||||||
|
| nopersist | set | 3 | 135043.00 | 150084.25 | 6.67 |
|
||||||
|
| nopersist | get | 3 | 155890.00 | 163760.25 | 6.11 |
|
||||||
|
|
||||||
# kvstore 读(HGET)
|
## kvstore 协议开销(基线 nopersist,去异常后)
|
||||||
./test-redis/bench --host 127.0.0.1 --port 8888 --mode get --set-cmd HSET --get-cmd HGET --requests 3000000 --pipeline 128 --keyspace 1000000 --value-size 32 --verify-get --key-prefix bench:ts:get:
|
|
||||||
|
|
||||||
# Redis 策略对比(示例:6381 配置成 rdb_default)
|
| 策略 | set QPS变化 | set us/op变化 | get QPS变化 | get us/op变化 |
|
||||||
./test-redis/bench --host 127.0.0.1 --port 6381 --mode set --requests 3000000 --pipeline 128 --keyspace 1000000000 --value-size 32 --key-prefix bench:ts:redis:
|
|---|---:|---:|---:|---:|
|
||||||
./test-redis/bench --host 127.0.0.1 --port 6379 --mode set --requests 3000000 --pipeline 128 --keyspace 1000000000 --value-size 32 --key-prefix bench:ts:redis:
|
| persist_no | -6.58% | +6.90% | +0.48% | -0.49% |
|
||||||
|
| persist_everysec | -11.31% | +12.74% | -0.25% | +0.16% |
|
||||||
|
|
||||||
./test-redis/bench --host 127.0.0.1 --port 6381 --mode set --requests 3000000 --pipeline 128 --keyspace 1000000000 --value-size 32 --key-prefix bench:ts:redis:
|
## Redis 原始5轮
|
||||||
./test-redis/bench --host 127.0.0.1 --port 6379 --mode set --requests 3000000 --pipeline 128 --keyspace 1000000000 --value-size 32 --key-prefix bench:ts:redis:
|
|
||||||
```
|
|
||||||
|
|
||||||
|
| 策略 | 模式 | Round1 | Round2 | Round3 | Round4 | Round5 | 原始均值QPS | 原始均值us/op |
|
||||||
|
|---|---|---:|---:|---:|---:|---:|---:|---:|
|
||||||
|
| none | set | 198673.00 | 211843.00 | 193900.00 | 208293.00 | 211071.00 | 204756.00 | 4.89 |
|
||||||
|
| none | get | 225347.00 | 221000.00 | 218357.00 | 216466.00 | 214747.00 | 219183.40 | 4.56 |
|
||||||
|
| aof_no | set | 144042.00 | 139615.00 | 140016.00 | 149925.00 | 150658.00 | 144851.20 | 6.91 |
|
||||||
|
| aof_no | get | 210541.00 | 211713.00 | 202589.00 | 231251.00 | 402028.00 | 251624.40 | 4.24 |
|
||||||
|
| aof_everysec | set | 143737.00 | 132998.00 | 136973.00 | 144448.00 | 142414.00 | 140114.00 | 7.14 |
|
||||||
|
| aof_everysec | get | 212422.00 | 201051.00 | 211508.00 | 192190.00 | 209874.00 | 205409.00 | 4.87 |
|
||||||
|
|
||||||
|
## Redis 去异常后(4轮均值)
|
||||||
|
|
||||||
## run_hash_bench.sh 三轮均值复测(2026-03-05 07:59:54)
|
| 策略 | 模式 | 剔除轮次 | 剔除QPS | 去异常均值QPS | 去异常均值us/op |
|
||||||
|
|---|---|---:|---:|---:|---:|
|
||||||
|
| none | set | 3 | 193900.00 | 207470.00 | 4.82 |
|
||||||
|
| none | get | 1 | 225347.00 | 217642.50 | 4.59 |
|
||||||
|
| aof_no | set | 5 | 150658.00 | 143399.50 | 6.98 |
|
||||||
|
| aof_no | get | 5 | 402028.00 | 214023.50 | 4.68 |
|
||||||
|
| aof_everysec | set | 2 | 132998.00 | 141893.00 | 7.05 |
|
||||||
|
| aof_everysec | get | 4 | 192190.00 | 208713.75 | 4.79 |
|
||||||
|
|
||||||
- 轮次:3 轮(取均值)
|
## Redis 协议开销(基线 none,去异常后)
|
||||||
- 参数:requests=1000000 pipeline=128 keyspace=1000000 value-size=32
|
|
||||||
- 明细数据:`results/hash_bench_detail_20260305_075954.csv`
|
|
||||||
- 汇总数据:`results/hash_bench_summary_20260305_075954.csv`
|
|
||||||
|
|
||||||
### kvstore:RSET/RGET(持久化 × allocator)
|
| 策略 | set QPS变化 | set us/op变化 | get QPS变化 | get us/op变化 |
|
||||||
|
|---|---:|---:|---:|---:|
|
||||||
|
| aof_no | -30.88% | +44.81% | -1.66% | +1.96% |
|
||||||
|
| aof_everysec | -31.61% | +46.27% | -4.10% | +4.36% |
|
||||||
|
|
||||||
| 场景 | 模式 | Round1 | Round2 | Round3 | 均值QPS | 均值avg(us/op) | 均值elapsed(s) |
|
## 简要结论
|
||||||
|---|---:|---:|---:|---:|---:|---:|---:|
|
|
||||||
| persist_mypool (incremental, mypool) | set | 125179 | 170592 | 164976 | 153582.33 | 6.64 | 6.64 |
|
|
||||||
| persist_mypool (incremental, mypool) | get | 186087 | 195807 | 193450 | 191781.33 | 5.22 | 5.22 |
|
|
||||||
| nopersist_mypool (none, mypool) | set | 185397 | 189265 | 187515 | 187392.33 | 5.33 | 5.34 |
|
|
||||||
| nopersist_mypool (none, mypool) | get | 195032 | 203252 | 196291 | 198191.67 | 5.05 | 5.05 |
|
|
||||||
| persist_malloc (incremental, malloc) | set | 175529 | 172307 | 181948 | 176594.67 | 5.67 | 5.67 |
|
|
||||||
| persist_malloc (incremental, malloc) | get | 202299 | 207732 | 181749 | 197260.00 | 5.08 | 5.09 |
|
|
||||||
| nopersist_malloc (none, malloc) | set | 162956 | 192052 | 191846 | 182284.67 | 5.52 | 5.52 |
|
|
||||||
| nopersist_malloc (none, malloc) | get | 200417 | 211609 | 196936 | 202987.33 | 4.93 | 4.93 |
|
|
||||||
|
|
||||||
### Redis:SET/GET(各持久化模式)
|
|
||||||
|
|
||||||
| 场景 | 模式 | Round1 | Round2 | Round3 | 均值QPS | 均值avg(us/op) | 均值elapsed(s) |
|
|
||||||
|---|---:|---:|---:|---:|---:|---:|---:|
|
|
||||||
| none (none) | set | 234761 | 247981 | 243948 | 242230.00 | 4.13 | 4.13 |
|
|
||||||
| none (none) | get | 247753 | 284771 | 275492 | 269338.67 | 3.73 | 3.73 |
|
|
||||||
| rdb_default (rdb_default) | set | 245989 | 238020 | 241112 | 241707.00 | 4.14 | 4.14 |
|
|
||||||
| rdb_default (rdb_default) | get | 278725 | 274510 | 276342 | 276525.67 | 3.62 | 3.62 |
|
|
||||||
| aof_no (aof_no) | set | 196100 | 209723 | 201687 | 202503.33 | 4.94 | 4.94 |
|
|
||||||
| aof_no (aof_no) | get | 269520 | 277701 | 270562 | 272594.33 | 3.67 | 3.67 |
|
|
||||||
| aof_everysec (aof_everysec) | set | 201758 | 201078 | 180037 | 194291.00 | 5.16 | 5.16 |
|
|
||||||
| aof_everysec (aof_everysec) | get | 259585 | 269224 | 279181 | 269330.00 | 3.71 | 3.72 |
|
|
||||||
| aof_always (aof_always) | set | 75968 | 78265 | 76608 | 76947.00 | 13.00 | 13.00 |
|
|
||||||
| aof_always (aof_always) | get | 276839 | 271247 | 275017 | 274367.67 | 3.65 | 3.65 |
|
|
||||||
|
|
||||||
|
|
||||||
## run_hash_bench.sh 三轮均值复测(2026-03-05 12:58:34)
|
|
||||||
|
|
||||||
- 轮次:5 轮(取均值)
|
|
||||||
- 参数:requests=1000000 pipeline=128 keyspace=1000000 value-size=32
|
|
||||||
- 明细数据:`results/hash_bench_detail_20260305_125834.csv`
|
|
||||||
- 汇总数据:`results/hash_bench_summary_20260305_125834.csv`
|
|
||||||
|
|
||||||
### kvstore:RSET/RGET(持久化 × allocator)
|
|
||||||
|
|
||||||
| 场景 | 模式 | Round1 | Round2 | Round3 | Round4 | Round5 | 均值QPS | 均值avg(us/op) | 均值elapsed(s) |
|
|
||||||
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|
|
|
||||||
| persist_mypool (incremental, mypool) | set | 166832 | 172252 | 184622 | 173181 | 180547 | 175486.80 | 5.71 | 5.71 |
|
|
||||||
| persist_mypool (incremental, mypool) | get | 187976 | 188203 | 193459 | 184560 | 190543 | 188948.20 | 5.29 | 5.29 |
|
|
||||||
| nopersist_mypool (none, mypool) | set | 183273 | 180666 | 184588 | 182765 | 180441 | 182346.60 | 5.49 | 5.48 |
|
|
||||||
| nopersist_mypool (none, mypool) | get | 186969 | 185652 | 183546 | 187826 | 191845 | 187167.60 | 5.34 | 5.34 |
|
|
||||||
| persist_malloc (incremental, malloc) | set | 189030 | 135132 | 163693 | 161888 | 163137 | 162576.00 | 6.22 | 6.22 |
|
|
||||||
| persist_malloc (incremental, malloc) | get | 198683 | 166038 | 159371 | 184912 | 181288 | 178058.40 | 5.65 | 5.65 |
|
|
||||||
| nopersist_malloc (none, malloc) | set | 181197 | 189295 | 189128 | 181291 | 178993 | 183980.80 | 5.44 | 5.44 |
|
|
||||||
| nopersist_malloc (none, malloc) | get | 189424 | 193316 | 194474 | 186572 | 163052 | 185367.60 | 5.42 | 5.42 |
|
|
||||||
|
|
||||||
### Redis:SET/GET(各持久化模式)
|
|
||||||
|
|
||||||
| 场景 | 模式 | Round1 | Round2 | Round3 | Round4 | Round5 | 均值QPS | 均值avg(us/op) | 均值elapsed(s) |
|
|
||||||
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|
|
|
||||||
| none (none) | set | 229799 | 235912 | 233883 | 232683 | 239711 | 234397.60 | 4.27 | 4.27 |
|
|
||||||
| none (none) | get | 256082 | 274863 | 257801 | 250389 | 262797 | 260386.40 | 3.85 | 3.84 |
|
|
||||||
| rdb_default (rdb_default) | set | 238612 | 232348 | 231110 | 233426 | 227900 | 232679.20 | 4.30 | 4.30 |
|
|
||||||
| rdb_default (rdb_default) | get | 268351 | 263651 | 268189 | 265139 | 249811 | 263028.20 | 3.80 | 3.80 |
|
|
||||||
| aof_no (aof_no) | set | 178673 | 199836 | 205048 | 204901 | 195694 | 196830.40 | 5.09 | 5.09 |
|
|
||||||
| aof_no (aof_no) | get | 245237 | 271172 | 257791 | 260414 | 269400 | 260802.80 | 3.84 | 3.84 |
|
|
||||||
| aof_everysec (aof_everysec) | set | 198803 | 193822 | 188866 | 170821 | 97423 | 169947.00 | 6.32 | 6.32 |
|
|
||||||
| aof_everysec (aof_everysec) | get | 277244 | 257143 | 253943 | 269896 | 284002 | 268445.60 | 3.73 | 3.73 |
|
|
||||||
| aof_always (aof_always) | set | 66274 | 70593 | 65851 | 54098 | 74587 | 66280.60 | 15.27 | 15.27 |
|
|
||||||
| aof_always (aof_always) | get | 263043 | 265738 | 257121 | 266889 | 272781 | 265114.40 | 3.77 | 3.77 |
|
|
||||||
|
|
||||||
|
|
||||||
## run_hash_bench.sh 三轮均值复测(2026-03-06 09:00:30)
|
|
||||||
|
|
||||||
- 轮次:3 轮(取均值)
|
|
||||||
- 参数:requests=1000000 pipeline=128 keyspace=1000000 value-size=32
|
|
||||||
- 明细数据:`results/hash_bench_detail_20260306_090030.csv`
|
|
||||||
- 汇总数据:`results/hash_bench_summary_20260306_090030.csv`
|
|
||||||
|
|
||||||
### kvstore:RSET/RGET(持久化 × allocator)
|
|
||||||
|
|
||||||
| 场景 | 模式 | Round1 | Round2 | Round3 | 均值QPS | 均值avg(us/op) | 均值elapsed(s) |
|
|
||||||
|---|---:|---:|---:|---:|---:|---:|---:|
|
|
||||||
| persist_mypool (incremental, mypool) | set | 170954 | 158299 | 175493 | 168248.67 | 5.96 | 5.96 |
|
|
||||||
| persist_mypool (incremental, mypool) | get | 173519 | 181416 | 188295 | 181076.67 | 5.53 | 5.53 |
|
|
||||||
| everysec_mypool (incremental, mypool) | set | 158378 | 160029 | 175998 | 164801.67 | 6.08 | 6.08 |
|
|
||||||
| everysec_mypool (incremental, mypool) | get | 180343 | 177421 | 177644 | 178469.33 | 5.60 | 5.60 |
|
|
||||||
| nopersist_mypool (none, mypool) | set | 168031 | 160304 | 168327 | 165554.00 | 6.04 | 6.04 |
|
|
||||||
| nopersist_mypool (none, mypool) | get | 173737 | 173007 | 161784 | 169509.33 | 5.91 | 5.91 |
|
|
||||||
| persist_malloc (incremental, malloc) | set | 160752 | 142393 | 182518 | 161887.67 | 6.24 | 6.24 |
|
|
||||||
| persist_malloc (incremental, malloc) | get | 157918 | 177457 | 181606 | 172327.00 | 5.83 | 5.82 |
|
|
||||||
| everysec_malloc (incremental, malloc) | set | 178195 | 168682 | 177041 | 174639.33 | 5.73 | 5.73 |
|
|
||||||
| everysec_malloc (incremental, malloc) | get | 193145 | 149187 | 178615 | 173649.00 | 5.83 | 5.83 |
|
|
||||||
| nopersist_malloc (none, malloc) | set | 170011 | 172967 | 171752 | 171576.67 | 5.83 | 5.83 |
|
|
||||||
| nopersist_malloc (none, malloc) | get | 174777 | 173381 | 181365 | 176507.67 | 5.67 | 5.67 |
|
|
||||||
|
|
||||||
### Redis:SET/GET(各持久化模式)
|
|
||||||
|
|
||||||
| 场景 | 模式 | Round1 | Round2 | Round3 | 均值QPS | 均值avg(us/op) | 均值elapsed(s) |
|
|
||||||
|---|---:|---:|---:|---:|---:|---:|---:|
|
|
||||||
| none (none) | set | 218920 | 223448 | 222306 | 221558.00 | 4.52 | 4.51 |
|
|
||||||
| none (none) | get | 252607 | 255685 | 256130 | 254807.33 | 3.92 | 3.92 |
|
|
||||||
| rdb_default (rdb_default) | set | 216497 | 220924 | 214752 | 217391.00 | 4.60 | 4.60 |
|
|
||||||
| rdb_default (rdb_default) | get | 252492 | 246194 | 248558 | 249081.33 | 4.01 | 4.02 |
|
|
||||||
| aof_no (aof_no) | set | 166307 | 186052 | 181121 | 177826.67 | 5.63 | 5.64 |
|
|
||||||
| aof_no (aof_no) | get | 255742 | 254771 | 257784 | 256099.00 | 3.91 | 3.90 |
|
|
||||||
| aof_everysec (aof_everysec) | set | 180584 | 184429 | 172466 | 179159.67 | 5.59 | 5.59 |
|
|
||||||
| aof_everysec (aof_everysec) | get | 257102 | 232146 | 242470 | 243906.00 | 4.11 | 4.11 |
|
|
||||||
| aof_always (aof_always) | set | 65397 | 67487 | 67538 | 66807.33 | 14.97 | 14.97 |
|
|
||||||
| aof_always (aof_always) | get | 235975 | 247116 | 227383 | 236824.67 | 4.23 | 4.23 |
|
|
||||||
|
|
||||||
|
1. 本次大 key(256)下,持久化开销主要体现在 `set`,`get` 相对更稳。
|
||||||
|
2. `aof_no/aof_everysec` 在 Redis 写路径的开销明显;kvstore 三策略在写路径也存在可见差异。
|
||||||
|
3. 本报告已剔除每场景 1 个异常轮次,避免单点抖动主导结论。
|
||||||
|
|||||||
BIN
test-redis/bench
BIN
test-redis/bench
Binary file not shown.
437
test-redis/run_bench.hash.sh
Executable file
437
test-redis/run_bench.hash.sh
Executable file
@@ -0,0 +1,437 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||||
|
ROOT_DIR=$(cd "$SCRIPT_DIR/.." && pwd)
|
||||||
|
cd "$ROOT_DIR"
|
||||||
|
|
||||||
|
TS=$(date +%Y%m%d_%H%M%S)
|
||||||
|
RUN_TIME=$(date '+%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
|
OUT_DIR="$ROOT_DIR/test-redis/results"
|
||||||
|
mkdir -p "$OUT_DIR"
|
||||||
|
|
||||||
|
DETAIL_CSV="$OUT_DIR/hash_bench_fair_detail_${TS}.csv"
|
||||||
|
SUMMARY_CSV="$OUT_DIR/hash_bench_fair_summary_${TS}.csv"
|
||||||
|
KV_LOG_DIR="/tmp/kv_bench_hash_fair_${TS}"
|
||||||
|
mkdir -p "$KV_LOG_DIR"
|
||||||
|
|
||||||
|
CONFIG_XML="$ROOT_DIR/config/config.xml"
|
||||||
|
README_MD="$ROOT_DIR/test-redis/README.md"
|
||||||
|
|
||||||
|
ROUNDS=${ROUNDS:-5}
|
||||||
|
RETRIES=${RETRIES:-3}
|
||||||
|
REQ=${REQ:-1000000}
|
||||||
|
PIPE=${PIPE:-128}
|
||||||
|
KEYSPACE=${KEYSPACE:-1000000}
|
||||||
|
VSIZE=${VSIZE:-32}
|
||||||
|
SEED=${SEED:-12345}
|
||||||
|
ALLOC=${ALLOC:-mypool}
|
||||||
|
KV_HOST=127.0.0.1
|
||||||
|
KV_PORT=${KV_PORT:-8888}
|
||||||
|
SET_CMD=${SET_CMD:-RSET}
|
||||||
|
GET_CMD=${GET_CMD:-RGET}
|
||||||
|
|
||||||
|
ORIG_CONFIG_BACKUP=$(mktemp "/tmp/kvstore_config_backup_${TS}.XXXXXX")
|
||||||
|
cp "$CONFIG_XML" "$ORIG_CONFIG_BACKUP"
|
||||||
|
KV_PID=""
|
||||||
|
|
||||||
|
printf "strategy,persistence,oplog_sync,allocator,mode,round,qps,avg_us,elapsed_s,key_prefix,seed,requests,pipeline,keyspace,value_size\n" > "$DETAIL_CSV"
|
||||||
|
printf "strategy,persistence,oplog_sync,allocator,mode,round_qps,round_avg_us,round_elapsed_s,avg_qps,avg_avg_us,avg_elapsed_s\n" > "$SUMMARY_CSV"
|
||||||
|
|
||||||
|
require_cmd() {
|
||||||
|
local cmd="$1"
|
||||||
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||||
|
echo "missing required command: $cmd" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_binaries() {
|
||||||
|
if [[ ! -x "$ROOT_DIR/kvstore" || ! -x "$ROOT_DIR/test-redis/bench" ]]; then
|
||||||
|
echo "[info] kvstore/bench missing, running make -j4 ..."
|
||||||
|
make -j4
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
set_config() {
|
||||||
|
local ptype="$1"
|
||||||
|
local oplog_sync="$2"
|
||||||
|
local pdir="$3"
|
||||||
|
local alloc="$4"
|
||||||
|
python3 - "$CONFIG_XML" "$ptype" "$oplog_sync" "$pdir" "$alloc" "$KV_PORT" <<'PY'
|
||||||
|
import sys
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
path, ptype, oplog_sync, pdir, alloc, kv_port = sys.argv[1:]
|
||||||
|
tree = ET.parse(path)
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
server = root.find("server")
|
||||||
|
if server is not None:
|
||||||
|
ip = server.find("ip")
|
||||||
|
port = server.find("port")
|
||||||
|
mode = server.find("mode")
|
||||||
|
replica = server.find("replica")
|
||||||
|
if ip is not None:
|
||||||
|
ip.text = "127.0.0.1"
|
||||||
|
if port is not None:
|
||||||
|
port.text = kv_port
|
||||||
|
if mode is not None:
|
||||||
|
mode.text = "master"
|
||||||
|
if replica is not None:
|
||||||
|
replica.text = "disable"
|
||||||
|
|
||||||
|
persistence = root.find("persistence")
|
||||||
|
if persistence is not None:
|
||||||
|
t = persistence.find("type")
|
||||||
|
d = persistence.find("dir")
|
||||||
|
s = persistence.find("oplog_sync")
|
||||||
|
if t is not None:
|
||||||
|
t.text = ptype
|
||||||
|
if d is not None:
|
||||||
|
d.text = pdir
|
||||||
|
if s is not None:
|
||||||
|
s.text = oplog_sync
|
||||||
|
|
||||||
|
memory = root.find("memory")
|
||||||
|
if memory is not None:
|
||||||
|
a = memory.find("allocator")
|
||||||
|
leak = memory.find("leakage")
|
||||||
|
if a is not None:
|
||||||
|
a.text = alloc
|
||||||
|
if leak is not None:
|
||||||
|
leak.text = "disable"
|
||||||
|
|
||||||
|
tree.write(path, encoding="UTF-8", xml_declaration=True)
|
||||||
|
PY
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_port_open() {
|
||||||
|
local port="$1"
|
||||||
|
for _ in $(seq 1 200); do
|
||||||
|
if ss -ltn | rg -q ":${port}\\b"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_port_close() {
|
||||||
|
local port="$1"
|
||||||
|
for _ in $(seq 1 200); do
|
||||||
|
if ! ss -ltn | rg -q ":${port}\\b"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_port_free() {
|
||||||
|
local port="$1"
|
||||||
|
if ss -ltn | rg -q ":${port}\\b"; then
|
||||||
|
echo "port ${port} is already in use, cannot start kvstore" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_metric() {
|
||||||
|
local line="$1"
|
||||||
|
local key="$2"
|
||||||
|
echo "$line" | sed -E "s/.*${key}=([0-9]+(\\.[0-9]+)?).*/\\1/"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_bench_capture() {
|
||||||
|
local mode="$1"
|
||||||
|
local key_prefix="$2"
|
||||||
|
local seed="$3"
|
||||||
|
local verify="$4"
|
||||||
|
local cmd=(
|
||||||
|
./test-redis/bench
|
||||||
|
--host "$KV_HOST"
|
||||||
|
--port "$KV_PORT"
|
||||||
|
--mode "$mode"
|
||||||
|
--set-cmd "$SET_CMD"
|
||||||
|
--get-cmd "$GET_CMD"
|
||||||
|
--requests "$REQ"
|
||||||
|
--pipeline "$PIPE"
|
||||||
|
--keyspace "$KEYSPACE"
|
||||||
|
--value-size "$VSIZE"
|
||||||
|
--seed "$seed"
|
||||||
|
--key-prefix "$key_prefix"
|
||||||
|
)
|
||||||
|
if [[ "$verify" == "1" ]]; then
|
||||||
|
cmd+=(--verify-get)
|
||||||
|
fi
|
||||||
|
|
||||||
|
local out
|
||||||
|
out=$("${cmd[@]}")
|
||||||
|
echo "$out" >&2
|
||||||
|
|
||||||
|
local line
|
||||||
|
line=$(echo "$out" | rg "\\[result\\]" | tail -n1)
|
||||||
|
if [[ -z "$line" ]]; then
|
||||||
|
echo "missing [result] line in benchmark output" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local qps avg elapsed
|
||||||
|
qps=$(extract_metric "$line" "qps")
|
||||||
|
avg=$(extract_metric "$line" "avg")
|
||||||
|
elapsed=$(extract_metric "$line" "elapsed")
|
||||||
|
if [[ -z "$qps" || -z "$avg" || -z "$elapsed" ]]; then
|
||||||
|
echo "failed to parse benchmark metrics: $line" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$qps,$avg,$elapsed"
|
||||||
|
}
|
||||||
|
|
||||||
|
start_kv() {
|
||||||
|
local label="$1"
|
||||||
|
assert_port_free "$KV_PORT"
|
||||||
|
./kvstore >"$KV_LOG_DIR/${label}.log" 2>&1 &
|
||||||
|
KV_PID=$!
|
||||||
|
if ! wait_port_open "$KV_PORT"; then
|
||||||
|
echo "kvstore start failed for ${label}" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_kv() {
|
||||||
|
if [[ -n "${KV_PID:-}" ]] && kill -0 "$KV_PID" >/dev/null 2>&1; then
|
||||||
|
kill "$KV_PID" >/dev/null 2>&1 || true
|
||||||
|
wait "$KV_PID" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
KV_PID=""
|
||||||
|
wait_port_close "$KV_PORT" || true
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
stop_kv
|
||||||
|
if [[ -f "$ORIG_CONFIG_BACKUP" ]]; then
|
||||||
|
cp "$ORIG_CONFIG_BACKUP" "$CONFIG_XML"
|
||||||
|
rm -f "$ORIG_CONFIG_BACKUP"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
case_params() {
|
||||||
|
local strategy="$1"
|
||||||
|
case "$strategy" in
|
||||||
|
persist_no)
|
||||||
|
echo "incremental,none"
|
||||||
|
;;
|
||||||
|
persist_everysec)
|
||||||
|
echo "incremental,every_sec"
|
||||||
|
;;
|
||||||
|
nopersist)
|
||||||
|
echo "none,none"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "unknown strategy: $strategy" >&2
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
run_one_case_round() {
|
||||||
|
local strategy="$1"
|
||||||
|
local round="$2"
|
||||||
|
local params ptype oplog_sync
|
||||||
|
local pdir_rel pdir_abs
|
||||||
|
local key_prefix seed
|
||||||
|
local m qps avg elapsed
|
||||||
|
local set_qps set_avg set_elapsed
|
||||||
|
local get_qps get_avg get_elapsed
|
||||||
|
local attempt ok
|
||||||
|
|
||||||
|
params=$(case_params "$strategy")
|
||||||
|
IFS=',' read -r ptype oplog_sync <<< "$params"
|
||||||
|
|
||||||
|
key_prefix="bench:${TS}:round:${round}:"
|
||||||
|
seed=$((SEED + round))
|
||||||
|
|
||||||
|
for attempt in $(seq 1 "$RETRIES"); do
|
||||||
|
pdir_rel="data/${strategy}_${TS}_r${round}_a${attempt}"
|
||||||
|
pdir_abs="$ROOT_DIR/${pdir_rel}"
|
||||||
|
rm -rf "$pdir_abs"
|
||||||
|
mkdir -p "$pdir_abs"
|
||||||
|
|
||||||
|
set_config "$ptype" "$oplog_sync" "$pdir_rel" "$ALLOC"
|
||||||
|
start_kv "${strategy}_r${round}_a${attempt}"
|
||||||
|
|
||||||
|
ok=1
|
||||||
|
if ! m=$(run_bench_capture "set" "$key_prefix" "$seed" 0); then
|
||||||
|
ok=0
|
||||||
|
else
|
||||||
|
IFS=',' read -r set_qps set_avg set_elapsed <<< "$m"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$ok" == "1" ]]; then
|
||||||
|
if ! m=$(run_bench_capture "get" "$key_prefix" "$seed" 1); then
|
||||||
|
ok=0
|
||||||
|
else
|
||||||
|
IFS=',' read -r get_qps get_avg get_elapsed <<< "$m"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
stop_kv
|
||||||
|
|
||||||
|
if [[ "$ok" == "1" ]]; then
|
||||||
|
printf "%s,%s,%s,%s,set,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" \
|
||||||
|
"$strategy" "$ptype" "$oplog_sync" "$ALLOC" "$round" \
|
||||||
|
"$set_qps" "$set_avg" "$set_elapsed" "$key_prefix" "$seed" \
|
||||||
|
"$REQ" "$PIPE" "$KEYSPACE" "$VSIZE" >> "$DETAIL_CSV"
|
||||||
|
|
||||||
|
printf "%s,%s,%s,%s,get,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" \
|
||||||
|
"$strategy" "$ptype" "$oplog_sync" "$ALLOC" "$round" \
|
||||||
|
"$get_qps" "$get_avg" "$get_elapsed" "$key_prefix" "$seed" \
|
||||||
|
"$REQ" "$PIPE" "$KEYSPACE" "$VSIZE" >> "$DETAIL_CSV"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[warn] retry $attempt/$RETRIES failed: strategy=$strategy round=$round" >&2
|
||||||
|
sleep 0.2
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "[error] all retries failed: strategy=$strategy round=$round" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
append_readme_results() {
|
||||||
|
python3 - "$DETAIL_CSV" "$SUMMARY_CSV" "$README_MD" "$RUN_TIME" "$ROUNDS" "$REQ" "$PIPE" "$KEYSPACE" "$VSIZE" "$ALLOC" "$SET_CMD" "$GET_CMD" <<'PY'
|
||||||
|
import csv
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
detail_csv, summary_csv, readme_path, run_time, rounds, req, pipeline, keyspace, value_size, alloc, set_cmd, get_cmd = sys.argv[1:]
|
||||||
|
rounds_i = int(rounds)
|
||||||
|
|
||||||
|
group = defaultdict(list)
|
||||||
|
meta = {}
|
||||||
|
|
||||||
|
with open(detail_csv, newline="", encoding="utf-8") as f:
|
||||||
|
reader = csv.DictReader(f)
|
||||||
|
for r in reader:
|
||||||
|
key = (r["strategy"], r["mode"])
|
||||||
|
group[key].append(r)
|
||||||
|
meta[r["strategy"]] = (r["persistence"], r["oplog_sync"], r["allocator"])
|
||||||
|
|
||||||
|
def f2(x):
|
||||||
|
return f"{float(x):.2f}"
|
||||||
|
|
||||||
|
with open(summary_csv, "w", newline="", encoding="utf-8") as f:
|
||||||
|
w = csv.writer(f)
|
||||||
|
w.writerow([
|
||||||
|
"strategy","persistence","oplog_sync","allocator","mode",
|
||||||
|
"round_qps","round_avg_us","round_elapsed_s",
|
||||||
|
"avg_qps","avg_avg_us","avg_elapsed_s"
|
||||||
|
])
|
||||||
|
|
||||||
|
for strategy in ["persist_no", "persist_everysec", "nopersist"]:
|
||||||
|
for mode in ["set", "get"]:
|
||||||
|
rows = sorted(group[(strategy, mode)], key=lambda x: int(x["round"]))
|
||||||
|
qps = [float(r["qps"]) for r in rows]
|
||||||
|
avg_us = [float(r["avg_us"]) for r in rows]
|
||||||
|
elapsed = [float(r["elapsed_s"]) for r in rows]
|
||||||
|
persistence, oplog_sync, allocator = meta[strategy]
|
||||||
|
w.writerow([
|
||||||
|
strategy, persistence, oplog_sync, allocator, mode,
|
||||||
|
"|".join(f2(v) for v in qps),
|
||||||
|
"|".join(f2(v) for v in avg_us),
|
||||||
|
"|".join(f2(v) for v in elapsed),
|
||||||
|
f2(sum(qps) / len(qps)),
|
||||||
|
f2(sum(avg_us) / len(avg_us)),
|
||||||
|
f2(sum(elapsed) / len(elapsed)),
|
||||||
|
])
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
with open(summary_csv, newline="", encoding="utf-8") as f:
|
||||||
|
rows = list(csv.DictReader(f))
|
||||||
|
|
||||||
|
def by_mode(mode):
|
||||||
|
ordered = ["persist_no", "persist_everysec", "nopersist"]
|
||||||
|
m = [r for r in rows if r["mode"] == mode]
|
||||||
|
m.sort(key=lambda r: ordered.index(r["strategy"]))
|
||||||
|
return m
|
||||||
|
|
||||||
|
round_headers = [f"Round{i}" for i in range(1, rounds_i + 1)]
|
||||||
|
detail_rel = os.path.relpath(detail_csv, os.path.dirname(readme_path))
|
||||||
|
summary_rel = os.path.relpath(summary_csv, os.path.dirname(readme_path))
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
lines.append("")
|
||||||
|
lines.append(f"## run_bench.hash.sh {rounds_i}轮均值复测({run_time})")
|
||||||
|
lines.append("")
|
||||||
|
lines.append(f"- 轮次:{rounds_i} 轮(每种情况)")
|
||||||
|
lines.append("- 策略:persist(no), persist(everysec), nopersist")
|
||||||
|
lines.append(f"- 命令:{set_cmd}/{get_cmd}(GET 保持 prefill + GET)")
|
||||||
|
lines.append("- 公平性:同一 case 同一轮的 SET/GET 使用相同 key_prefix 与 seed;case 顺序按轮次轮转")
|
||||||
|
lines.append(f"- 参数:requests={req} pipeline={pipeline} keyspace={keyspace} value-size={value_size} allocator={alloc}")
|
||||||
|
lines.append(f"- 明细数据:`{detail_rel}`")
|
||||||
|
lines.append(f"- 汇总数据:`{summary_rel}`")
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
|
for mode in ["set", "get"]:
|
||||||
|
lines.append(f"### kvstore:{set_cmd}/{get_cmd} ({mode})")
|
||||||
|
lines.append("")
|
||||||
|
header = "| 场景 | persistence | oplog_sync | " + " | ".join(round_headers) + " | 均值QPS | 均值avg(us/op) | 均值elapsed(s) |"
|
||||||
|
sep = "|---|---|---|" + "|".join(["---:"] * len(round_headers)) + "|---:|---:|---:|"
|
||||||
|
lines.append(header)
|
||||||
|
lines.append(sep)
|
||||||
|
for r in by_mode(mode):
|
||||||
|
qps_rounds = r["round_qps"].split("|")
|
||||||
|
lines.append(
|
||||||
|
"| {} | {} | {} | {} | {} | {} | {} |".format(
|
||||||
|
r["strategy"],
|
||||||
|
r["persistence"],
|
||||||
|
r["oplog_sync"],
|
||||||
|
" | ".join(qps_rounds),
|
||||||
|
r["avg_qps"],
|
||||||
|
r["avg_avg_us"],
|
||||||
|
r["avg_elapsed_s"],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
|
with open(readme_path, "a", encoding="utf-8") as f:
|
||||||
|
f.write("\n".join(lines) + "\n")
|
||||||
|
PY
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
require_cmd python3
|
||||||
|
require_cmd rg
|
||||||
|
require_cmd ss
|
||||||
|
ensure_binaries
|
||||||
|
|
||||||
|
for round in $(seq 1 "$ROUNDS"); do
|
||||||
|
case $((round % 3)) in
|
||||||
|
1)
|
||||||
|
order=(persist_no persist_everysec nopersist)
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
order=(persist_everysec nopersist persist_no)
|
||||||
|
;;
|
||||||
|
0)
|
||||||
|
order=(nopersist persist_no persist_everysec)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
for strategy in "${order[@]}"; do
|
||||||
|
run_one_case_round "$strategy" "$round"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
append_readme_results
|
||||||
|
|
||||||
|
echo "DETAIL_CSV=$DETAIL_CSV"
|
||||||
|
echo "SUMMARY_CSV=$SUMMARY_CSV"
|
||||||
|
echo "README_UPDATED=$README_MD"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
@@ -1,524 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
|
||||||
ROOT_DIR=$(cd "$SCRIPT_DIR/.." && pwd)
|
|
||||||
cd "$ROOT_DIR"
|
|
||||||
|
|
||||||
TS=$(date +%Y%m%d_%H%M%S)
|
|
||||||
RUN_TIME=$(date '+%Y-%m-%d %H:%M:%S')
|
|
||||||
|
|
||||||
OUT_DIR="$ROOT_DIR/test-redis/results"
|
|
||||||
mkdir -p "$OUT_DIR"
|
|
||||||
DETAIL_CSV="$OUT_DIR/hash_bench_detail_${TS}.csv"
|
|
||||||
SUMMARY_CSV="$OUT_DIR/hash_bench_summary_${TS}.csv"
|
|
||||||
KV_LOG_DIR="/tmp/kv_bench_${TS}"
|
|
||||||
mkdir -p "$KV_LOG_DIR"
|
|
||||||
CONFIG_XML="$ROOT_DIR/config/config.xml"
|
|
||||||
README_MD="$ROOT_DIR/test-redis/README.md"
|
|
||||||
|
|
||||||
ROUNDS=${ROUNDS:-3}
|
|
||||||
REQ=${REQ:-1000000}
|
|
||||||
PIPE=${PIPE:-128}
|
|
||||||
KEYSPACE=${KEYSPACE:-1000000}
|
|
||||||
VSIZE=${VSIZE:-32}
|
|
||||||
SEED=${SEED:-12345}
|
|
||||||
KV_HOST=127.0.0.1
|
|
||||||
KV_PORT=${KV_PORT:-8888}
|
|
||||||
REDIS_HOST=127.0.0.1
|
|
||||||
REDIS_PORTS=(6381 6382 6383 6384 6385)
|
|
||||||
|
|
||||||
ORIG_CONFIG_BACKUP=$(mktemp "/tmp/kvstore_config_backup_${TS}.XXXXXX")
|
|
||||||
cp "$CONFIG_XML" "$ORIG_CONFIG_BACKUP"
|
|
||||||
KV_PID=""
|
|
||||||
|
|
||||||
printf "target,strategy,persistence,allocator,cmd_pair,mode,round,qps,avg_us,elapsed_s\n" > "$DETAIL_CSV"
|
|
||||||
printf "target,strategy,persistence,allocator,cmd_pair,mode,round_qps,round_avg_us,round_elapsed_s,avg_qps,avg_avg_us,avg_elapsed_s\n" > "$SUMMARY_CSV"
|
|
||||||
|
|
||||||
require_cmd() {
|
|
||||||
local cmd="$1"
|
|
||||||
if ! command -v "$cmd" >/dev/null 2>&1; then
|
|
||||||
echo "missing required command: $cmd" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_binaries() {
|
|
||||||
if [[ ! -x "$ROOT_DIR/kvstore" || ! -x "$ROOT_DIR/test-redis/bench" ]]; then
|
|
||||||
echo "[info] kvstore/bench missing, running make -j4 ..."
|
|
||||||
make -j4
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
set_config() {
|
|
||||||
local ptype="$1"
|
|
||||||
local alloc="$2"
|
|
||||||
local pdir="$3"
|
|
||||||
local oplog_sync="$4"
|
|
||||||
python3 - "$CONFIG_XML" "$ptype" "$alloc" "$pdir" "$KV_PORT" "$oplog_sync" <<'PY'
|
|
||||||
import sys
|
|
||||||
import xml.etree.ElementTree as ET
|
|
||||||
|
|
||||||
path, ptype, alloc, pdir, kv_port, oplog_sync = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6]
|
|
||||||
tree = ET.parse(path)
|
|
||||||
root = tree.getroot()
|
|
||||||
|
|
||||||
server = root.find("server")
|
|
||||||
if server is not None:
|
|
||||||
ip = server.find("ip")
|
|
||||||
port = server.find("port")
|
|
||||||
mode = server.find("mode")
|
|
||||||
replica = server.find("replica")
|
|
||||||
if ip is not None:
|
|
||||||
ip.text = "127.0.0.1"
|
|
||||||
if port is not None:
|
|
||||||
port.text = kv_port
|
|
||||||
if mode is not None:
|
|
||||||
mode.text = "master"
|
|
||||||
if replica is not None:
|
|
||||||
replica.text = "disable"
|
|
||||||
|
|
||||||
persistence = root.find("persistence")
|
|
||||||
if persistence is not None:
|
|
||||||
t = persistence.find("type")
|
|
||||||
d = persistence.find("dir")
|
|
||||||
osync = persistence.find("oplog_sync")
|
|
||||||
if t is not None:
|
|
||||||
t.text = ptype
|
|
||||||
if d is not None:
|
|
||||||
d.text = pdir
|
|
||||||
if osync is not None:
|
|
||||||
osync.text = oplog_sync
|
|
||||||
|
|
||||||
memory = root.find("memory")
|
|
||||||
if memory is not None:
|
|
||||||
a = memory.find("allocator")
|
|
||||||
leak = memory.find("leakage")
|
|
||||||
if a is not None:
|
|
||||||
a.text = alloc
|
|
||||||
if leak is not None:
|
|
||||||
leak.text = "disable"
|
|
||||||
|
|
||||||
tree.write(path, encoding="UTF-8", xml_declaration=True)
|
|
||||||
PY
|
|
||||||
}
|
|
||||||
|
|
||||||
wait_port_open() {
|
|
||||||
local port="$1"
|
|
||||||
for _ in $(seq 1 200); do
|
|
||||||
if ss -ltn | rg -q ":${port}\\b"; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
sleep 0.1
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
wait_port_close() {
|
|
||||||
local port="$1"
|
|
||||||
for _ in $(seq 1 200); do
|
|
||||||
if ! ss -ltn | rg -q ":${port}\\b"; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
sleep 0.1
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_port_free() {
|
|
||||||
local port="$1"
|
|
||||||
local svc="$2"
|
|
||||||
if ss -ltn | rg -q ":${port}\\b"; then
|
|
||||||
echo "port ${port} is already in use, cannot start ${svc}" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
extract_metric() {
|
|
||||||
local line="$1"
|
|
||||||
local key="$2"
|
|
||||||
echo "$line" | sed -E "s/.*${key}=([0-9]+(\\.[0-9]+)?).*/\\1/"
|
|
||||||
}
|
|
||||||
|
|
||||||
float_add() {
|
|
||||||
awk -v a="$1" -v b="$2" 'BEGIN { printf "%.6f", a + b }'
|
|
||||||
}
|
|
||||||
|
|
||||||
float_div() {
|
|
||||||
awk -v a="$1" -v b="$2" 'BEGIN { if (b == 0) printf "0"; else printf "%.6f", a / b }'
|
|
||||||
}
|
|
||||||
|
|
||||||
join_pipe() {
|
|
||||||
local IFS='|'
|
|
||||||
echo "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
run_bench_capture() {
|
|
||||||
local host="$1"
|
|
||||||
local port="$2"
|
|
||||||
local mode="$3"
|
|
||||||
local set_cmd="$4"
|
|
||||||
local get_cmd="$5"
|
|
||||||
local key_prefix="$6"
|
|
||||||
local seed="$7"
|
|
||||||
local verify="$8"
|
|
||||||
local cmd=(
|
|
||||||
./test-redis/bench
|
|
||||||
--host "$host"
|
|
||||||
--port "$port"
|
|
||||||
--mode "$mode"
|
|
||||||
--set-cmd "$set_cmd"
|
|
||||||
--get-cmd "$get_cmd"
|
|
||||||
--requests "$REQ"
|
|
||||||
--pipeline "$PIPE"
|
|
||||||
--keyspace "$KEYSPACE"
|
|
||||||
--value-size "$VSIZE"
|
|
||||||
--seed "$seed"
|
|
||||||
--key-prefix "$key_prefix"
|
|
||||||
)
|
|
||||||
if [[ "$verify" == "1" ]]; then
|
|
||||||
cmd+=(--verify-get)
|
|
||||||
fi
|
|
||||||
|
|
||||||
local out
|
|
||||||
out=$("${cmd[@]}")
|
|
||||||
echo "$out" >&2
|
|
||||||
|
|
||||||
local line
|
|
||||||
line=$(echo "$out" | rg "\\[result\\]" | tail -n1)
|
|
||||||
if [[ -z "$line" ]]; then
|
|
||||||
echo "missing [result] line in benchmark output" >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
local qps avg elapsed
|
|
||||||
qps=$(extract_metric "$line" "qps")
|
|
||||||
avg=$(extract_metric "$line" "avg")
|
|
||||||
elapsed=$(extract_metric "$line" "elapsed")
|
|
||||||
if [[ -z "$qps" || -z "$avg" || -z "$elapsed" ]]; then
|
|
||||||
echo "failed to parse benchmark metrics: $line" >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
echo "$qps,$avg,$elapsed"
|
|
||||||
}
|
|
||||||
|
|
||||||
start_kv() {
|
|
||||||
local label="$1"
|
|
||||||
assert_port_free "$KV_PORT" "kvstore"
|
|
||||||
./kvstore >"$KV_LOG_DIR/${label}.log" 2>&1 &
|
|
||||||
KV_PID=$!
|
|
||||||
if ! wait_port_open "$KV_PORT"; then
|
|
||||||
echo "kvstore start failed for ${label}" >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_kv() {
|
|
||||||
if [[ -n "${KV_PID:-}" ]] && kill -0 "$KV_PID" >/dev/null 2>&1; then
|
|
||||||
kill "$KV_PID" >/dev/null 2>&1 || true
|
|
||||||
wait "$KV_PID" >/dev/null 2>&1 || true
|
|
||||||
fi
|
|
||||||
KV_PID=""
|
|
||||||
wait_port_close "$KV_PORT" || true
|
|
||||||
}
|
|
||||||
|
|
||||||
start_redis() {
|
|
||||||
local strategy="$1"
|
|
||||||
local round="$2"
|
|
||||||
local port="$3"
|
|
||||||
local save_rule="$4"
|
|
||||||
local appendonly="$5"
|
|
||||||
local appendfsync="$6"
|
|
||||||
local rdir="/tmp/redis_${strategy}_${TS}_r${round}"
|
|
||||||
local conf="$rdir/redis.conf"
|
|
||||||
|
|
||||||
rm -rf "$rdir"
|
|
||||||
mkdir -p "$rdir"
|
|
||||||
assert_port_free "$port" "redis(${strategy})"
|
|
||||||
|
|
||||||
cat > "$conf" <<EOF
|
|
||||||
bind 127.0.0.1
|
|
||||||
port $port
|
|
||||||
daemonize yes
|
|
||||||
pidfile $rdir/redis.pid
|
|
||||||
dir $rdir
|
|
||||||
dbfilename dump.rdb
|
|
||||||
appendfilename appendonly.aof
|
|
||||||
save $save_rule
|
|
||||||
appendonly $appendonly
|
|
||||||
appendfsync $appendfsync
|
|
||||||
logfile $rdir/redis.log
|
|
||||||
EOF
|
|
||||||
|
|
||||||
redis-server "$conf"
|
|
||||||
if ! wait_port_open "$port"; then
|
|
||||||
echo "redis start failed for ${strategy}, check $rdir/redis.log" >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_redis_port() {
|
|
||||||
local port="$1"
|
|
||||||
if ss -ltn | rg -q ":${port}\\b"; then
|
|
||||||
redis-cli -h "$REDIS_HOST" -p "$port" shutdown nosave >/dev/null 2>&1 || true
|
|
||||||
wait_port_close "$port" || true
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup() {
|
|
||||||
stop_kv
|
|
||||||
for port in "${REDIS_PORTS[@]}"; do
|
|
||||||
stop_redis_port "$port"
|
|
||||||
done
|
|
||||||
if [[ -f "$ORIG_CONFIG_BACKUP" ]]; then
|
|
||||||
cp "$ORIG_CONFIG_BACKUP" "$CONFIG_XML"
|
|
||||||
rm -f "$ORIG_CONFIG_BACKUP"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
trap cleanup EXIT
|
|
||||||
|
|
||||||
run_kv_case() {
|
|
||||||
local strategy="$1"
|
|
||||||
local persistence="$2"
|
|
||||||
local alloc="$3"
|
|
||||||
local oplog_sync="$4"
|
|
||||||
|
|
||||||
local -a set_qps_list=() set_avg_list=() set_elapsed_list=()
|
|
||||||
local -a get_qps_list=() get_avg_list=() get_elapsed_list=()
|
|
||||||
local set_qps_sum="0" set_avg_sum="0" set_elapsed_sum="0"
|
|
||||||
local get_qps_sum="0" get_avg_sum="0" get_elapsed_sum="0"
|
|
||||||
|
|
||||||
for round in $(seq 1 "$ROUNDS"); do
|
|
||||||
local pdir_rel="data/${strategy}_${TS}_r${round}"
|
|
||||||
local pdir_abs="$ROOT_DIR/${pdir_rel}"
|
|
||||||
rm -rf "$pdir_abs"
|
|
||||||
mkdir -p "$pdir_abs"
|
|
||||||
|
|
||||||
set_config "$persistence" "$alloc" "$pdir_rel" "$oplog_sync"
|
|
||||||
start_kv "${strategy}_r${round}"
|
|
||||||
|
|
||||||
local m qps avg elapsed
|
|
||||||
m=$(run_bench_capture "$KV_HOST" "$KV_PORT" "set" "RSET" "RGET" "bench:${TS}:kv:${strategy}:r${round}:set:" "$((SEED + round * 10 + 1))" 0)
|
|
||||||
IFS=',' read -r qps avg elapsed <<< "$m"
|
|
||||||
printf "kvstore,%s,%s,%s,RSET/RGET,set,%s,%s,%s,%s\n" "$strategy" "$persistence" "$alloc" "$round" "$qps" "$avg" "$elapsed" >> "$DETAIL_CSV"
|
|
||||||
set_qps_list+=("$qps")
|
|
||||||
set_avg_list+=("$avg")
|
|
||||||
set_elapsed_list+=("$elapsed")
|
|
||||||
set_qps_sum=$(float_add "$set_qps_sum" "$qps")
|
|
||||||
set_avg_sum=$(float_add "$set_avg_sum" "$avg")
|
|
||||||
set_elapsed_sum=$(float_add "$set_elapsed_sum" "$elapsed")
|
|
||||||
|
|
||||||
m=$(run_bench_capture "$KV_HOST" "$KV_PORT" "get" "RSET" "RGET" "bench:${TS}:kv:${strategy}:r${round}:get:" "$((SEED + round * 10 + 2))" 1)
|
|
||||||
IFS=',' read -r qps avg elapsed <<< "$m"
|
|
||||||
printf "kvstore,%s,%s,%s,RSET/RGET,get,%s,%s,%s,%s\n" "$strategy" "$persistence" "$alloc" "$round" "$qps" "$avg" "$elapsed" >> "$DETAIL_CSV"
|
|
||||||
get_qps_list+=("$qps")
|
|
||||||
get_avg_list+=("$avg")
|
|
||||||
get_elapsed_list+=("$elapsed")
|
|
||||||
get_qps_sum=$(float_add "$get_qps_sum" "$qps")
|
|
||||||
get_avg_sum=$(float_add "$get_avg_sum" "$avg")
|
|
||||||
get_elapsed_sum=$(float_add "$get_elapsed_sum" "$elapsed")
|
|
||||||
|
|
||||||
stop_kv
|
|
||||||
done
|
|
||||||
|
|
||||||
local set_avg_qps set_avg_avg set_avg_elapsed
|
|
||||||
local get_avg_qps get_avg_avg get_avg_elapsed
|
|
||||||
set_avg_qps=$(float_div "$set_qps_sum" "$ROUNDS")
|
|
||||||
set_avg_avg=$(float_div "$set_avg_sum" "$ROUNDS")
|
|
||||||
set_avg_elapsed=$(float_div "$set_elapsed_sum" "$ROUNDS")
|
|
||||||
get_avg_qps=$(float_div "$get_qps_sum" "$ROUNDS")
|
|
||||||
get_avg_avg=$(float_div "$get_avg_sum" "$ROUNDS")
|
|
||||||
get_avg_elapsed=$(float_div "$get_elapsed_sum" "$ROUNDS")
|
|
||||||
|
|
||||||
printf "kvstore,%s,%s,%s,RSET/RGET,set,avg,%s,%s,%s\n" "$strategy" "$persistence" "$alloc" "$set_avg_qps" "$set_avg_avg" "$set_avg_elapsed" >> "$DETAIL_CSV"
|
|
||||||
printf "kvstore,%s,%s,%s,RSET/RGET,get,avg,%s,%s,%s\n" "$strategy" "$persistence" "$alloc" "$get_avg_qps" "$get_avg_avg" "$get_avg_elapsed" >> "$DETAIL_CSV"
|
|
||||||
|
|
||||||
printf "kvstore,%s,%s,%s,RSET/RGET,set,%s,%s,%s,%s,%s,%s\n" \
|
|
||||||
"$strategy" "$persistence" "$alloc" \
|
|
||||||
"$(join_pipe "${set_qps_list[@]}")" \
|
|
||||||
"$(join_pipe "${set_avg_list[@]}")" \
|
|
||||||
"$(join_pipe "${set_elapsed_list[@]}")" \
|
|
||||||
"$set_avg_qps" "$set_avg_avg" "$set_avg_elapsed" >> "$SUMMARY_CSV"
|
|
||||||
printf "kvstore,%s,%s,%s,RSET/RGET,get,%s,%s,%s,%s,%s,%s\n" \
|
|
||||||
"$strategy" "$persistence" "$alloc" \
|
|
||||||
"$(join_pipe "${get_qps_list[@]}")" \
|
|
||||||
"$(join_pipe "${get_avg_list[@]}")" \
|
|
||||||
"$(join_pipe "${get_elapsed_list[@]}")" \
|
|
||||||
"$get_avg_qps" "$get_avg_avg" "$get_avg_elapsed" >> "$SUMMARY_CSV"
|
|
||||||
}
|
|
||||||
|
|
||||||
run_redis_case() {
|
|
||||||
local strategy="$1"
|
|
||||||
local persistence="$2"
|
|
||||||
local port="$3"
|
|
||||||
local save_rule="$4"
|
|
||||||
local appendonly="$5"
|
|
||||||
local appendfsync="$6"
|
|
||||||
|
|
||||||
local -a set_qps_list=() set_avg_list=() set_elapsed_list=()
|
|
||||||
local -a get_qps_list=() get_avg_list=() get_elapsed_list=()
|
|
||||||
local set_qps_sum="0" set_avg_sum="0" set_elapsed_sum="0"
|
|
||||||
local get_qps_sum="0" get_avg_sum="0" get_elapsed_sum="0"
|
|
||||||
|
|
||||||
for round in $(seq 1 "$ROUNDS"); do
|
|
||||||
start_redis "$strategy" "$round" "$port" "$save_rule" "$appendonly" "$appendfsync"
|
|
||||||
|
|
||||||
local m qps avg elapsed
|
|
||||||
m=$(run_bench_capture "$REDIS_HOST" "$port" "set" "SET" "GET" "bench:${TS}:redis:${strategy}:r${round}:set:" "$((SEED + round * 100 + 1))" 0)
|
|
||||||
IFS=',' read -r qps avg elapsed <<< "$m"
|
|
||||||
printf "redis,%s,%s,-,SET/GET,set,%s,%s,%s,%s\n" "$strategy" "$persistence" "$round" "$qps" "$avg" "$elapsed" >> "$DETAIL_CSV"
|
|
||||||
set_qps_list+=("$qps")
|
|
||||||
set_avg_list+=("$avg")
|
|
||||||
set_elapsed_list+=("$elapsed")
|
|
||||||
set_qps_sum=$(float_add "$set_qps_sum" "$qps")
|
|
||||||
set_avg_sum=$(float_add "$set_avg_sum" "$avg")
|
|
||||||
set_elapsed_sum=$(float_add "$set_elapsed_sum" "$elapsed")
|
|
||||||
|
|
||||||
m=$(run_bench_capture "$REDIS_HOST" "$port" "get" "SET" "GET" "bench:${TS}:redis:${strategy}:r${round}:get:" "$((SEED + round * 100 + 2))" 1)
|
|
||||||
IFS=',' read -r qps avg elapsed <<< "$m"
|
|
||||||
printf "redis,%s,%s,-,SET/GET,get,%s,%s,%s,%s\n" "$strategy" "$persistence" "$round" "$qps" "$avg" "$elapsed" >> "$DETAIL_CSV"
|
|
||||||
get_qps_list+=("$qps")
|
|
||||||
get_avg_list+=("$avg")
|
|
||||||
get_elapsed_list+=("$elapsed")
|
|
||||||
get_qps_sum=$(float_add "$get_qps_sum" "$qps")
|
|
||||||
get_avg_sum=$(float_add "$get_avg_sum" "$avg")
|
|
||||||
get_elapsed_sum=$(float_add "$get_elapsed_sum" "$elapsed")
|
|
||||||
|
|
||||||
stop_redis_port "$port"
|
|
||||||
done
|
|
||||||
|
|
||||||
local set_avg_qps set_avg_avg set_avg_elapsed
|
|
||||||
local get_avg_qps get_avg_avg get_avg_elapsed
|
|
||||||
set_avg_qps=$(float_div "$set_qps_sum" "$ROUNDS")
|
|
||||||
set_avg_avg=$(float_div "$set_avg_sum" "$ROUNDS")
|
|
||||||
set_avg_elapsed=$(float_div "$set_elapsed_sum" "$ROUNDS")
|
|
||||||
get_avg_qps=$(float_div "$get_qps_sum" "$ROUNDS")
|
|
||||||
get_avg_avg=$(float_div "$get_avg_sum" "$ROUNDS")
|
|
||||||
get_avg_elapsed=$(float_div "$get_elapsed_sum" "$ROUNDS")
|
|
||||||
|
|
||||||
printf "redis,%s,%s,-,SET/GET,set,avg,%s,%s,%s\n" "$strategy" "$persistence" "$set_avg_qps" "$set_avg_avg" "$set_avg_elapsed" >> "$DETAIL_CSV"
|
|
||||||
printf "redis,%s,%s,-,SET/GET,get,avg,%s,%s,%s\n" "$strategy" "$persistence" "$get_avg_qps" "$get_avg_avg" "$get_avg_elapsed" >> "$DETAIL_CSV"
|
|
||||||
|
|
||||||
printf "redis,%s,%s,-,SET/GET,set,%s,%s,%s,%s,%s,%s\n" \
|
|
||||||
"$strategy" "$persistence" \
|
|
||||||
"$(join_pipe "${set_qps_list[@]}")" \
|
|
||||||
"$(join_pipe "${set_avg_list[@]}")" \
|
|
||||||
"$(join_pipe "${set_elapsed_list[@]}")" \
|
|
||||||
"$set_avg_qps" "$set_avg_avg" "$set_avg_elapsed" >> "$SUMMARY_CSV"
|
|
||||||
printf "redis,%s,%s,-,SET/GET,get,%s,%s,%s,%s,%s,%s\n" \
|
|
||||||
"$strategy" "$persistence" \
|
|
||||||
"$(join_pipe "${get_qps_list[@]}")" \
|
|
||||||
"$(join_pipe "${get_avg_list[@]}")" \
|
|
||||||
"$(join_pipe "${get_elapsed_list[@]}")" \
|
|
||||||
"$get_avg_qps" "$get_avg_avg" "$get_avg_elapsed" >> "$SUMMARY_CSV"
|
|
||||||
}
|
|
||||||
|
|
||||||
append_readme_results() {
|
|
||||||
python3 - "$SUMMARY_CSV" "$README_MD" "$RUN_TIME" "$ROUNDS" "$REQ" "$PIPE" "$KEYSPACE" "$VSIZE" "$DETAIL_CSV" "$SUMMARY_CSV" <<'PY'
|
|
||||||
import csv
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
summary_csv, readme_path, run_time, rounds, req, pipeline, keyspace, value_size, detail_csv, summary_path = sys.argv[1:]
|
|
||||||
rounds_i = int(rounds)
|
|
||||||
|
|
||||||
def split_rounds(v):
|
|
||||||
if not v:
|
|
||||||
return []
|
|
||||||
return v.split("|")
|
|
||||||
|
|
||||||
def fmt(v):
|
|
||||||
try:
|
|
||||||
return f"{float(v):.2f}"
|
|
||||||
except Exception:
|
|
||||||
return v
|
|
||||||
|
|
||||||
rows = []
|
|
||||||
with open(summary_csv, newline="", encoding="utf-8") as f:
|
|
||||||
rows = list(csv.DictReader(f))
|
|
||||||
|
|
||||||
kv_rows = [r for r in rows if r["target"] == "kvstore"]
|
|
||||||
redis_rows = [r for r in rows if r["target"] == "redis"]
|
|
||||||
|
|
||||||
lines = []
|
|
||||||
lines.append("")
|
|
||||||
lines.append(f"## run_hash_bench.sh 三轮均值复测({run_time})")
|
|
||||||
lines.append("")
|
|
||||||
lines.append(f"- 轮次:{rounds_i} 轮(取均值)")
|
|
||||||
lines.append(f"- 参数:requests={req} pipeline={pipeline} keyspace={keyspace} value-size={value_size}")
|
|
||||||
lines.append(f"- 明细数据:`{os.path.relpath(detail_csv, os.path.dirname(readme_path))}`")
|
|
||||||
lines.append(f"- 汇总数据:`{os.path.relpath(summary_path, os.path.dirname(readme_path))}`")
|
|
||||||
lines.append("")
|
|
||||||
|
|
||||||
round_headers = [f"Round{i}" for i in range(1, rounds_i + 1)]
|
|
||||||
|
|
||||||
def render_table(title, items, scene_fn):
|
|
||||||
lines.append(f"### {title}")
|
|
||||||
lines.append("")
|
|
||||||
header = "| 场景 | 模式 | " + " | ".join(round_headers) + " | 均值QPS | 均值avg(us/op) | 均值elapsed(s) |"
|
|
||||||
sep = "|---|---:|" + "|".join(["---:"] * len(round_headers)) + "|---:|---:|---:|"
|
|
||||||
lines.append(header)
|
|
||||||
lines.append(sep)
|
|
||||||
for row in items:
|
|
||||||
rounds_qps = split_rounds(row["round_qps"])
|
|
||||||
while len(rounds_qps) < rounds_i:
|
|
||||||
rounds_qps.append("-")
|
|
||||||
rounds_qps = rounds_qps[:rounds_i]
|
|
||||||
scene = scene_fn(row)
|
|
||||||
lines.append(
|
|
||||||
"| {} | {} | {} | {} | {} | {} |".format(
|
|
||||||
scene,
|
|
||||||
row["mode"],
|
|
||||||
" | ".join(rounds_qps),
|
|
||||||
fmt(row["avg_qps"]),
|
|
||||||
fmt(row["avg_avg_us"]),
|
|
||||||
fmt(row["avg_elapsed_s"]),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
lines.append("")
|
|
||||||
|
|
||||||
render_table(
|
|
||||||
"kvstore:RSET/RGET(持久化 × allocator)",
|
|
||||||
kv_rows,
|
|
||||||
lambda r: f"{r['strategy']} ({r['persistence']}, {r['allocator']})",
|
|
||||||
)
|
|
||||||
render_table(
|
|
||||||
"Redis:SET/GET(各持久化模式)",
|
|
||||||
redis_rows,
|
|
||||||
lambda r: f"{r['strategy']} ({r['persistence']})",
|
|
||||||
)
|
|
||||||
|
|
||||||
with open(readme_path, "a", encoding="utf-8") as f:
|
|
||||||
f.write("\n".join(lines) + "\n")
|
|
||||||
PY
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
require_cmd python3
|
|
||||||
require_cmd rg
|
|
||||||
require_cmd ss
|
|
||||||
require_cmd redis-server
|
|
||||||
require_cmd redis-cli
|
|
||||||
ensure_binaries
|
|
||||||
|
|
||||||
run_kv_case "persist_mypool" "incremental" "mypool" "none"
|
|
||||||
run_kv_case "everysec_mypool" "incremental" "mypool" "every_sec"
|
|
||||||
run_kv_case "nopersist_mypool" "none" "mypool" "none"
|
|
||||||
run_kv_case "persist_malloc" "incremental" "malloc" "none"
|
|
||||||
run_kv_case "everysec_malloc" "incremental" "malloc" "every_sec"
|
|
||||||
run_kv_case "nopersist_malloc" "none" "malloc" "none"
|
|
||||||
|
|
||||||
run_redis_case "none" "none" 6381 "\"\"" "no" "everysec"
|
|
||||||
run_redis_case "rdb_default" "rdb_default" 6382 "900 1 300 10 60 10000" "no" "everysec"
|
|
||||||
run_redis_case "aof_no" "aof_no" 6383 "\"\"" "yes" "no"
|
|
||||||
run_redis_case "aof_everysec" "aof_everysec" 6384 "\"\"" "yes" "everysec"
|
|
||||||
run_redis_case "aof_always" "aof_always" 6385 "\"\"" "yes" "always"
|
|
||||||
|
|
||||||
append_readme_results
|
|
||||||
|
|
||||||
echo "DETAIL_CSV=$DETAIL_CSV"
|
|
||||||
echo "SUMMARY_CSV=$SUMMARY_CSV"
|
|
||||||
echo "README_UPDATED=$README_MD"
|
|
||||||
}
|
|
||||||
|
|
||||||
main "$@"
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
TS=$(date +%Y%m%d_%H%M%S)
|
|
||||||
CSV="test-redis/results/kv_overwrite5_${TS}.csv"
|
|
||||||
SUMMARY="test-redis/results/kv_overwrite5_summary_${TS}.csv"
|
|
||||||
BACKUP=$(mktemp /tmp/config.xml.bak.${TS}.XXXXXX)
|
|
||||||
cp config/config.xml "$BACKUP"
|
|
||||||
|
|
||||||
cleanup() {
|
|
||||||
cp "$BACKUP" config/config.xml || true
|
|
||||||
rm -f "$BACKUP" || true
|
|
||||||
pkill -x kvstore >/dev/null 2>&1 || true
|
|
||||||
}
|
|
||||||
trap cleanup EXIT
|
|
||||||
|
|
||||||
pkill -x kvstore >/dev/null 2>&1 || true
|
|
||||||
mkdir -p test-redis/results
|
|
||||||
rm -rf data/*
|
|
||||||
|
|
||||||
echo "case,mode,round,qps,avg_us,requests,keyspace,value_size,pipeline" > "$CSV"
|
|
||||||
|
|
||||||
auto_set_cfg() {
|
|
||||||
local ptype="$1" alloc="$2" syncm="$3" pdir="$4"
|
|
||||||
python3 - "$ptype" "$alloc" "$syncm" "$pdir" <<'PY'
|
|
||||||
import sys
|
|
||||||
import xml.etree.ElementTree as ET
|
|
||||||
|
|
||||||
ptype, alloc, syncm, pdir = sys.argv[1:]
|
|
||||||
path = "config/config.xml"
|
|
||||||
tree = ET.parse(path)
|
|
||||||
root = tree.getroot()
|
|
||||||
|
|
||||||
server = root.find("server")
|
|
||||||
if server is not None:
|
|
||||||
ip = server.find("ip")
|
|
||||||
port = server.find("port")
|
|
||||||
mode = server.find("mode")
|
|
||||||
replica = server.find("replica")
|
|
||||||
if ip is not None:
|
|
||||||
ip.text = "127.0.0.1"
|
|
||||||
if port is not None:
|
|
||||||
port.text = "8888"
|
|
||||||
if mode is not None:
|
|
||||||
mode.text = "master"
|
|
||||||
if replica is not None:
|
|
||||||
replica.text = "disable"
|
|
||||||
|
|
||||||
persist = root.find("persistence")
|
|
||||||
if persist is not None:
|
|
||||||
ptype_node = persist.find("type")
|
|
||||||
dir_node = persist.find("dir")
|
|
||||||
sync_node = persist.find("oplog_sync")
|
|
||||||
if ptype_node is not None:
|
|
||||||
ptype_node.text = ptype
|
|
||||||
if dir_node is not None:
|
|
||||||
dir_node.text = pdir
|
|
||||||
if sync_node is not None:
|
|
||||||
sync_node.text = syncm
|
|
||||||
|
|
||||||
memory = root.find("memory")
|
|
||||||
if memory is not None:
|
|
||||||
alloc_node = memory.find("allocator")
|
|
||||||
leak_node = memory.find("leakage")
|
|
||||||
if alloc_node is not None:
|
|
||||||
alloc_node.text = alloc
|
|
||||||
if leak_node is not None:
|
|
||||||
leak_node.text = "disable"
|
|
||||||
|
|
||||||
tree.write(path, encoding="UTF-8", xml_declaration=True)
|
|
||||||
PY
|
|
||||||
}
|
|
||||||
|
|
||||||
wait_port_open() {
|
|
||||||
for _ in $(seq 1 200); do
|
|
||||||
if ss -ltn | rg -q ":8888\\b"; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
sleep 0.1
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
extract_qps() {
|
|
||||||
local line="$1"
|
|
||||||
echo "$line" | sed -E "s/.*qps=([0-9]+).*/\\1/"
|
|
||||||
}
|
|
||||||
|
|
||||||
extract_avg() {
|
|
||||||
local line="$1"
|
|
||||||
echo "$line" | sed -E "s/.*avg=([0-9]+(\\.[0-9]+)?).*/\\1/"
|
|
||||||
}
|
|
||||||
|
|
||||||
run_case() {
|
|
||||||
local cname="$1" ptype="$2" alloc="$3" syncm="$4"
|
|
||||||
local REQ=2000000 KEYSPACE=1000000 VSIZE=64 PIPE=128
|
|
||||||
|
|
||||||
for r in 1 2 3 4 5; do
|
|
||||||
local pdir="data/ovw_${cname}_r${r}_${TS}"
|
|
||||||
local line qps avg out kp
|
|
||||||
|
|
||||||
rm -rf "$pdir"
|
|
||||||
mkdir -p "$pdir"
|
|
||||||
auto_set_cfg "$ptype" "$alloc" "$syncm" "$pdir"
|
|
||||||
|
|
||||||
./kvstore > "/tmp/kv_${cname}_r${r}_${TS}.log" 2>&1 &
|
|
||||||
local kvpid=$!
|
|
||||||
wait_port_open
|
|
||||||
|
|
||||||
kp="bench:ovw:long-key-prefix-abcdefghijklmnopqrstuvwxyz-0123456789:${cname}:r${r}:set:"
|
|
||||||
out=$(./test-redis/bench \
|
|
||||||
--host 127.0.0.1 --port 8888 --mode set \
|
|
||||||
--set-cmd RSET --get-cmd RGET \
|
|
||||||
--requests "$REQ" --pipeline "$PIPE" --keyspace "$KEYSPACE" \
|
|
||||||
--value-size "$VSIZE" --seed $((13000 + r * 31)) \
|
|
||||||
--key-prefix "$kp")
|
|
||||||
echo "$out"
|
|
||||||
line=$(echo "$out" | rg "\\[result\\]" | tail -n1)
|
|
||||||
qps=$(extract_qps "$line")
|
|
||||||
avg=$(extract_avg "$line")
|
|
||||||
echo "${cname},set,${r},${qps},${avg},${REQ},${KEYSPACE},${VSIZE},${PIPE}" >> "$CSV"
|
|
||||||
|
|
||||||
kp="bench:ovw:long-key-prefix-abcdefghijklmnopqrstuvwxyz-0123456789:${cname}:r${r}:get:"
|
|
||||||
out=$(./test-redis/bench \
|
|
||||||
--host 127.0.0.1 --port 8888 --mode get \
|
|
||||||
--set-cmd RSET --get-cmd RGET \
|
|
||||||
--requests "$REQ" --pipeline "$PIPE" --keyspace "$KEYSPACE" \
|
|
||||||
--value-size "$VSIZE" --seed $((23000 + r * 31)) --verify-get \
|
|
||||||
--key-prefix "$kp")
|
|
||||||
echo "$out"
|
|
||||||
line=$(echo "$out" | rg "\\[result\\]" | tail -n1)
|
|
||||||
qps=$(extract_qps "$line")
|
|
||||||
avg=$(extract_avg "$line")
|
|
||||||
echo "${cname},get,${r},${qps},${avg},${REQ},${KEYSPACE},${VSIZE},${PIPE}" >> "$CSV"
|
|
||||||
|
|
||||||
kill "$kvpid" >/dev/null 2>&1 || true
|
|
||||||
wait "$kvpid" >/dev/null 2>&1 || true
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
run_case nopersist_mypool none mypool none
|
|
||||||
run_case persist_mypool incremental mypool none
|
|
||||||
run_case everysec_mypool incremental mypool every_sec
|
|
||||||
run_case nopersist_malloc none malloc none
|
|
||||||
run_case persist_malloc incremental malloc none
|
|
||||||
run_case everysec_malloc incremental malloc every_sec
|
|
||||||
|
|
||||||
{
|
|
||||||
echo "case,mode,avg_qps,avg_avg_us"
|
|
||||||
awk -F, 'NR>1{ k=$1","$2; q[k]+=$4; u[k]+=$5; n[k]++ } END{ for(k in n) printf "%s,%.2f,%.2f\n", k, q[k]/n[k], u[k]/n[k] }' "$CSV" | sort
|
|
||||||
} > "$SUMMARY"
|
|
||||||
|
|
||||||
echo "RAW_CSV=$CSV"
|
|
||||||
echo "SUMMARY_CSV=$SUMMARY"
|
|
||||||
cat "$SUMMARY"
|
|
||||||
Reference in New Issue
Block a user