工作总结-微服务性能优化与架构.md 19.2 KB

工作总结:微服务性能优化与架构

本文档汇总三个微服务的性能优化架构设计性能测试基线,便于汇报与后续复现。


一、完成三个微服务的性能优化

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.yamlservices.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=8080TEI_MODEL_ID=Qwen/Qwen3-Embedding-0.6BTEI_VERSION=1.9TEI_MAX_BATCH_TOKENS=4096TEI_MAX_CLIENT_BATCH_SIZE=24TEI_DTYPE=float16;T4 自动选镜像 ghcr.io/huggingface/text-embeddings-inference:turing-1.9
  • 编排./scripts/service_ctl.sh start teistart embedding(text embedding 会校验 TEI /health 后再就绪)。

工程化收益

  • 独立服务:TEI 以 Docker 容器运行,与主程序 .venv 解耦;embedding 使用 .venv-embedding,便于独立扩缩容与升级。
  • 协议统一:与 local_st(SentenceTransformers)可插拔,通过 config.yamlservices.embedding.backend 或环境变量 EMBEDDING_BACKEND 切换。
  • T4 适配:按 GPU 架构自动选择镜像(T4 用 turing-*,Ampere+ 用 cuda-*);TEI_MAX_BATCH_TOKENSTEI_MAX_CLIENT_BATCH_SIZETEI_DTYPE 已按短文本场景调优。
  • 健康检查与编排service_ctl.sh 对 tei 校验容器存在且 GET http://127.0.0.1:8080/health 成功;embedding 启动前会等待 TEI 健康。

详见:docs/TEI_SERVICE说明文档.mddocs/QUICKSTART.md §4。


2. 重排(Reranker)

后端:vLLM 部署 Qwen3-Reranker-0.6B,对外提供 POST /rerank(query + docs → scores),端口 6007

针对 T4 的优化(已落地配置)

  • 精度dtype: "float16",降低显存与计算量。
  • Prefix Cachingenable_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: 64max_model_len: 256 满足 query+doc 短文本场景;gpu_memory_utilization: 0.36 与 T4 16GB 匹配。

具体配置config/config.yamlservices.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_BACKENDRERANKER_SERVICE_URLRERANK_VLLM_INFER_BATCH_SIZERERANK_VLLM_SORT_BY_DOC_LENGTH 等。启停:./scripts/service_ctl.sh start reranker,健康:curl -sS http://127.0.0.1:6007/health

详见:reranker/DEPLOYMENT_AND_TUNING.mdreranker/README.md


3. 图片向量(Image Embedding)

方案clip-as-service(CN-CLIP,模型由配置控制),由独立服务提供图片向量化能力。

具体内容

  • 端口:clip-as-service 默认 51000CNCLIP_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.yamlservices.embedding 下配置(若存在 image 相关 backend);clip-as-service 默认模型由 embeddings/config.pyCLIP_AS_SERVICE_MODEL_NAME 控制,flow 配置在 third-party/clip-as-service/server/torch-flow-temp.yml

详见:docs/CNCLIP_SERVICE说明文档.mdembeddings/README.md


4. 翻译(Translation)

背景:原使用 DeepL,后迁移至 qwen-mt(如 qwen-mt-flash)。qwen-mt 云端限速约 RPM=60(每分钟 60 请求),此前未做大商品量压测,未暴露问题;高并发索引或查询场景下易触限。

当前方案

  • 统一 translator service:业务侧统一走 6006,按 model + scene 选择能力,不再存在翻译 provider 分支。
  • 配置入口config/config.yamlservices.translation,显式声明 service_urldefault_modeldefault_scene、各 capability 的 backendbase_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_attributestags,供索引与 suggest 使用。

具体内容

  • 接口POST /indexer/enrich-content(Indexer 服务端口 6004)。请求体为 items 数组,每项含 spu_idtitle(必填)及可选多语言标题等;单次请求最多 50 条,建议批量调用。响应 resultsitems 一一对应,每项含 spu_idqanchors(按语言键,如 qanchors.zhqanchors.en,逗号分隔短语)、enriched_attributestags
  • 索引侧:微服务组合方式下,调用方先拿不含 qanchors/tags 的 doc,再调用本接口补齐后写入 ES 的 qanchors.{lang} 等字段;索引 transformer(indexer/document_transformer.pyindexer/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.mddocs/搜索API对接指南-05-索引接口(Indexer).mdenrich-content 等)、api/routes/indexer.py(enrich-content 路由)。


二、架构

1. Translator Service 与动态选择翻译

  • 设计:翻译已从 provider 架构中独立出来,采用 一个 translator service + 多个 capability backend;配置单一来源为 config/config.yamlservices.translation 块,service_url / default_model / default_scene 不再接受环境变量静默覆盖。
  • 翻译(具体实现)
    • 业务入口translation.create_translation_client()
    • 服务编排translation/service.py
    • 后端实现translation/backends/qwen_mt.pytranslation/backends/llm.pytranslation/backends/deepl.pytranslation/backends/local_seq2seq.py
    • 调用方query/query_parser.pyindexer/incremental_service.pyindexer/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_PORTINDEXER_PORTFRONTEND_PORTEVAL_WEB_PORTEMBEDDING_TEXT_PORTEMBEDDING_IMAGE_PORTTRANSLATION_PORTRERANKER_PORTTEI_PORTCNCLIP_PORT
  • 命令
    • ./scripts/service_ctl.sh start [service...]up all / start all(all 含 tei、cnclip、embedding、embedding-image、translator、reranker、backend、indexer、frontend、eval-web,按依赖顺序);stoprestartdown 同参数;status 默认列出所有服务。
    • 启动时:backend/indexer/frontend/embedding/translator/reranker 会写 pid 到 logs/<service>.pid,并执行 wait_for_health(GET http://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.shLOG_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.pySuggestionIndexBuilder:从 ES 商品索引(含 titleqanchors)与查询日志等拉取数据,写入 versioned 建议索引并切换 alias。
  • 尚未完成的“增量机制”:指自动/事件驱动的增量(如商品变更或日志写入时自动刷新建议索引);当前 incremental 模式为“按 watermark 再跑一次构建”,仍为脚本主动触发,非持续增量流水线。
  • 依赖:suggest 候选依赖商品侧 内容理解字段(qanchors/tags);sources: ["query_log", "qanchor"] 表示候选来自查询日志与 qanchor;当前内容理解未全量跑完一轮,suggest 数据会随全量重建逐步完善。

详见:suggestion/builder.pysuggestion/ARCHITECTURE_V2.mdmain.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),在线高并发场景可优先考虑云后端。


并发 请求数 成功率 吞吐(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