Files
inkreach-official-website/docs/references/performance-review-public-port.md
T

9.7 KiB
Raw Blame History

public 端口性能审查报告(1w 瞬时并发请求口径)

  • 审查日期:2026-09-03
  • 审查对象:https://official.inkreach.cc 的公开访问链路(public 端口 = 边缘 nginx 80/443 → v2-api:3001 → v2-postgres
  • 审查口径:1w 瞬时并发请求——同一时刻 1 万个请求同时到达边缘(压力测试式,万 QPS 级)
  • 结论:当前形态不能承压,差距约 2~3 个数量级。瓶颈全部位于「配置与架构层」,与商品数据规模无关(goods 仅 240 行),改造后单机有希望在口径内达标,需压测实证。

1. 现状架构

单机(4 核 / 14GB / 无资源限额)docker compose 单栈 4 容器,全部单副本:

公网:80/443 (official.inkreach.cc)
  └─ deploy-admin-1 (边缘 nginx 1.27-alpine,官方默认主配置)
       ├─ /public/ /v2-api/ /uploads/ /assets/ ──► deploy-v2-api-1 (NestJS :3001)
       ├─ /v2/admin/ /v2/h5/ ──► deploy-v2-admin-1 (SPA 静态)
       └─ /admin/ /h5/ ──► try_files 本地静态
  deploy-v2-api-1 ──► deploy-v2-postgres-1 (postgres:16-alpine)

关键事实(均已核对源码/配置原文):

现状 出处
nginx worker worker_processes auto4 worker)× worker_connections 1024最多 4096 条客户端连接 容器内官方默认 nginx.confdeploy/nginx/admin.conf 仅覆盖 conf.d
边缘路由 /public/ 路径原样透传至 v2-api:3001 deploy/nginx/admin.conf L72-79
压缩 无 gzipJSON/JS/图片全裸传) nginx 默认 gzip 注释关闭;main.ts 无 compression 中间件
上游 keepalive 无(每请求新建到 v2-api 的 TCP 连接) admin.conf 无 upstream keepalive
限流 全局限流 120 req/min/IP apps/api/src/app.module.ts L27-32
API 连接池 Prisma 零配置 → 默认池 = 4核×2+1 = 9 条连接,排队默认 10s 后报错 apps/api/src/prisma/prisma.service.ts L12DATABASE_URL 无参数(compose L35
PG max_connections=100(默认)、无 statement_timeout、shared_buffers 默认 docker-compose.yml 未覆盖;postgres:16 默认
缓存 全链路零缓存(无 Redis/cache-manager/nginx proxy_cache 全仓 grep 零命中
同步任务 整点分类同步(长事务串行 ~226 分类)、03:30 详情全量同步 + 逐单族重算,与 public 同进程同池 apps/api/src/sync/sync.service.ts L106-114、L138-145
数据规模 goods 240 / origin_goods 542 / variants 12,155 / categories 243 / countries 12 生产导出 data-dump.json2026-08-22

2. 逐层瓶颈证据

2.1 边缘 nginx:第 0 层就爆(连接数硬顶 4096)

worker_connections 1024 × 4 worker = 4096 条并发客户端连接。HTTP/2 下每个浏览器占 1 条连接;1 万并发请求到场时,约 六成连接进不了 accept 队列(内核 backlog 默认 511,其余直接 reset/拒绝)。这是与后端优化无关的硬天花板。

2.2 API 层:单进程 + 9 连接池,直连 DB 吞吐 2050 req/s

  • GET /public/goods 无 SQL 分页findMany 不带 take/skip 全量拉取匹配行(public.service.ts L234),再内存分组、内存分页(L249-280)。数据量百级时可行,但每次请求的成本是「全表扫描 + 多表联表 + JS 排序」。
  • 每次请求两个全表聚合
    • loadFamilyMinPrices()L334-351):CROSS JOIN LATERAL jsonb_array_elements(price_matrix->'rows') 展开全部族(每族 ~11KB JSONB),/public/goods 每页与 /public/home-goods 每次都跑;注释实测同类全量扫描 ~330ms(L329-333)。
    • DEFAULT 排序额外 loadTreeOrderMeta()L287-307):全 countries + 全 categories 联表 raw SQL。
  • N+1 与串行链路
    • 分类树 getCategoriesTree:逐祖先串行 findUniqueL102-113)。
    • 详情 getGoodByFamilyId:3 条查询并发 + 响应内嵌整份 ~11KB price_matrix、全部变体 designDataresolveCategoryIcon 串行向上最多 10 次 findUniqueL552-565)。
  • keywordILIKE '%kw%'L199),无 pg_trgm 索引 → 必 seq scan(当前 240 行无感,量级放大后失效)。
  • 单请求 DB 成本合计 300500ms(列表)与 100300ms(详情),9 条连接串行化后:列表接口吞吐 ≈ 9 ÷ 0.4s ≈ 20~25 req/s,全端点混合 3060 req/s。

2.3 数据库层:无防护,池耗尽即排队超时

  • Prisma 池 9 < PG max_connections 100,但无任何超时参数:慢查询可无限期占住连接;同步长事务(分类同步单事务串行 ~226 分类、详情同步逐商品 upsert)与 public 抢同一池。
  • 池排队默认 10s 超时(P2028):1 万瞬时请求直连 DB 时,绝大多数请求排队 >10s 直接报错。
  • 无 statement_timeout,无连接池水位监控。

