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

122 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 auto`4 worker)× `worker_connections 1024`**最多 4096 条客户端连接** | 容器内官方默认 nginx.conf`deploy/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 吞吐 ~20~50 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`:逐祖先串行 `findUnique`L102-113)。
- 详情 `getGoodByFamilyId`:3 条查询并发 + 响应内嵌整份 ~11KB price_matrix、全部变体 designData`resolveCategoryIcon` 串行向上最多 10 次 findUniqueL552-565)。
- **`keyword``ILIKE '%kw%'`**L199),无 pg_trgm 索引 → 必 seq scan(当前 240 行无感,量级放大后失效)。
- 单请求 DB 成本合计 ~300~500ms(列表)与 ~100~300ms(详情),9 条连接串行化后:**列表接口吞吐 ≈ 9 ÷ 0.4s ≈ 20~25 req/s**,全端点混合 ~30~60 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 可压 5~10 倍。
- `/uploads/` `/assets/` 静态资源无任何 Cache-Control`main.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/IP`app.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-03**P0-1/P0-2/P0-3 已在 `refactor/public-capacity-10k-yeuimu` 分支完成并全量测试通过(238/238)——进程内分域缓存 + 全写路径即时失效、nginx 主配置/keepalive/gzip/限流/缓存头、连接池与 PG 参数。**已于 2026-09-03 08:38 部署到生产**(备份存档 `deploy/backups/20260903-083800-p0-perf-deploy/`,切换停机 23s):部署后实测——home-goods 首次 90ms/缓存命中 12ms;详情 247KB → gzip 23KB10.7x);静态资源 30d 缓存头生效;nginx 洪峰限流 429 生效且随窗口恢复(注意:单 IP 高频实测同时会打满 app 层 120 req/min 限流,属双层按设计工作);PG statement_timeout=10s/max_connections=200/shared_buffers=512MB 生效;行数 diff 零变化。**P1-3 压测基线(镜像栈 + 分布式源)为验收前置,未达标按计划扩展阶梯升级。**
完整任务分解见 [plans/refactor/public-capacity-10k-refactor.md](../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 16384``worker_rlimit_nofile`、upstream `keepalive 64`、gzip on、/uploads /assets 缓存头、limit_req 兜底、proxy 超时显式化
- **P0-3** 连接与超时:`DATABASE_URL?connection_limit=50&pool_timeout=3`pool_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.ts``apps/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.ts``apps/api/src/product-families/family-recompute.service.ts`
- 数据规模:`deploy/data-dump.json`2026-08-22 导出)