resp-benchmark 0.2.0__pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of resp-benchmark might be problematic. Click here for more details.
- resp_benchmark/__init__.py +3 -0
- resp_benchmark/_resp_benchmark_rust_lib.pypy311-pp73-aarch64-linux-gnu.so +0 -0
- resp_benchmark/cli.py +44 -0
- resp_benchmark/cores.py +24 -0
- resp_benchmark/wrapper.py +158 -0
- resp_benchmark-0.2.0.dist-info/METADATA +386 -0
- resp_benchmark-0.2.0.dist-info/RECORD +10 -0
- resp_benchmark-0.2.0.dist-info/WHEEL +4 -0
- resp_benchmark-0.2.0.dist-info/entry_points.txt +2 -0
- resp_benchmark-0.2.0.dist-info/licenses/LICENSE +21 -0
resp_benchmark/cli.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
from importlib.metadata import version
|
|
3
|
+
|
|
4
|
+
from resp_benchmark.wrapper import Benchmark
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def parse_args():
|
|
8
|
+
parser = argparse.ArgumentParser(
|
|
9
|
+
description="RESP Benchmark Tool",
|
|
10
|
+
add_help=False,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
parser.add_argument("-h", metavar="host", default="127.0.0.1", help="Server hostname (default 127.0.0.1)")
|
|
14
|
+
parser.add_argument("-p", metavar="port", type=int, default=6379, help="Server port (default 6379)")
|
|
15
|
+
parser.add_argument("-u", metavar="username", type=str, default="", help="Used to send ACL style \"AUTH username pass\". Needs -a.")
|
|
16
|
+
parser.add_argument("-a", metavar="password", type=str, default="", help="Password for Redis Auth")
|
|
17
|
+
parser.add_argument("-c", metavar="clients", type=int, default=0, help="Number of parallel connections (0 for auto, default: 0)")
|
|
18
|
+
parser.add_argument("--cores", type=str, default=f"", help="Comma-separated list of CPU cores to use (default all)")
|
|
19
|
+
parser.add_argument("--cluster", action="store_true", help="Use cluster mode (default false)")
|
|
20
|
+
parser.add_argument("-n", metavar="requests", type=int, default=0, help="Total number of requests (default 0), 0 for unlimited.")
|
|
21
|
+
parser.add_argument("-t", metavar="target", type=int, default=0, help="Target number of requests per second, 0 for unlimited, recommended to be multiple of 100.")
|
|
22
|
+
parser.add_argument("-s", metavar="seconds", type=int, default=0, help="Total time in seconds (default 0), 0 for unlimited.")
|
|
23
|
+
parser.add_argument("-P", metavar="pipeline", type=int, default=1, help="Pipeline <numreq> requests. Default 1 (no pipeline).")
|
|
24
|
+
# parser.add_argument("--tls", action="store_true", help="Use TLS for connection (default false)")
|
|
25
|
+
parser.add_argument("--load", action="store_true", help="Only load data to Redis, no benchmark.")
|
|
26
|
+
parser.add_argument('-v', '--version', action='version', version=version('resp_benchmark'))
|
|
27
|
+
parser.add_argument("--help", action="help", help="Output this help and exit.")
|
|
28
|
+
parser.add_argument("command", type=str, default="SET {key uniform 100000} {value 64}", nargs="?", help="The Redis command to benchmark (default SET {key uniform 100000} {value 64})")
|
|
29
|
+
|
|
30
|
+
args = parser.parse_args()
|
|
31
|
+
return args
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def main():
|
|
35
|
+
args = parse_args()
|
|
36
|
+
bm = Benchmark(host=args.h, port=args.p, username=args.u, password=args.a, cluster=args.cluster, cores=args.cores, timeout=30)
|
|
37
|
+
if args.load:
|
|
38
|
+
bm.load_data(command=args.command, connections=args.c, pipeline=args.P, count=args.n, target=args.t)
|
|
39
|
+
else:
|
|
40
|
+
bm.bench(command=args.command, connections=args.c, pipeline=args.P, count=args.n, target=args.t, seconds=args.s)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == "__main__":
|
|
44
|
+
main()
|
resp_benchmark/cores.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from itertools import chain
|
|
3
|
+
from typing import List
|
|
4
|
+
import multiprocessing
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def parse_range_list(rl):
|
|
8
|
+
def parse_range(r):
|
|
9
|
+
if len(r) == 0:
|
|
10
|
+
return []
|
|
11
|
+
parts = r.split("-")
|
|
12
|
+
if len(parts) > 2:
|
|
13
|
+
raise ValueError("Invalid range: {}".format(r))
|
|
14
|
+
return range(int(parts[0]), int(parts[-1]) + 1)
|
|
15
|
+
|
|
16
|
+
return sorted(set(chain.from_iterable(map(parse_range, rl.split(",")))))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def parse_cores_string(cores) -> List[int]:
|
|
20
|
+
try:
|
|
21
|
+
return parse_range_list(cores)
|
|
22
|
+
except ValueError:
|
|
23
|
+
print(f"Invalid cores range: {cores}.")
|
|
24
|
+
sys.exit(1)
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import multiprocessing
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
import pydantic
|
|
6
|
+
import redis
|
|
7
|
+
|
|
8
|
+
from .cores import parse_cores_string
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class Result:
|
|
13
|
+
"""
|
|
14
|
+
Represents the overall result of a benchmark.
|
|
15
|
+
|
|
16
|
+
Attributes:
|
|
17
|
+
qps (float): Average queries per second.
|
|
18
|
+
avg_latency_ms (float): Average latency in milliseconds.
|
|
19
|
+
p99_latency_ms (float): 99th percentile latency in milliseconds.
|
|
20
|
+
connections (int): The number of parallel connections.
|
|
21
|
+
"""
|
|
22
|
+
qps: float
|
|
23
|
+
avg_latency_ms: float
|
|
24
|
+
p99_latency_ms: float
|
|
25
|
+
connections: int
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Benchmark:
|
|
29
|
+
"""
|
|
30
|
+
A class to perform and manage benchmark tests on a Redis server.
|
|
31
|
+
|
|
32
|
+
Attributes:
|
|
33
|
+
host (str): The host address of the Redis server.
|
|
34
|
+
port (int): The port number of the Redis server.
|
|
35
|
+
username (str): The username for authentication.
|
|
36
|
+
password (str): The password for authentication.
|
|
37
|
+
cluster (bool): Whether to connect to a Redis cluster.
|
|
38
|
+
tls (bool): Whether to use TLS for the connection.
|
|
39
|
+
timeout (int): Timeout for the connection in seconds.
|
|
40
|
+
cores (str): Comma-separated list of CPU cores to use.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
@pydantic.validate_call
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
host: str = "127.0.0.1",
|
|
47
|
+
port: int = 6379,
|
|
48
|
+
username: str = "",
|
|
49
|
+
password: str = "",
|
|
50
|
+
cluster: bool = False,
|
|
51
|
+
# tls: bool = False,
|
|
52
|
+
timeout: int = 30,
|
|
53
|
+
cores: str = "",
|
|
54
|
+
):
|
|
55
|
+
self.host = host
|
|
56
|
+
self.port = port
|
|
57
|
+
self.username = username
|
|
58
|
+
self.password = password
|
|
59
|
+
self.cluster = cluster
|
|
60
|
+
# self.tls = tls
|
|
61
|
+
self.timeout = timeout
|
|
62
|
+
if cores == "":
|
|
63
|
+
cores = f"0-{multiprocessing.cpu_count() - 1}"
|
|
64
|
+
self.cores = parse_cores_string(cores)
|
|
65
|
+
|
|
66
|
+
def bench(
|
|
67
|
+
self,
|
|
68
|
+
command: str,
|
|
69
|
+
connections: int = 0,
|
|
70
|
+
pipeline: int = 1,
|
|
71
|
+
count: int = 0,
|
|
72
|
+
target: int = 0,
|
|
73
|
+
seconds: int = 0,
|
|
74
|
+
quiet: bool = False,
|
|
75
|
+
) -> Result:
|
|
76
|
+
"""
|
|
77
|
+
Runs a benchmark test with the specified parameters.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
command (str): The Redis command to benchmark.
|
|
81
|
+
connections (int): The number of parallel connections.
|
|
82
|
+
pipeline (int): The number of commands to pipeline.
|
|
83
|
+
count (int): The total number of requests to make.
|
|
84
|
+
target(int): The number of requests to send per second.
|
|
85
|
+
seconds (int): The duration of the test in seconds.
|
|
86
|
+
quiet: (bool): Whether to suppress output.
|
|
87
|
+
Returns:
|
|
88
|
+
Result: The results of the benchmark test.
|
|
89
|
+
"""
|
|
90
|
+
from . import _resp_benchmark_rust_lib
|
|
91
|
+
ret = _resp_benchmark_rust_lib.benchmark(
|
|
92
|
+
host=self.host,
|
|
93
|
+
port=self.port,
|
|
94
|
+
username=self.username,
|
|
95
|
+
password=self.password,
|
|
96
|
+
cluster=self.cluster,
|
|
97
|
+
tls=False, # TODO: Implement TLS support
|
|
98
|
+
timeout=self.timeout,
|
|
99
|
+
cores=self.cores,
|
|
100
|
+
|
|
101
|
+
command=command,
|
|
102
|
+
connections=connections,
|
|
103
|
+
pipeline=pipeline,
|
|
104
|
+
count=count,
|
|
105
|
+
target=target,
|
|
106
|
+
seconds=seconds,
|
|
107
|
+
load=False,
|
|
108
|
+
quiet=quiet,
|
|
109
|
+
)
|
|
110
|
+
result = Result(
|
|
111
|
+
qps=ret.qps,
|
|
112
|
+
avg_latency_ms=ret.avg_latency_ms,
|
|
113
|
+
p99_latency_ms=ret.p99_latency_ms,
|
|
114
|
+
connections=ret.connections
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
return result
|
|
118
|
+
|
|
119
|
+
def load_data(self, command: str, count: int, target: int = 0, connections: int = 128, pipeline: int = 10, quiet: bool = False):
|
|
120
|
+
"""
|
|
121
|
+
Load data into the Redis server using the specified command.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
command (str): The Redis command to use for loading data.
|
|
125
|
+
count (int): The total number of requests to make.
|
|
126
|
+
target(int): The number of requests to send per second.
|
|
127
|
+
connections (int): The number of parallel connections.
|
|
128
|
+
pipeline (int): The number of commands to pipeline
|
|
129
|
+
quiet: (bool): Whether to suppress output.
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
from . import _resp_benchmark_rust_lib
|
|
133
|
+
_resp_benchmark_rust_lib.benchmark(
|
|
134
|
+
host=self.host,
|
|
135
|
+
port=self.port,
|
|
136
|
+
username=self.username,
|
|
137
|
+
password=self.password,
|
|
138
|
+
cluster=self.cluster,
|
|
139
|
+
tls=False,
|
|
140
|
+
timeout=self.timeout,
|
|
141
|
+
cores=self.cores,
|
|
142
|
+
|
|
143
|
+
command=command,
|
|
144
|
+
connections=connections,
|
|
145
|
+
pipeline=pipeline,
|
|
146
|
+
count=count,
|
|
147
|
+
target=target,
|
|
148
|
+
seconds=0,
|
|
149
|
+
load=True,
|
|
150
|
+
quiet=quiet,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
def flushall(self):
|
|
154
|
+
"""
|
|
155
|
+
Clears all data from all Redis databases.
|
|
156
|
+
"""
|
|
157
|
+
r = redis.Redis(host=self.host, port=self.port, username=self.username, password=self.password)
|
|
158
|
+
r.flushall()
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: resp-benchmark
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Classifier: Programming Language :: Rust
|
|
5
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
7
|
+
Requires-Dist: pydantic
|
|
8
|
+
Requires-Dist: redis
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Summary: resp-benchmark is a benchmark tool for testing databases that support the RESP protocol, such as Redis, Valkey, and Tair.
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
13
|
+
|
|
14
|
+
# resp-benchmark
|
|
15
|
+
|
|
16
|
+
[](https://www.python.org/doc/versions/)
|
|
17
|
+
[](https://pypi.org/project/resp-benchmark/)
|
|
18
|
+
[](https://pypi.org/project/resp-benchmark/)
|
|
19
|
+
[](https://github.com/tair-opensource/resp-benchmark/blob/main/LICENSE)
|
|
20
|
+
|
|
21
|
+
[English](README_en.md) | 中文
|
|
22
|
+
|
|
23
|
+
一个基于 Rust 构建的 RESP (Redis 序列化协议) 数据库基准测试工具,提供 Python 绑定。用于测试 Redis、Valkey、Tair 等 RESP 兼容数据库的性能。
|
|
24
|
+
|
|
25
|
+
## 主要功能
|
|
26
|
+
|
|
27
|
+
- 支持自定义命令模板和占位符
|
|
28
|
+
- 多线程并发测试
|
|
29
|
+
- 支持连接池和管道操作
|
|
30
|
+
- 支持 Redis 集群模式
|
|
31
|
+
- 提供 CLI 工具和 Python 库接口
|
|
32
|
+
- 内置 QPS 限流控制
|
|
33
|
+
|
|
34
|
+
## 安装
|
|
35
|
+
|
|
36
|
+
需要 Python 3.9 或更高版本。
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install resp-benchmark
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 快速开始
|
|
43
|
+
|
|
44
|
+
### 命令行使用
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# 基础基准测试
|
|
48
|
+
resp-benchmark -s 10 "SET {key uniform 100000} {value 64}"
|
|
49
|
+
|
|
50
|
+
# 加载数据然后测试
|
|
51
|
+
resp-benchmark --load -n 1000000 "SET {key sequence 100000} {value 64}"
|
|
52
|
+
resp-benchmark -s 10 "GET {key uniform 100000}"
|
|
53
|
+
|
|
54
|
+
# 自定义连接数和管道
|
|
55
|
+
resp-benchmark -c 128 -P 10 -s 30 "SET {key uniform 1000000} {value 128}"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Python 库使用
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from resp_benchmark import Benchmark
|
|
62
|
+
|
|
63
|
+
# 初始化基准测试
|
|
64
|
+
bm = Benchmark(host="127.0.0.1", port=6379)
|
|
65
|
+
|
|
66
|
+
# 加载测试数据
|
|
67
|
+
bm.load_data(
|
|
68
|
+
command="SET {key sequence 1000000} {value 64}",
|
|
69
|
+
count=1000000,
|
|
70
|
+
connections=128
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# 运行基准测试
|
|
74
|
+
result = bm.bench(
|
|
75
|
+
command="GET {key uniform 1000000}",
|
|
76
|
+
seconds=30,
|
|
77
|
+
connections=64
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
print(f"QPS: {result.qps}")
|
|
81
|
+
print(f"平均延迟: {result.avg_latency_ms}ms")
|
|
82
|
+
print(f"P99 延迟: {result.p99_latency_ms}ms")
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## 命令语法
|
|
86
|
+
|
|
87
|
+
resp-benchmark 使用强大的占位符系统来生成多样化和真实的测试数据:
|
|
88
|
+
|
|
89
|
+
### 键占位符
|
|
90
|
+
|
|
91
|
+
- **`{key uniform N}`**: 从 0 到 N-1 的随机键
|
|
92
|
+
- 示例: `{key uniform 100000}` → `key_0000099999`
|
|
93
|
+
|
|
94
|
+
- **`{key sequence N}`**: 从 0 到 N-1 的顺序键(适用于加载数据)
|
|
95
|
+
- 示例: `{key sequence 100000}` → `key_0000000000`, `key_0000000001`, ...
|
|
96
|
+
|
|
97
|
+
- **`{key zipfian N}`**: Zipfian 分布键(模拟真实世界的访问模式)
|
|
98
|
+
- 示例: `{key zipfian 100000}` → 遵循指数为 1.03 的 Zipfian 分布
|
|
99
|
+
|
|
100
|
+
### 值占位符
|
|
101
|
+
|
|
102
|
+
- **`{value N}`**: N 字节的随机字符串
|
|
103
|
+
- 示例: `{value 64}` → `a8x9mK2p...` (64 字节)
|
|
104
|
+
|
|
105
|
+
- **`{rand N}`**: 0 到 N-1 的随机数
|
|
106
|
+
- 示例: `{rand 1000}` → `742`
|
|
107
|
+
|
|
108
|
+
- **`{range N W}`**: 范围 N 内相差 W 的两个数字
|
|
109
|
+
- 示例: `{range 100 10}` → `45 55`
|
|
110
|
+
|
|
111
|
+
### 命令示例
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# 字符串操作
|
|
115
|
+
SET {key uniform 1000000} {value 64}
|
|
116
|
+
GET {key uniform 1000000}
|
|
117
|
+
INCR {key uniform 100000}
|
|
118
|
+
|
|
119
|
+
# 列表操作
|
|
120
|
+
LPUSH {key uniform 1000} {value 64}
|
|
121
|
+
LINDEX {key uniform 1000} {rand 100}
|
|
122
|
+
|
|
123
|
+
# 集合操作
|
|
124
|
+
SADD {key uniform 1000} {value 64}
|
|
125
|
+
SISMEMBER {key uniform 1000} {value 64}
|
|
126
|
+
|
|
127
|
+
# 有序集合操作
|
|
128
|
+
ZADD {key uniform 1000} {rand 1000} {value 64}
|
|
129
|
+
ZRANGEBYSCORE {key uniform 1000} {range 1000 100}
|
|
130
|
+
|
|
131
|
+
# 哈希操作
|
|
132
|
+
HSET {key uniform 1000} {key uniform 100} {value 64}
|
|
133
|
+
HGET {key uniform 1000} {key uniform 100}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## 命令行选项
|
|
137
|
+
|
|
138
|
+
| 选项 | 描述 | 默认值 |
|
|
139
|
+
|------|------|--------|
|
|
140
|
+
| `-h` | 服务器主机名 | 127.0.0.1 |
|
|
141
|
+
| `-p` | 服务器端口 | 6379 |
|
|
142
|
+
| `-u` | 认证用户名 | "" |
|
|
143
|
+
| `-a` | 认证密码 | "" |
|
|
144
|
+
| `-c` | 连接数(0 为自动) | 0 |
|
|
145
|
+
| `-n` | 总请求数(0 为无限) | 0 |
|
|
146
|
+
| `-s` | 持续时间(秒)(0 为无限) | 0 |
|
|
147
|
+
| `-t` | 目标 QPS(0 为无限) | 0 |
|
|
148
|
+
| `-P` | 管道深度 | 1 |
|
|
149
|
+
| `--cores` | 使用的 CPU 核心(逗号分隔) | 全部 |
|
|
150
|
+
| `--cluster` | 启用集群模式 | false |
|
|
151
|
+
| `--load` | 仅加载数据,不进行基准测试 | false |
|
|
152
|
+
|
|
153
|
+
## 高级特性
|
|
154
|
+
|
|
155
|
+
### 连接自动扩展
|
|
156
|
+
|
|
157
|
+
当指定 `-c 0` 时,resp-benchmark 根据系统资源和目标 QPS 自动确定最优连接数。
|
|
158
|
+
|
|
159
|
+
### CPU 核心绑定
|
|
160
|
+
|
|
161
|
+
将基准测试线程绑定到特定 CPU 核心以获得一致的性能:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
# 使用核心 0, 1, 2, 3
|
|
165
|
+
resp-benchmark --cores 0,1,2,3 -s 10 "SET {key uniform 100000} {value 64}"
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### 速率限制
|
|
169
|
+
|
|
170
|
+
控制请求速率进行渐进式负载测试:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
# 目标 10,000 QPS
|
|
174
|
+
resp-benchmark -t 10000 -s 30 "SET {key uniform 100000} {value 64}"
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 管道操作
|
|
178
|
+
|
|
179
|
+
使用管道进行批量操作:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# 每个连接管道 10 个请求
|
|
183
|
+
resp-benchmark -P 10 -c 128 -s 30 "SET {key uniform 100000} {value 64}"
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 集群模式
|
|
187
|
+
|
|
188
|
+
使用自动槽位分布测试 Redis 集群:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
resp-benchmark --cluster -h cluster-endpoint -p 7000 -s 30 "SET {key uniform 100000} {value 64}"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## 性能优化
|
|
195
|
+
|
|
196
|
+
### 最佳实践
|
|
197
|
+
|
|
198
|
+
1. **预加载数据**: 使用 `--load` 在基准测试前填充测试数据
|
|
199
|
+
2. **适当的连接数**: 从 `-c 128` 开始,根据结果调整
|
|
200
|
+
3. **键分布**: 读取使用 `uniform`,写入使用 `sequence`
|
|
201
|
+
4. **明智使用管道**: 批量操作使用 `-P 10`,延迟测试使用 `-P 1`
|
|
202
|
+
5. **清洁状态**: 测试之间清除数据以避免干扰
|
|
203
|
+
|
|
204
|
+
### 示例工作流程
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
# 1. 清除现有数据
|
|
208
|
+
redis-cli FLUSHALL
|
|
209
|
+
|
|
210
|
+
# 2. 加载测试数据
|
|
211
|
+
resp-benchmark --load -c 256 -P 10 -n 1000000 "SET {key sequence 100000} {value 64}"
|
|
212
|
+
|
|
213
|
+
# 3. 使用不同模式进行基准测试
|
|
214
|
+
resp-benchmark -c 128 -s 30 "GET {key uniform 100000}" # 随机访问
|
|
215
|
+
resp-benchmark -c 128 -s 30 "GET {key zipfian 100000}" # 真实访问模式
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## 完整示例
|
|
219
|
+
|
|
220
|
+
### 字符串操作
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# 基本 SET/GET
|
|
224
|
+
resp-benchmark --load -n 1000000 "SET {key sequence 100000} {value 64}"
|
|
225
|
+
resp-benchmark -s 10 "GET {key uniform 100000}"
|
|
226
|
+
|
|
227
|
+
# 大值
|
|
228
|
+
resp-benchmark -s 10 "SET {key uniform 10000} {value 1024}"
|
|
229
|
+
|
|
230
|
+
# 递增操作
|
|
231
|
+
resp-benchmark -s 10 "INCR {key uniform 10000}"
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### 列表操作
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
# 构建列表
|
|
238
|
+
resp-benchmark --load -n 1000000 "LPUSH {key sequence 1000} {value 64}"
|
|
239
|
+
|
|
240
|
+
# 随机访问
|
|
241
|
+
resp-benchmark -s 10 "LINDEX {key uniform 1000} {rand 1000}"
|
|
242
|
+
|
|
243
|
+
# 范围操作
|
|
244
|
+
resp-benchmark -s 10 "LRANGE {key uniform 1000} {range 1000 10}"
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### 集合操作
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
# 填充集合
|
|
251
|
+
resp-benchmark --load -n 1000000 "SADD {key sequence 1000} {key sequence 1000}"
|
|
252
|
+
|
|
253
|
+
# 测试成员关系
|
|
254
|
+
resp-benchmark -s 10 "SISMEMBER {key uniform 1000} {key uniform 1000}"
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### 有序集合操作
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# 添加带分数的成员
|
|
261
|
+
resp-benchmark --load -n 1000000 "ZADD {key sequence 1000} {rand 10000} {key sequence 1000}"
|
|
262
|
+
|
|
263
|
+
# 分数查询
|
|
264
|
+
resp-benchmark -s 10 "ZSCORE {key uniform 1000} {key uniform 1000}"
|
|
265
|
+
|
|
266
|
+
# 范围查询
|
|
267
|
+
resp-benchmark -s 10 "ZRANGEBYSCORE {key uniform 1000} {range 10000 100}"
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### 哈希操作
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
# 填充哈希
|
|
274
|
+
resp-benchmark --load -n 1000000 "HSET {key sequence 1000} {key sequence 100} {value 64}"
|
|
275
|
+
|
|
276
|
+
# 字段访问
|
|
277
|
+
resp-benchmark -s 10 "HGET {key uniform 1000} {key uniform 100}"
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Lua 脚本
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
# 加载脚本
|
|
284
|
+
redis-cli SCRIPT LOAD "return redis.call('SET', KEYS[1], ARGV[1])"
|
|
285
|
+
|
|
286
|
+
# 基准测试脚本执行
|
|
287
|
+
resp-benchmark -s 10 "EVALSHA d8f2fad9f8e86a53d2a6ebd960b33c4972cacc37 1 {key uniform 100000} {value 64}"
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Python 库 API
|
|
291
|
+
|
|
292
|
+
### 初始化
|
|
293
|
+
|
|
294
|
+
```python
|
|
295
|
+
from resp_benchmark import Benchmark
|
|
296
|
+
|
|
297
|
+
# 基本连接
|
|
298
|
+
bm = Benchmark(host="127.0.0.1", port=6379)
|
|
299
|
+
|
|
300
|
+
# 带认证
|
|
301
|
+
bm = Benchmark(
|
|
302
|
+
host="redis.example.com",
|
|
303
|
+
port=6379,
|
|
304
|
+
username="user",
|
|
305
|
+
password="pass"
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
# 集群模式
|
|
309
|
+
bm = Benchmark(
|
|
310
|
+
host="cluster-endpoint",
|
|
311
|
+
port=7000,
|
|
312
|
+
cluster=True
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
# 自定义配置
|
|
316
|
+
bm = Benchmark(
|
|
317
|
+
host="127.0.0.1",
|
|
318
|
+
port=6379,
|
|
319
|
+
cores="0,1,2,3", # 使用特定核心
|
|
320
|
+
timeout=30 # 连接超时
|
|
321
|
+
)
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### 加载数据
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
# 顺序加载(推荐)
|
|
328
|
+
bm.load_data(
|
|
329
|
+
command="SET {key sequence 1000000} {value 64}",
|
|
330
|
+
count=1000000,
|
|
331
|
+
connections=128,
|
|
332
|
+
pipeline=10
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
# 带速率限制
|
|
336
|
+
bm.load_data(
|
|
337
|
+
command="SET {key sequence 1000000} {value 64}",
|
|
338
|
+
count=1000000,
|
|
339
|
+
connections=128,
|
|
340
|
+
target=50000 # 50k QPS
|
|
341
|
+
)
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### 基准测试
|
|
345
|
+
|
|
346
|
+
```python
|
|
347
|
+
# 基于时间的基准测试
|
|
348
|
+
result = bm.bench(
|
|
349
|
+
command="GET {key uniform 1000000}",
|
|
350
|
+
seconds=30,
|
|
351
|
+
connections=64
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
# 基于计数的基准测试
|
|
355
|
+
result = bm.bench(
|
|
356
|
+
command="GET {key uniform 1000000}",
|
|
357
|
+
count=1000000,
|
|
358
|
+
connections=64
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
# 带管道
|
|
362
|
+
result = bm.bench(
|
|
363
|
+
command="SET {key uniform 1000000} {value 64}",
|
|
364
|
+
seconds=30,
|
|
365
|
+
connections=64,
|
|
366
|
+
pipeline=10
|
|
367
|
+
)
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### 结果分析
|
|
371
|
+
|
|
372
|
+
```python
|
|
373
|
+
# 访问基准测试结果
|
|
374
|
+
print(f"QPS: {result.qps:.2f}")
|
|
375
|
+
print(f"平均延迟: {result.avg_latency_ms:.2f}ms")
|
|
376
|
+
print(f"P99 延迟: {result.p99_latency_ms:.2f}ms")
|
|
377
|
+
print(f"使用的连接数: {result.connections}")
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## 贡献
|
|
381
|
+
|
|
382
|
+
欢迎贡献!请随时提交拉取请求或开启议题。
|
|
383
|
+
|
|
384
|
+
## 许可证
|
|
385
|
+
|
|
386
|
+
该项目基于 MIT 许可证 - 详见 [LICENSE](LICENSE) 文件。
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
resp_benchmark-0.2.0.dist-info/METADATA,sha256=BxS1x3Bjr63N3XyEZDirnxWF1GQ6v_QfT7ab-mScQo4,9432
|
|
2
|
+
resp_benchmark-0.2.0.dist-info/WHEEL,sha256=pdo47EFB8jvJ7Rk8aRXFTmxNh-rSG_26kj9cjGCRbFo,138
|
|
3
|
+
resp_benchmark-0.2.0.dist-info/entry_points.txt,sha256=q1llaLwyhHn2jvpR28wBbila30DyZ1B5_4ackdlZ2R4,57
|
|
4
|
+
resp_benchmark-0.2.0.dist-info/licenses/LICENSE,sha256=Kj-yFXYfT2SMHVx80nmX0ta2SPNqCQAq1_fwhkPqJrw,1072
|
|
5
|
+
resp_benchmark/__init__.py,sha256=5DYLIsYOU6wd-xMX2sJF1IMr3vktktFIBE6CyxUc3A4,74
|
|
6
|
+
resp_benchmark/_resp_benchmark_rust_lib.pypy311-pp73-aarch64-linux-gnu.so,sha256=ZnJNlIjUzi3XrDMCyRkbkW_1J1WQd8KMYcl6Synaeqo,3129896
|
|
7
|
+
resp_benchmark/cli.py,sha256=MH7MfDBBzEVCfTuq_K9vd_iKGVIs4LW4pk_U1tZpGoM,2695
|
|
8
|
+
resp_benchmark/cores.py,sha256=bSEaHXJYo6spGIK_j-beTz8qbun3D7bgYrYxjUaMuDw,619
|
|
9
|
+
resp_benchmark/wrapper.py,sha256=6S1YChLkEc65pGY5SxGnjO5biwVpZ8gHMGVt8tHeXtU,4989
|
|
10
|
+
resp_benchmark-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 tair-opensource
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|