2.4 传输层:无 gzip、无缓存头

  • 详情响应内嵌 ~11KB price_matrix + 全部变体 designData;列表响应平均 ~2-5KB。按 20KB/响应粗算,1 万 req/s ≈ 1.6Gbps,可打满常见 1Gbps 出口带宽;gzip 后 JSON 可压 510 倍。
  • /uploads/ /assets/ 静态资源无任何 Cache-Controlmain.ts L73-81),每次访问重复下载。

2.5 全链路零缓存(杠杆最高的修复点)

分类树、国家、标签组、首页商品、商品列表、详情全部每次实时查库。数据变更频率为小时级同步syncCategories/syncProducts 整点跑),这意味着对 public 读路径引入分钟级 TTL 缓存几乎无损数据新鲜度,却能把 DB 热路径负载降 95%+。

2.6 同步任务竞争

整点分类同步长事务、03:30 详情全量同步 + 逐单族重算(fire-and-forget 进程内任务)与 public 共享同一 9 连接池。同步窗口内池被长事务/串行往返占满时,在线请求直接排队甚至超时。

2.7 压测陷阱:Throttler 429

全局限流 120 req/min/IPapp.module.ts L27-32)。真实 1 万用户分布在不同 IP 无影响;但单机/少 IP 压测流量会被 429 打满,压测必须使用分布式源(≥数十个出口 IP)或临时抬高 THROTTLE_LIMIT,否则测出来的是限流器而不是系统容量。

3. 容量估算与结论

上限 1w 瞬时并发需求 差距
nginx 连接数 4096 10000 ~2.4x
API 直连 DB 吞吐 ~30-60 req/s ~10000 req/s ~200-300x
出口带宽(无 gzip ~1 Gbps ~1.6 Gbps ~1.6x
PG 连接 100 9 池上限前置

结论:当前形态不能承压 1w 瞬时并发请求。即便并发被 nginx 放进来,DB 直连吞吐差两个数量级以上,池排队 10s 超时会把瞬时洪峰转为大面积 5xx。

方向:瓶颈 100% 属于「配置与架构层」——进程内存缓存(TTL 5~10min + 同步后失效)可把 DB 热路径负载降 ~95-99%nginx 连接数/gzip/keepalive/限流补齐后边缘可达 1w+ 连接;池参数与 statement_timeout 防排队超时与慢查询占池。改造后单机 4 核全缓存热路径(万级 req/s 简单 JSON 响应)有达标可能,但必须用分布式压测实证,达标口径见下。

4. 整改方向(摘要)

实施进度(2026-09-03P0-1/P0-2/P0-3 已在 refactor/public-capacity-10k-yeuimu 分支完成并全量测试通过(238/238)——进程内分域缓存 + 全写路径即时失效、nginx 主配置/keepalive/gzip/限流/缓存头、连接池与 PG 参数。尚未部署到生产(部署需按全局约束先备份存档、低峰 force-recreate/重建镜像);P1-3 压测基线(镜像栈 + 分布式源)为验收前置,未达标按计划扩展阶梯升级。

完整任务分解见 plans/refactor/public-capacity-10k-refactor.md

  • P0-1 进程内存缓存层(NestJS cache-manager 或等价实现):categories/countries/tags/tag-groups/home-goods/goods(全量物化+内存分页)/goods/:id/族最低价聚合/树序元数据;所有写路径(sync/族重算/admin 写/上传)提交后按域版本号主动失效(全局约束:等待 TTL 过期不是兜底)
  • P0-2 nginx 调优:worker_connections 16384worker_rlimit_nofile、upstream keepalive 64、gzip on、/uploads /assets 缓存头、limit_req 兜底、proxy 超时显式化
  • P0-3 连接与超时:DATABASE_URL?connection_limit=50&pool_timeout=3pool_timeout 单位为秒)、PG statement_timeout=10s、shared_buffers/effective_cache_size 调参
  • P1-1 /public/goods SQL 分页(take/skip + count
  • P1-2 同步任务与 public 隔离(错峰/批量化/独立 worker 开关)
  • P1-3 压测基线:一次性 docker postgres + 生产 dump 测关键 SQL 真实耗时;k6 分布式压测
  • P2 静态资源边缘直出、pg_trgm 索引、连接池水位监控告警

5. 验收口径(改造后)

  • 分布式压测(≥数十个出口 IP,或 THROTTLE_LIMIT 临时抬高):1 万并发瞬时请求下:
    • p95 延迟 < 300msCPU 侧),p99 < 1s
    • 错误率 < 0.1%,无 nginx 连接拒绝/重置
    • PG 连接水位不触顶(< 80%),无池排队超时
  • 公布达标数字(req/s、p95/p99、错误率)后视为验收通过;不达标则加 v2-api 副本(上游 keepalive 已就位,扩容仅需加容器)。

附:相关文件索引

  • 边缘路由:deploy/nginx/admin.conf
  • 编排:deploy/docker-compose.yml
  • 公开 API 实现:apps/api/src/public/public.controller.tsapps/api/src/public/public.service.ts
  • 入口中间件:apps/api/src/main.ts;限流:apps/api/src/app.module.ts
  • 连接池:apps/api/src/prisma/prisma.service.ts
  • 同步任务:apps/api/src/sync/sync.service.tsapps/api/src/product-families/family-recompute.service.ts
  • 数据规模:deploy/data-dump.json2026-08-22 导出)