|
| 1 | +# 性能测试 |
| 2 | + |
| 3 | +本文档介绍 SQLRec 的性能测试方法和测试结果。 |
| 4 | + |
| 5 | +## 测试环境 |
| 6 | + |
| 7 | +**硬件配置**: |
| 8 | +- CPU: AMD Ryzen 5600H |
| 9 | +- 内存: 32GB DDR4 |
| 10 | + |
| 11 | +**软件环境**: |
| 12 | +- 操作系统: Debian 12 |
| 13 | +- Kubernetes: Minikube |
| 14 | +- SQLRec: 单实例部署 |
| 15 | + |
| 16 | +## 测试数据 |
| 17 | + |
| 18 | +默认测试配置如下: |
| 19 | + |
| 20 | +| 配置项 | 值 | |
| 21 | +|--------|-----| |
| 22 | +| 用户数量 | 10万 | |
| 23 | +| 物品数量 | 10万 | |
| 24 | +| 向量维度 | 8维 | |
| 25 | +| User Embedding | 固定值 | |
| 26 | + |
| 27 | +## 推荐流程 |
| 28 | + |
| 29 | +测试的推荐流程包含以下环节: |
| 30 | + |
| 31 | +### 召回阶段 |
| 32 | + |
| 33 | +| 召回策略 | 说明 | 召回数量 | |
| 34 | +|----------|------|----------| |
| 35 | +| 全局高热召回 | 基于全局物品热度排序 | 300 | |
| 36 | +| 用户兴趣类目召回 | 基于用户兴趣类目召回高热物品 | 300 | |
| 37 | +| ItemCF 召回 | 基于物品协同过滤召回 | 300 | |
| 38 | +| 向量检索召回 | 基于向量相似度检索 | 300 | |
| 39 | + |
| 40 | +### 过滤阶段 |
| 41 | + |
| 42 | +| 过滤策略 | 说明 | |
| 43 | +|----------|------| |
| 44 | +| 曝光去重 | 过滤用户已曝光的物品 | |
| 45 | +| 类目打散 | 每个类目最多展示 N 个物品 | |
| 46 | + |
| 47 | +## 测试脚本 |
| 48 | + |
| 49 | +### 初始化测试环境 |
| 50 | + |
| 51 | +```bash |
| 52 | +cd benchmark |
| 53 | +bash init.sh |
| 54 | +``` |
| 55 | + |
| 56 | +`init.sh` 脚本执行以下操作: |
| 57 | + |
| 58 | +1. **创建 Milvus 向量集合** |
| 59 | + - 创建 `item_embedding` 集合 |
| 60 | + - 定义向量维度为 8 维 |
| 61 | + - 创建 COSINE 相似度索引 |
| 62 | + |
| 63 | +2. **创建数据表** |
| 64 | + - 用户表 (`user_table`) |
| 65 | + - 物品表 (`item_table`) |
| 66 | + - 全局高热物品表 (`global_hot_item`) |
| 67 | + - 用户兴趣类目表 (`user_interest_category1`) |
| 68 | + - 类目高热物品表 (`category1_hot_item`) |
| 69 | + - 用户最近点击表 (`user_recent_click_item`) |
| 70 | + - 用户曝光表 (`user_exposure_item`) |
| 71 | + - ItemCF I2I 表 (`itemcf_i2i`) |
| 72 | + - 物品向量表 (`item_embedding`) |
| 73 | + - 推荐日志表 (`rec_log_kafka`) |
| 74 | + |
| 75 | +3. **生成模拟数据** |
| 76 | + - 使用 Python 脚本生成 10 万用户和 10 万物品数据 |
| 77 | + - 生成用户行为数据并上传到 HDFS |
| 78 | + |
| 79 | +4. **安装测试工具** |
| 80 | + - 安装 wrk HTTP 压测工具 |
| 81 | + |
| 82 | +### 执行性能测试 |
| 83 | + |
| 84 | +```bash |
| 85 | +bash benchmark.sh |
| 86 | +``` |
| 87 | + |
| 88 | +`benchmark.sh` 脚本执行以下操作: |
| 89 | + |
| 90 | +1. **预热阶段** |
| 91 | + - 单线程、单连接运行 10 秒 |
| 92 | + - 预热系统缓存 |
| 93 | + |
| 94 | +2. **正式测试** |
| 95 | + - 并发数: 10 |
| 96 | + - 持续时间: 30 秒 |
| 97 | + - 测试 URL: `/api/v1/main_rec` |
| 98 | + |
| 99 | +### 测试请求脚本 |
| 100 | + |
| 101 | +`request.lua` 是 wrk 的自定义请求脚本: |
| 102 | + |
| 103 | +```lua |
| 104 | +-- Set random seed |
| 105 | +math.randomseed(os.time()) |
| 106 | + |
| 107 | +function request() |
| 108 | + -- Generate random ID between 0-99999 |
| 109 | + local random_id = math.random(0, 99999) |
| 110 | + |
| 111 | + -- Construct request body |
| 112 | + local request_body = string.format( |
| 113 | + '{"inputs":{"user_info":[{"id":%d}]},"params":{"recall_fun":"recall_fun"}}', |
| 114 | + random_id |
| 115 | + ) |
| 116 | + |
| 117 | + -- Configure HTTP request |
| 118 | + wrk.method = "POST" |
| 119 | + wrk.headers["Content-Type"] = "application/json" |
| 120 | + wrk.body = request_body |
| 121 | + |
| 122 | + return wrk.format() |
| 123 | +end |
| 124 | +``` |
| 125 | + |
| 126 | +## 测试结果 |
| 127 | + |
| 128 | +在 AMD Ryzen 5600H、32GB DDR4 内存机器上的测试结果: |
| 129 | + |
| 130 | +``` |
| 131 | +Running 30s test @ http://192.168.49.2:30301/api/v1/main_rec |
| 132 | + 10 threads and 10 connections |
| 133 | + Thread Stats Avg Stdev Max +/- Stdev |
| 134 | + Latency 10.80ms 4.81ms 53.85ms 92.68% |
| 135 | + Req/Sec 95.12 17.61 121.00 82.63% |
| 136 | + 28464 requests in 30.02s, 49.80MB read |
| 137 | + Socket errors: connect 0, read 28463, write 0, timeout 0 |
| 138 | +Requests/sec: 948.09 |
| 139 | +Transfer/sec: 1.66MB |
| 140 | +``` |
| 141 | + |
| 142 | +**性能指标**: |
| 143 | + |
| 144 | +| 指标 | 值 | |
| 145 | +|------|-----| |
| 146 | +| 平均延迟 | 10.80ms | |
| 147 | +| 延迟标准差 | 4.81ms | |
| 148 | +| 最大延迟 | 53.85ms | |
| 149 | +| 平均 QPS | 95.12 | |
| 150 | +| 总请求数 | 28,464 | |
| 151 | +| 总 QPS | 948.09 | |
| 152 | +| 吞吐量 | 1.66MB/s | |
0 commit comments