工作总结:微服务性能优化与架构
本文档汇总三个微服务的性能优化、架构设计及性能测试基线,便于汇报与后续复现。
一、完成三个微服务的性能优化
1. 文本向量(Embedding)
调研与选型:对 TEI(Text Embeddings Inference)、vLLM 与原有 SentenceTransformers 方案进行对比评估。
| 方案 | 特点 | 结论 |
|---|---|---|
| SentenceTransformers | 本地 Python 进程,单机推理,无独立服务化 | 此前用于 Qwen3-Embedding-0.6B,扩展性与运维性一般 |
| vLLM | 高吞吐推理框架,更适合生成式与重排混合场景 | 纯 embedding 场景通常不作为首选 |
| TEI | HuggingFace 官方 embedding 专用推理服务,Docker 部署 | 当前最优选型 |
当前方案:以 TEI 为文本向量后端,模型为 Qwen/Qwen3-Embedding-0.6B;文本 embedding 服务(端口 6005)将 POST /embed/text 请求转发至 TEI(默认端口 8080)。
具体配置与脚本:
- 配置:
config/config.yaml→services.embedding.backend: "tei",services.embedding.backends.tei.base_url: "http://127.0.0.1:8080"、model_id: "Qwen/Qwen3-Embedding-0.6B"、timeout_sec: 20。 - 启动:
scripts/start_tei_service.sh(Docker 容器);环境变量:TEI_DEVICE=cuda(默认)、TEI_PORT=8080、TEI_MODEL_ID=Qwen/Qwen3-Embedding-0.6B、TEI_VERSION=1.9、TEI_MAX_BATCH_TOKENS=4096、TEI_MAX_CLIENT_BATCH_SIZE=24、TEI_DTYPE=float16;T4 自动选镜像ghcr.io/huggingface/text-embeddings-inference:turing-1.9。 - 编排:
./scripts/service_ctl.sh start tei或start embedding(text embedding 会校验 TEI/health后再就绪)。
工程化收益:
- 独立服务:TEI 以 Docker 容器运行,与主程序
.venv解耦;embedding 使用.venv-embedding,便于独立扩缩容与升级。 - 协议统一:与
local_st(SentenceTransformers)可插拔,通过config.yaml的services.embedding.backend或环境变量EMBEDDING_BACKEND切换。 - T4 适配:按 GPU 架构自动选择镜像(T4 用
turing-*,Ampere+ 用cuda-*);TEI_MAX_BATCH_TOKENS、TEI_MAX_CLIENT_BATCH_SIZE、TEI_DTYPE已按短文本场景调优。 - 健康检查与编排:
service_ctl.sh对 tei 校验容器存在且GET http://127.0.0.1:8080/health成功;embedding 启动前会等待 TEI 健康。
详见:docs/TEI_SERVICE说明文档.md、docs/QUICKSTART.md §4。
2. 重排(Reranker)
后端:vLLM 部署 Qwen3-Reranker-0.6B,对外提供 POST /rerank(query + docs → scores),端口 6007。
针对 T4 的优化(已落地配置):
- 精度:
dtype: "float16",降低显存与计算量。 - Prefix Caching:
enable_prefix_caching: true,对重复前缀(如相同 query)做缓存,减少重复计算。 - CUDA 图:
enforce_eager: false(默认),利用 vLLM 的 CUDA graph 降低 kernel 启动开销。 - 按文档长度分批:
sort_by_doc_length: true,请求内先按文档长度排序再按infer_batch_size分批推理,减少 padding 浪费。 - 参数搜索结论:在 T4、1000-doc 口径下对
infer_batch_size做了 24/32/48/64 对比;单请求延迟(c=1) 上infer_batch_size=64最优,故当前默认infer_batch_size: 64;max_model_len: 256满足 query+doc 短文本场景;gpu_memory_utilization: 0.36与 T4 16GB 匹配。
具体配置(config/config.yaml → services.rerank.backends.qwen3_vllm):
model_name: "Qwen/Qwen3-Reranker-0.6B"
engine: "vllm"
max_model_len: 256
tensor_parallel_size: 1
gpu_memory_utilization: 0.36
dtype: "float16"
enable_prefix_caching: true
enforce_eager: false
infer_batch_size: 64
sort_by_doc_length: true
instruction: "Given a shopping query, rank product titles by relevance"
环境变量覆盖:RERANK_BACKEND、RERANKER_SERVICE_URL、RERANK_VLLM_INFER_BATCH_SIZE、RERANK_VLLM_SORT_BY_DOC_LENGTH 等。启停:./scripts/service_ctl.sh start reranker,健康:curl -sS http://127.0.0.1:6007/health。
详见:reranker/DEPLOYMENT_AND_TUNING.md、reranker/README.md。
3. 图片向量(Image Embedding)
方案:clip-as-service(CN-CLIP,模型由配置控制),由独立服务提供图片向量化能力。
具体内容:
- 端口:clip-as-service 默认 51000(
CNCLIP_PORT);文本走 TEI(8080),图片走 clip-as-service。 - API:文本 embedding 服务默认暴露
POST /embed/text(6005),图片 embedding 服务默认暴露POST /embed/image(6008);图片请求由embeddings/server.py按配置调用实现ImageEncoderProtocol的后端(clip-as-service 或本地 CN-CLIP)。 - 环境与启停:CN-CLIP 使用独立虚拟环境
.venv-cnclip;启动scripts/start_cnclip_service.sh,或./scripts/service_ctl.sh start cnclip;设备可通过CNCLIP_DEVICE=cuda(默认)或cpu指定。 - 配置:图片后端在
config/config.yaml的services.embedding下配置(若存在 image 相关 backend);clip-as-service 默认模型由embeddings/config.py的CLIP_AS_SERVICE_MODEL_NAME控制,flow 配置在third-party/clip-as-service/server/torch-flow-temp.yml。
详见:docs/CNCLIP_SERVICE说明文档.md、embeddings/README.md。
4. 翻译(Translation)
背景:原使用 DeepL,后迁移至 qwen-mt(如 qwen-mt-flash)。qwen-mt 云端限速约 RPM=60(每分钟 60 请求),此前未做大商品量压测,未暴露问题;高并发索引或查询场景下易触限。
当前方案:
- 统一 translator service:业务侧统一走 6006,按
model + scene选择能力,不再存在翻译 provider 分支。 - 配置入口:
config/config.yaml→services.translation,显式声明service_url、default_model、default_scene、各 capability 的backend、base_url/api_url、timeout 与本地模型运行参数。 - 内部规则收口:scene 集合、语言码映射、LLM prompt 模板、本地模型方向约束统一放在
translation/内部,不再散落在config/、query/等位置。 - 调用位置:QueryParser 与 Indexer 均通过
translation.create_translation_client()获取客户端,不写死 URL 或模型名。 - 缓存:translator service 对所有 translation capability 统一接入 Redis 缓存;每个 capability 通过
use_cache控制开关,key 格式固定为trans:{model}:{target_lang}:{source_text[:4]}{sha256}。 - 场景支撑:在线索引(indexer)与 query 请求(QueryParser)共用同一套 provider 配置;可按环境或租户通过修改
config.yaml或环境变量切换 provider/model。 - 待配合:金伟侧对索引侧翻译调用做流量控制(限流/排队/批量聚合),避免索引高峰打满 qwen 限速,影响在线 query 翻译。
5. 内容理解字段(支撑 Suggest)
能力:支持根据商品标题批量生成 qanchors(锚文本)、enriched_attributes、tags,供索引与 suggest 使用。
具体内容:
- 接口:
POST /indexer/enrich-content(Indexer 服务端口 6004)。请求体为items数组,每项含spu_id、title(必填)及可选多语言标题等;单次请求最多 50 条,建议批量调用。响应results与items一一对应,每项含spu_id、qanchors(按语言键,如qanchors.zh、qanchors.en,逗号分隔短语)、enriched_attributes、tags。 - 索引侧:微服务组合方式下,调用方先拿不含 qanchors/tags 的 doc,再调用本接口补齐后写入 ES 的
qanchors.{lang}等字段;索引 transformer(indexer/document_transformer.py、indexer/product_enrich.py)内也可在构建 doc 时调用内容理解逻辑,写入qanchors.{lang}。 - Suggest 侧:
suggestion/builder.py从 ES 商品索引读取_source: ["id", "spu_id", "title", "qanchors"],对qanchors.{lang}用_split_qanchors拆成词条,以source="qanchor"加入候选,排序时qanchor权重大于纯 title(add_product("qanchor", ...));suggest 配置中sources: ["query_log", "qanchor"]表示候选来源包含 qanchor。 - 实现与依赖:内容理解内部使用大模型(需
DASHSCOPE_API_KEY),支持多语言与 Redis 缓存(如product_anchors);逻辑与indexer/product_enrich一致。
状态:内容理解字段已接入索引与 suggest 链路;依赖内容理解(qanchors/tags)的全量数据尚未全部完成一轮,后续需持续跑满并校验效果。
详见:indexer/ANCHORS_AND_SEMANTIC_ATTRIBUTES.md、docs/搜索API对接指南-05-索引接口(Indexer).md(enrich-content 等)、api/routes/indexer.py(enrich-content 路由)。
二、架构
1. Translator Service 与动态选择翻译
- 设计:翻译已从 provider 架构中独立出来,采用 一个 translator service + 多个 capability backend;配置单一来源为
config/config.yaml的services.translation块,service_url/default_model/default_scene不再接受环境变量静默覆盖。 - 翻译(具体实现):
- 业务入口:
translation.create_translation_client() - 服务编排:
translation/service.py - 后端实现:
translation/backends/qwen_mt.py、translation/backends/llm.py、translation/backends/deepl.py、translation/backends/local_seq2seq.py - 调用方:
query/query_parser.py、indexer/incremental_service.py、indexer/indexing_utils.py
- 业务入口:
- 效果:仅改
services.translation.default_model或启用的 capability,即可切换云端/本地翻译能力;调用方始终只连 6006。
2. 服务的监控与拉起机制
- 脚本:
scripts/service_ctl.sh统一负责各服务的生命周期与监控;依赖scripts/lib/load_env.sh与项目根目录.env。 - 服务与端口:
- 核心:backend 6002、indexer 6004、frontend 6003、eval-web 6010(搜索评估 UI)。
- 可选:embedding(text) 6005、embedding-image 6008、translator 6006、reranker 6007、tei 8080、cnclip 51000。
- 端口可由环境变量覆盖:
API_PORT、INDEXER_PORT、FRONTEND_PORT、EVAL_WEB_PORT、EMBEDDING_TEXT_PORT、EMBEDDING_IMAGE_PORT、TRANSLATION_PORT、RERANKER_PORT、TEI_PORT、CNCLIP_PORT。
- 命令:
./scripts/service_ctl.sh start [service...]或up all/start all(all 含 tei、cnclip、embedding、embedding-image、translator、reranker、backend、indexer、frontend、eval-web,按依赖顺序);stop、restart、down同参数;status默认列出所有服务。- 启动时:backend/indexer/frontend/embedding/translator/reranker 会写 pid 到
logs/<service>.pid,并执行wait_for_health(GEThttp://127.0.0.1:<port>/health);reranker 健康重试 90 次,其余 30 次;TEI 校验 Docker 容器存在且/health成功;cnclip 无 HTTP 健康则仅校验进程/端口。
- 监控常驻:
./scripts/service_ctl.sh monitor-start <targets>启动后台监控进程,将 targets 写入logs/service-monitor.targets,pid 写入logs/service-monitor.pid,日志追加到logs/service-monitor.log。- 轮询间隔
MONITOR_INTERVAL_SEC默认 10 秒;连续 3 次(MONITOR_FAIL_THRESHOLD)健康失败则触发重启;重启冷却MONITOR_RESTART_COOLDOWN_SEC默认 30 秒;每小时最多重启MONITOR_MAX_RESTARTS_PER_HOUR默认 6 次;超限时调用scripts/ops/wechat_alert.py告警(若存在)。
- 日志:各服务按日滚动到
logs/<service>-<date>.log,通过scripts/ops/daily_log_router.sh与LOG_RETENTION_DAYS(默认 30)控制保留。
详见:scripts/service_ctl.sh 内注释及 docs/Usage-Guide.md。
3. Suggest 索引与增量
- 当前:suggest 索引由全量脚本触发,入口为
main.py build-suggestions,或封装脚本scripts/build_suggestions.sh <tenant_id> [args...]。- 全量示例:
./scripts/build_suggestions.sh 162 --mode full --days 30 --publish-alias(重建建议索引,近 30 天数据,并发布别名)。 - 增量示例:
./scripts/build_suggestions.sh 162 --mode incremental --overlap-minutes 30(按 watermark 增量更新);脚本内部调用main.py build-suggestions --tenant-id <id> ...。 - 构建逻辑在
suggestion/builder.py的SuggestionIndexBuilder:从 ES 商品索引(含title、qanchors)与查询日志等拉取数据,写入 versioned 建议索引并切换 alias。
- 全量示例:
- 尚未完成的“增量机制”:指自动/事件驱动的增量(如商品变更或日志写入时自动刷新建议索引);当前 incremental 模式为“按 watermark 再跑一次构建”,仍为脚本主动触发,非持续增量流水线。
- 依赖:suggest 候选依赖商品侧 内容理解字段(qanchors/tags);
sources: ["query_log", "qanchor"]表示候选来自查询日志与 qanchor;当前内容理解未全量跑完一轮,suggest 数据会随全量重建逐步完善。
详见:suggestion/builder.py、suggestion/ARCHITECTURE_V2.md、main.py(build-suggestions 子命令)。
三、性能测试报告摘要
以下数据来自 docs/性能测试报告.md,测试时间 2026-03-12,环境:8 vCPU(Intel Xeon Platinum 8255C @ 2.50GHz)、约 15Gi 可用内存;租户 162 文档数约 53(search/search/suggestions/rerank 与文档规模相关)。压测工具:benchmarks/perf_api_benchmark.py,场景×并发矩阵,每档 20s。
复现命令(四场景×四并发):
cd /data/saas-search
.venv/bin/python benchmarks/perf_api_benchmark.py \
--scenario backend_search,backend_suggest,embed_text,rerank \
--concurrency-list 1,5,10,20 \
--duration 20 \
--tenant-id 162 \
--backend-base http://127.0.0.1:6002 \
--embedding-base http://127.0.0.1:6005 \
--translator-base http://127.0.0.1:6006 \
--reranker-base http://127.0.0.1:6007 \
--output perf_reports/2026-03-12/perf_matrix_report.json
执行前需启动服务:./scripts/service_ctl.sh start embedding translator reranker backend,并通过各端口 /health 检查。Reranker 单独 386-docs 口径复现见性能测试报告 §7.4 与 §13。
3.1 向量化服务(embed_text)
| 并发 | 请求数 | 成功率 | 吞吐(RPS) | Avg(ms) | P95(ms) | Max(ms) |
|---|---|---|---|---|---|---|
| 1 | 966 | 100% | 48.27 | 20.63 | 23.41 | 49.80 |
| 5 | 1796 | 100% | 89.57 | 55.55 | 69.62 | 109.84 |
| 10 | 2095 | 100% | 104.42 | 95.22 | 117.66 | 152.48 |
| 20 | 2393 | 100% | 118.70 | 167.37 | 212.21 | 318.70 |
结论:随并发提升吞吐持续增长,延迟平滑上升,扩展性较好。
3.2 Reranker(rerank)
口径:query 固定 wireless mouse,每次请求 386 docs,句长 15–40 词随机(从 1000 词池采样);配置 rerank_window=384。复现命令:
.venv/bin/python benchmarks/perf_api_benchmark.py \
--scenario rerank --duration 20 --concurrency-list 1,5,10,20 --timeout 60 \
--rerank-dynamic-docs --rerank-doc-count 386 --rerank-vocab-size 1000 \
--rerank-sentence-min-words 15 --rerank-sentence-max-words 40 \
--rerank-query "wireless mouse" --rerank-seed 20260312 \
--reranker-base http://127.0.0.1:6007 \
--output perf_reports/2026-03-12/rerank_realistic/rerank_386docs.json
| 并发 | 请求数 | 成功率 | 吞吐(RPS) | Avg(ms) | P95(ms) | Max(ms) |
|---|---|---|---|---|---|---|
| 1 | 14 | 100% | 0.67 | 1498.64 | 1799.25 | 2160.96 |
| 5 | 15 | 100% | 0.62 | 8011.99 | 9725.61 | 9726.02 |
| 10 | 20 | 100% | 0.61 | 16217.12 | 18043.05 | 18050.04 |
| 20 | 20 | 100% | 0.60 | 33252.35 | 33456.74 | 33480.14 |
结论:在 386 docs/请求 的真实口径下,吞吐约 0.6 rps,延迟随并发明显上升(并发 20 时 P95 约 33.5s),是当前整条链路的最重瓶颈。与 DashScope 云后端对比:单并发 vLLM 延迟更优;并发 5+ 时云后端吞吐更高(约 1.3x–6x),在线高并发场景可优先考虑云后端。
3.3 搜索(backend_search)
| 并发 | 请求数 | 成功率 | 吞吐(RPS) | Avg(ms) | P95(ms) | Max(ms) |
|---|---|---|---|---|---|---|
| 1 | 160 | 100% | 7.98 | 124.89 | 228.06 | 345.49 |
| 5 | 161 | 100% | 7.89 | 628.91 | 1271.49 | 1441.02 |
| 10 | 181 | 100% | 8.78 | 1129.23 | 1295.88 | 1330.96 |
| 20 | 161 | 100% | 7.63 | 2594.00 | 4706.44 | 4783.05 |
结论:吞吐约 8 rps 平台化,延迟随并发上升明显,符合“检索 + 向量 + 重排”重链路特征。多租户补测(文档数 500–10000,见报告 §12)表明:文档数越大,RPS 下降、延迟升高;tenant 0(10000 doc)在并发 20 出现部分 ReadTimeout(成功率 59.02%),需注意 timeout 与容量规划;补测命令示例:for t in 0 1 2 3 4; do .venv/bin/python benchmarks/perf_api_benchmark.py --scenario backend_search --concurrency-list 1,5,10,20 --duration 20 --tenant-id $t --output perf_reports/2026-03-12/search_tenant_matrix/tenant_${t}.json; done。
3.4 Suggest(backend_suggest)
| 并发 | 请求数 | 成功率 | 吞吐(RPS) | Avg(ms) | P95(ms) | Max(ms) |
|---|---|---|---|---|---|---|
| 1 | 3502 | 100% | 175.09 | 5.68 | 8.70 | 15.98 |
| 5 | 4168 | 100% | 208.10 | 23.93 | 36.93 | 59.53 |
| 10 | 4152 | 100% | 207.25 | 48.05 | 59.45 | 127.20 |
| 20 | 4190 | 100% | 208.99 | 95.20 | 110.74 | 181.37 |
结论:吞吐高且稳定(约 200+ rps),对并发友好,与 search/rerank 相比压力较小。
四、总结
| 维度 | 要点 |
|---|---|
| Embedding | TEI 替代 SentenceTransformers/vLLM 作为文本向量后端,兼顾性能与工程化(Docker、配置化、T4 调优);图片向量由 clip-as-service 承担。 |
| Reranker | vLLM + Qwen3-Reranker-0.6B,针对 T4 做 float16、prefix caching、CUDA 图、按长度分批及 batch/长度参数搜索;高并发场景可选用 DashScope 云后端。 |
| 翻译 | 因 qwen-mt 限速(RPM≈60),迁移至可配置的 qwen-flash 等方案,支撑在线索引与 query;需金伟侧对索引做流量控制。 |
| 内容理解 | 提供 qanchors/tags 等字段生成接口,支撑 suggest 与检索增强;全量一轮尚未完全跑满。 |
| 架构 | Provider 动态选择翻译;service_ctl 统一监控与拉起;suggest 目前全量脚本触发,增量待做。 |
| 性能基线 | 向量化扩展性良好;reranker 为整链瓶颈(386 docs 约 0.6 rps);search 约 8 rps;suggest 约 200+ rps。 |
关键文件与复现:
- 配置:
config/config.yaml(services、rerank、query_config)、.env(端口与 API Key)。 - 脚本:
scripts/service_ctl.sh(启停与监控)、benchmarks/perf_api_benchmark.py(压测)、scripts/build_suggestions.sh(suggest 构建)。 - 完整步骤与多租户/rerank 对比见:
docs/性能测试报告.md。