feat(aia): Complete AIA V2.0 with universal streaming capabilities

Major Changes:
- Add StreamingService with OpenAI Compatible format
- Upgrade Chat component V2 with Ant Design X integration
- Implement AIA module with 12 intelligent agents
- Update API routes to unified /api/v1 prefix
- Update system documentation

Backend (~1300 lines):
- common/streaming: OpenAI Compatible adapter
- modules/aia: 12 agents, conversation service, streaming integration
- Update route versions (RVW, PKB to v1)

Frontend (~3500 lines):
- modules/aia: AgentHub + ChatWorkspace (100% prototype restoration)
- shared/Chat: AIStreamChat, ThinkingBlock, useAIStream Hook
- Update API endpoints to v1

Documentation:
- AIA module status guide
- Universal capabilities catalog
- System overview updates
- All module documentation sync

Tested: Stream response verified, authentication working
Status: AIA V2.0 core completed (85%)
This commit is contained in:
2026-01-14 19:15:01 +08:00
parent 3d35e9c58b
commit 1b53ab9d52
386 changed files with 52096 additions and 65238 deletions

View File

@@ -1,115 +1,96 @@
# **Postgres-Only <20><EFBFBD><E588BB><EFBFBD><EFBFBD><E996AB><EFBFBD><EFBFBD>**
## **—— 面向微型 AI 团队的高可靠、低成本技术战略**
## **<EFBFBD><EFBFBD>?<3F><EFBFBD>敺桀<E695BA> AI <20><EFBFBD><EFBD81><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E888AB><EFBFBD><EFBFBD><EFBFBD>鞉𧋦<E99E89><F0A78BA6><EFBFBD><EFBFBD><E88880>?*
<EFBFBD><EFBFBD>𧋦嚗鯝1.0
适用场景1-2人初创团队、Node.js/Fastify 技术栈、阿里云 SAE 部署环境
核心目标:在不引入 Redis 的前提下,实现企业级的任务队列、缓存与会话管理,保障 2小时+ 长任务的绝对可靠性。
<EFBFBD><EFBFBD><EFBFBD>箸艶嚗?-2鈭箏<E988AD><E7AE8F>𥕦𣪧<F0A595A6><EFBFBD><E9BA84>ode.js/Fastify <20><><EFBFBD><EFBFBD><E88880><EFBFBD><EFBFBD><EFBFBD> SAE <20>函蔡<E587BD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>嚗𡁜銁銝滚<EFBFBD><EFBFBD>?Redis <20><><EFBFBD><EFBFBD>𣂷<EFBFBD><EFBFBD><E59A97><EFBFBD><EFBFBD>銝𡁶漣<F0A181B6><E6BCA3><EFBFBD><EFBFBD><E28ABF>𨰜<EFBFBD><F0A8B09C><EFBFBD>摮䀝<E691AE>隡朞<E99AA1>蝞∠<E89D9E>嚗䔶<E59A97><E494B6>?2撠𤩺𧒄+ <20>蹂遙<E8B982><EFBFBD>蝏嘥笆<E598A5><EFBFBD><E888AB><EFBFBD>?
## **1\. <20><EFBFBD><E689AF><EFBFBD> (Executive Summary)**
针对我方当前MAU \< 5000的业务规模与“稳定性优先”的战略诉求本方案主张采用 **"Postgres-Only" (全能数据库)** 架构。
<EFBFBD><EFBFBD><EFBFBD>烐䲮敶枏<EFBFBD>嚗㇈AU \< 5000嚗厩<E59A97>銝𡁜𦛚閫<F0A69B9A>芋銝𢛶<E98A9D>𦦵迅摰𡁏<E691B0><EFBFBD><E689BE><EFBFBD><EFBFBD><EFBFBD><E89098>条裦霂㗇<E99C82>嚗峕𧋦<E5B395><EFBFBD>銝餃<E98A9D><E9A483><EFBFBD> **"Postgres-Only" (<EFBFBD><EFBFBD><EFBFBD>唳旿摨?** <20><EFBFBD><E59786>?
<EFBFBD><EFBFBD><EFBFBD>拍鍂 PostgreSQL <20><><EFBFBD>蝥抒鸌<E68A92><EFBFBD>憒?SKIP LOCKED <20><><EFBFBD><EFBFBD><E5979A>SONB 摮睃<E691AE><E79D83><EFBFBD>nlogged Tables嚗㚁<E59A97><E39A81>睲賑<E79DB2>臭誑摰<E8AA91><E691B0><EFBFBD>蹂誨 Redis <20>?*隞餃𦛚<E9A483><EFBFBD>**<2A>?*蝻枏<E89DBB>**<2A>?*隡朞<E99AA1>摮睃<E691AE>**銝剔<E98A9D>雿𦦵鍂<F0A6A6B5>?
**<EFBFBD>条裦<EFBFBD><EFBFBD>嚗?*
通过利用 PostgreSQL 的高级特性(如 SKIP LOCKED 锁机制、JSONB 存储、Unlogged Tables我们可以完全替代 Redis 在**任务队列**、**缓存**、**会话存储**中的作用。
1. **<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗𡁶宏<F0A181B6>?Redis 銝剝𡢿隞塚<E99A9E>蝟餌<E89D9F>憭齿<E686AD>摨阡<E691A8>雿?50%<25>?
2. **<EFBFBD>唳旿撘箔<EFBFBD><EFBFBD>?*嚗帋<E59A97><E5B88B>⊥㺭<E28AA5><EFBFBD>隞餃𦛚<E9A483><EFBFBD><E59786><EFBFBD><EFBFBD>鈭见𦛚銝剜<E98A9D>鈭歹<E988AD>敶餃<E695B6><E9A483>寥膄<E5AFA5>𨅯<EFBFBD><EFBFBD><E692A3>鈭见𦛚<E8A781><EFBFBD><E597AA><EFBFBD>?
3. **<EFBFBD><EFBFBD>憭𡝗<EFBFBD><EFBFBD>?*嚗𡁜<E59A97><F0A1819C>函緵<E587BD>?RDS 韏<><E99F8F>嚗峕<E59A97>撟渲<E6929F><E6B8B2><EFBFBD><EFBFBD><E3BAAD><EFBFBD>銝剝𡢿隞嗉晶<E59789><EFBFBD>?
4. **隡<><E99AA1>蝥批虾<E689B9>?*嚗帋<E59A97><E5B88B>?RDS <20><><EFBFBD><EFBFBD>隞賭<E99A9E> PITR嚗<52>𧒄<EFBFBD><EFBFBD><E6B8A1><EFBFBD>嚗㕑<E59A97><E39591>𨥈<EFBFBD>靽嗪<E99DBD>隞餃𦛚<E9A483><EFBFBD><E7AC94>唳旿<E594B3>𨀣偶銝滢腺憭晦<E686AD><EFBFBD>?
## **2\. <20><EFBFBD><E6A185>峕艶銝擧<E98A9D><E693A7>?*
**战略收益:**
### **2.1 敶枏<E695B6><E69E8F>𤤿<EFBFBD>嚗𡁻鵭隞餃𦛚<E9A483><F0A69B9A><EFBFBD>撘望<E69298>?*
1. **架构极简**:移除 Redis 中间件,系统复杂度降低 50%。
2. **数据强一致**:业务数据与任务状态在同一事务中提交,彻底根除“分布式事务”风险。
3. **零额外成本**:复用现有 RDS 资源,每年节省数千元中间件费用。
4. **企业级可靠**:依托 RDS 的自动备份与 PITR时间点恢复能力保障任务队列数据“永不丢失”。
## **2\. 问题背景与挑战**
### **2.1 当前痛点:长任务的脆弱性**
我们的业务涉及“文献全库解析”和“双模型交叉验证”,单次任务耗时可能长达 **2小时**
* **现状**使用内存队列MemoryQueue
* **风险**:在 Serverless (SAE) 环境下,实例可能因无流量缩容、发布更新或内存溢出而随时销毁。一旦销毁,内存中的任务进度即刻丢失,导致用户任务失败。
### **2.2 常见误区:只有 Redis 能救命?**
业界常见的观点认为:“必须引入 Redis (BullMQ) 才能实现任务持久化。”
* **反驳**:这是惯性思维。任务持久化的核心是\*\*“持久化存储”\*\*,而非 Redis 本身。PostgreSQL 同样具备持久化能力,且在事务安全性上优于 Redis。
<EFBFBD>睲賑<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>𪙛<EFBFBD>𨀣<EFBFBD><EFBFBD><EFBFBD>摨栞圾<EFBFBD><EFBFBD><EFBFBD><EFBFBD>𨅯<EFBFBD><EFBFBD>鈭文<EFBFBD>撉諹<EFBFBD><EFBFBD><EFBFBD><EFBFBD>閙活隞餃𦛚<EFBFBD>埈𧒄<EFBFBD><EFBFBD><EFBFBD>輯噢 **2撠𤩺𧒄**<EFBFBD>?
* **<2A>啁𠶖**嚗帋蝙<E5B88B><EFBFBD>摮㗛<E691AE><E3979B><EFBFBD>MemoryQueue嚗剹<E59A97>?
* **憌𡡞埯**嚗𡁜銁 Serverless (SAE) <20><EFBFBD>銝页<E98A9D>摰硺<E691B0><E7A1BA><EFBFBD><E888AA><EFBFBD><EFBFBD><E7989A>蝻拙捆<E68B99><E68D86><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E594B3><EFBFBD><EFBFBD><EFBCB7><EFBFBD><E5B1B8><EFBFBD><EFBFBD><E798A5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E798A5><EFBFBD><EFBFBD><EFBFBD>銝剔<E98A9D>隞餃𦛚餈𥕦漲<F0A595A6><EFBFBD>仃嚗<E4BB83><EFBFBD>渡鍂<E6B8A1>瑚遙<E7919A>仃韐乓<E99F90>?
### **2.2 撣貉<E692A3>霂臬躹嚗𡁜蘨<F0A1819C>?Redis <20><EFBFBD><E8B3A3><EFBFBD>**
銝𡁶<EFBFBD>撣貉<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>寡恕銝綽<EFBFBD><EFBFBD>𨅯<EFBFBD>憿餃<EFBFBD><EFBFBD>?Redis (BullMQ) <20><EFBFBD>摰䂿緵隞餃𦛚<E9A483><F0A69B9A><EFBFBD><EFBFBD><EFBFBD><E7A194><EFBFBD>?
* **<2A>漤底**嚗朞<E59A97><E69C9E><EFBFBD><E88880><EFBFBD>萘輕<E89098><E8BC95><EFBFBD><EFBFBD><EFBFBD><E98A8B><EFBFBD><EFBFBD>瓲敹<E793B2>糓\*\*<2A>𨀣<EFBFBD><EFBFBD><E98A8B>摮睃<E691AE><E79D83>𩄼*\*嚗諹<E59A97><EFBFBD> Redis <20>祈澈<E7A588><E6BE88>ostgreSQL <20>峕甅<E5B395><EFBFBD><E79195><EFBFBD><EFBFBD><EFBFBD>𤥁<EFBFBD><F0A4A581>𨥈<EFBFBD>銝𥪜銁鈭见𦛚摰匧<E691B0><E58CA7><EFBFBD>隡䀝<E99AA1> Redis<69>?
## **3\. <20><EFBFBD><EFBFBD><E996AB><EFBFBD><EFBFBD>嚗䥪ostgres-Only <20><EFBFBD>**
本方案将 Redis 的三大核心功能(队列、缓存、会话)全部收敛至 PostgreSQL
### **3.1 替代 Redis 队列:使用 pg-boss**
我们引入 Node.js 库 **pg-boss**,它利用 PostgreSQL 的 FOR UPDATE SKIP LOCKED 特性,实现了高性能的抢占式队列。
<EFBFBD>祆䲮獢<EFBFBD><EFBFBD> Redis <EFBFBD><EFBFBD><EFBFBD>憭扳瓲敹<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>摮塩<EFBFBD><EFBFBD><EFBFBD>霂嘅<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?PostgreSQL<EFBFBD>?
### **3.1 <20>蹂誨 Redis <20><EFBFBD>嚗帋蝙<E5B88B>?pg-boss**
<EFBFBD>睲賑撘訫<EFBFBD> Node.js 摨?**pg-boss**嚗<><E59A97><EFBFBD>拍鍂 PostgreSQL <20>?FOR UPDATE SKIP LOCKED <20><EFBFBD><EFBFBD>摰䂿緵鈭<E7B7B5><E988AD><EFBFBD><EFBFBD><E689AF><EFBFBD>𦜖<EFBFBD><EFBFBD><E683A9><EFBFBD><E7AC94>?
#### **<2A><EFBFBD><E59786><EFBFBD>**
1. **入队**API 接收请求将任务元数据JSON写入 job 表。**此操作在毫秒级完成,数据立即安全落盘。**
2. **处理**Worker 进程从数据库捞取任务,并锁定该行记录。
3. **容灾**:如果 SAE 实例在处理过程中崩溃(如 OOM数据库锁会在超时后自动释放其他存活的 Worker 实例会立即接管该任务重试。
1. **<EFBFBD>仿<EFBFBD>**嚗鋫PI <20>交𤣰霂瑟<E99C82><EFBFBD><E59A97>隞餃𦛚<E9A483><F0A69B9A><EFBFBD><EFBFBD>JSON嚗匧<E59A97><E58CA7>?job 銵具<E98AB5>?*甇斗<E79487>雿𨅯銁瘥怎<E798A5>蝥批<E89DA5><E689B9><EFBFBD><E7909C>唳旿蝡见朖摰匧<E691B0><E58CA7><EFBFBD><E8B39C>?*
2. **<EFBFBD><EFBFBD>**嚗阳orker 餈𤤿<E9A488>隞擧㺭<E693A7><EFBFBD><E6A180>𧼮<EFBFBD>隞餃𦛚嚗<F0A69B9A><EFBFBD><E5838E><EFBFBD>霂亥<E99C82>霈啣<E99C88><E595A3>?
3. **摰寧<EFBFBD>**嚗𡁜<E59A97><F0A1819C>?SAE 摰硺<E691B0><E7A1BA><EFBFBD><E585B8><EFBFBD><EFBFBD>蝔衤葉撏拇<E6928F><EFBFBD><E59A97> OOM嚗㚁<E59A97><E39A81>唳旿摨㯄<E691A8>隡𡁜銁頞<E98A81>𧒄<EFBFBD>舘䌊<E88898><EFBFBD><E588B8><EFBFBD><E6A998><EFBFBD>摮䀹暑<E480B9>?Worker 摰硺<E691B0>隡𡁶<E99AA1><F0A181B6>單𦻖蝞∟砲隞餃𦛚<E9A483><EFBFBD><E6BBA9>?
#### **隞<><E99A9E>摰䂿緵<E482BF><E7B7B5><EFBFBD>**
import PgBoss from 'pg-boss';
const boss \= new PgBoss({
connectionString: process.env.DATABASE\_URL,
schema: 'job\_queue', // 独立Schema,不污染业务表
max: 5 // 并发控制,保护 DeepSeek API
schema: 'job\_queue', // <EFBFBD><EFBFBD>Schema嚗䔶<EFBFBD>瘙⊥<EFBFBD>銝𡁜𦛚銵?
max: 5 // 撟嗅<EFBFBD><EFBFBD><EFBFBD>嚗䔶<EFBFBD><EFBFBD>?DeepSeek API
});
await boss.start();
// 消费者定义 (Worker)
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD>銋?(Worker)
await boss.work('screening-task', {
// 关键配置:设置锁的有效期为 4小时
// 即使任务跑 3.9小时,只要 Worker 活着,就不会被抢走
// 如果 Worker 死了,锁过期,任务自动重试
// <EFBFBD>喲睸<EFBFBD>滨蔭嚗朞挽蝵桅<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>銝?4撠𤩺𧒄
// <EFBFBD>喃蝙隞餃𦛚頝?3.9撠𤩺𧒄嚗<EFBFBD>蘨閬?Worker 瘣餌<E798A3><EFBFBD>停銝滢<E98A9D>鋡急𦜖韏?
// <EFBFBD><EFBFBD> Worker 甇颱<EFBFBD>嚗屸<EFBFBD><EFBFBD><EFBFBD>嚗䔶遙<EFBFBD>∟䌊<EFBFBD><EFBFBD>霂?
expireInSeconds: 14400,
retryLimit: 3
}, async (job) \=\> {
// 銝𡁜𦛚<F0A1819C><EFBFBD>...
});
### **3.2 替代 Redis 缓存:基于 Table KV 存储**
对于 AI 结果缓存(避免重复调用 LLMPostgres 的查询速度1-3ms对于用户体验秒级等待来说完全可以接受。
### **3.2 <EFBFBD>蹂誨 Redis 蝻枏<EFBFBD>嚗𡁜抅鈭?Table <EFBFBD>?KV 摮睃<EFBFBD>**
撖嫣<EFBFBD> AI 蝏𤘪<E89D8F>蝻枏<E89DBB><EFBFBD><E59A97><EFBFBD><EFBFBD>憭滩<E686AD><E6BBA9>?LLM嚗㚁<E59A97>Postgres <20><>䰻霂<E99C82>笔漲嚗?-3ms嚗匧笆鈭𡒊鍂<F0A1928A><EFBFBD>撉䕘<E69289>蝘垍漣蝑匧<E89D91>嚗㗇䔉霂游<E99C82><E6B8B8>典虾隞交𦻖<E4BAA4>𨰜<EFBFBD>?
#### **<2A><EFBFBD>霈箄<E99C88>**
```
实际并发分析:
- 当前规模: 500 MAU
- 峰值并发: < 50 QPS极端情况
- Postgres能力: 5万+ QPS简单查询
- 性能余量: 1000倍
响应时间对比:
- Redis: 0.15ms(网络+读取)
- Postgres: 1.5ms(网络+查询)
- 差异: 1.35ms
- 用户感知: 无总耗时200ms中占比 < 1%
摰鮋<EFBFBD>撟嗅<EFBFBD><EFBFBD><EFBFBD><EFBFBD>嚗?- 敶枏<E695B6><EFBFBD>芋: 500 MAU
- 撜啣<EFBFBD>澆僎<EFBFBD>? < 50 QPS嚗<EFBFBD><EFBFBD>蝡舀<EFBFBD><EFBFBD><EFBFBD>
- Postgres<EFBFBD><EFBFBD>: 5銝? QPS嚗<53><E59A97><EFBFBD>閙䰻霂<E99C82>
- <EFBFBD><EFBFBD>雿䠷<EFBFBD>: 1000<30>?
<EFBFBD><EFBFBD><EFBFBD>園𡢿撖寞<EFBFBD>嚗?- Redis: 0.15ms嚗<EFBFBD><EFBFBD>蝏?霂餃<E99C82>嚗?- Postgres: 1.5ms嚗<EFBFBD><EFBFBD>蝏?<3F>亥砭嚗?- 撌桀<E6928C>: 1.35ms
- <20><EFBFBD><E586BD>毺䰻: <20>𩤃<EFBFBD><F0A9A483><EFBFBD>埈𧒄200ms銝剖<E98A9D>瘥?< 1%嚗?
蝏栞捏嚗𡁜銁<EFBFBD>交暑10銝<EFBFBD>誑銝页<EFBFBD>Postgres<EFBFBD><EFBFBD><EFBFBD><EFBFBD>憭毺鍂
```
#### **数据库设计**
#### **<EFBFBD>唳旿摨栞挽霈?*
```prisma
model AppCache {
id Int @id @default(autoincrement())
key String @unique
value Json // 对应 Redis Value
expiresAt DateTime // 对应 Redis TTL
value Json // 撖孵<EFBFBD> Redis <EFBFBD>?Value
expiresAt DateTime // 撖孵<EFBFBD> Redis <EFBFBD>?TTL
createdAt DateTime @default(now())
@@index([expiresAt]) // 索引用于快速清理过期数据
@@index([key, expiresAt]) // 复合索引优化查询
@@index([expiresAt]) // <EFBFBD><EFBFBD><EFBFBD>敹恍<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? @@index([key, expiresAt]) // 憭滚<E686AD><E89D9D>隡睃<E99AA1><E79D83>亥砭
@@map("app_cache")
}
```
#### **封装 Service(完整版)**
#### **<EFBFBD><EFBFBD> Service<EFBFBD><EFBFBD><EFBFBD><EFBFBD>嚗?*
```typescript
// <20><>辣嚗颹ackend/src/common/cache/PostgresCacheAdapter.ts
@@ -121,8 +102,7 @@ import { logger } from '../logging/index';
export class PostgresCacheAdapter implements CacheAdapter {
/**
* 获取缓存(带懒惰删除)
*/
* <EFBFBD><EFBFBD>蝻枏<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>𣳇膄嚗? */
async get<T = any>(key: string): Promise<T | null> {
try {
const record = await prisma.appCache.findUnique({
@@ -131,10 +111,8 @@ export class PostgresCacheAdapter implements CacheAdapter {
if (!record) return null;
// 检查是否过期
if (record.expiresAt < new Date()) {
// 懒惰删除:顺手清理(异步,不阻塞)
this.deleteAsync(key);
// <EFBFBD><EFBFBD>交糓<EFBFBD>西<EFBFBD><EFBFBD>? if (record.expiresAt < new Date()) {
// <20><EFBFBD><E59F9D>𣳇膄嚗𡁻◇<F0A181BB>𧢲<EFBFBD><F0A7A2B2><EFBFBD><EFBFBD><EFBFBD>郊嚗䔶<E59A97><E494B6><EFBFBD>嚗? this.deleteAsync(key);
return null;
}
@@ -203,12 +181,11 @@ export class PostgresCacheAdapter implements CacheAdapter {
}
/**
* 清空所有缓存
*/
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>摮? */
async flush(): Promise<void> {
try {
await prisma.appCache.deleteMany({});
logger.info('[PostgresCache] 缓存已清空');
logger.info('[PostgresCache] 蝻枏<EFBFBD>撌脫<EFBFBD>蝛?);
} catch (error) {
logger.error('[PostgresCache] <EFBFBD>', { error });
}
@@ -216,13 +193,11 @@ export class PostgresCacheAdapter implements CacheAdapter {
}
/**
* 启动定时清理任务(分批清理,防止阻塞)
*/
* <EFBFBD>臬𢆡摰𡁏𧒄皜<EFBFBD><EFBFBD>隞餃𦛚嚗<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>脫迫<EFBFBD><EFBFBD>嚗? */
export function startCacheCleanupTask() {
setInterval(async () => {
try {
// 每次只删除1000条过期数据
const result = await prisma.$executeRaw`
// 瘥𤩺活<EFBFBD><EFBFBD><EFBFBD>?000<30><EFBFBD><E2889F><EFBFBD><EFBFBD>? const result = await prisma.$executeRaw`
DELETE FROM app_cache
WHERE id IN (
SELECT id FROM app_cache
@@ -238,96 +213,80 @@ export function startCacheCleanupTask() {
} catch (error) {
logger.error('[PostgresCache] 𡁏𧒄<EFBFBD><EFBFBD>', { error });
}
}, 60000); // 每分钟执行一次
logger.info('[PostgresCache] 定时清理任务已启动每分钟1000条');
}, 60000); // 瘥誩<EFBFBD><EFBFBD><EFBFBD><EFBFBD>銵䔶<EFBFBD>甈?
logger.info('[PostgresCache] 𡁏𧒄<EFBFBD><EFBFBD>𦛚<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?000<EFBFBD><EFBFBD>');
}
```
#### **性能优化技巧**
#### **<EFBFBD><EFBFBD>隡睃<EFBFBD><EFBFBD><EFBFBD>撌?*
1. **蝝<E89D9D>隡睃<E99AA1>**嚗䫤@@index([key, expiresAt])` 閬<><E996AC><EFBFBD>亥砭嚗峕<E59A97><E5B395><EFBFBD><EFBFBD>噼”
2. **懒惰删除**:读取时顺便清理,分散负载
3. **分批清理**每次LIMIT 1000毫秒级完成
4. **连接池复用**Prisma自动管理无额外开销
2. **<EFBFBD><EFBFBD><EFBFBD>𣳇膄**嚗朞粉<E69C9E>𡝗𧒄憿箔噶皜<E599B6><E79A9C><EFBFBD><E59A97><EFBFBD><EFBFBD><EFBFBD>頧?3. **<EFBFBD><EFBFBD>鸌皜<EFBFBD><EFBFBD>**嚗𡁏<E59A97>甈‥IMIT 1000嚗峕神蝘垍漣摰峕<E691B0>
4. **餈墧𦻖瘙惩<EFBFBD><EFBFBD>?*嚗䥪risma<6D>芸𢆡蝞∠<E89D9E>嚗峕<E59A97>憸嘥<E686B8><EFBFBD><E69298><EFBFBD>
### **3.3 <20>蹂誨 Redis 隡朞<E99AA1>嚗䬙onnect-pg-simple**
使用成熟的社区方案,将 Session 存储在 Postgres session 表中。SAE 多实例重启后,用户无需重新登录。
## **4\. 深度对比:为什么 Postgres 胜出?**
雿輻鍂<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>箸䲮獢<EFBFBD><EFBFBD>撠?Session 摮睃<EFBFBD><EFBFBD>?Postgres <EFBFBD>?session 銵其葉<EFBFBD><EFBFBD>AE 憭𡁜<E686AD>靘钅<E99D98><E99285><EFBFBD>嚗𣬚鍂<F0A3AC9A><EFBFBD><E7919F><EFBFBD><EFBFBD>齿鰵<E9BDBF><EFBFBD><E9A483>?
## **4\. 瘛勗漲撖寞<E69296>嚗帋蛹隞<E89BB9>銋?Postgres <20>𨅯枂嚗?*
| 蝏游漲 | <20><EFBFBD> A: 隡删<E99AA1> Redis (BullMQ) | <20><EFBFBD> B: Postgres (pg-boss) | <20><EFBFBD><E79181><EFBFBD> |
| :---- | :---- | :---- | :---- |
| **数据一致性** | **弱** (双写一致性难题) 任务在 Redis业务在 DB。若 DB 事务回滚Redis 任务可能无法回滚。 | **** (事务级原子性) 任务入队与业务数据写入在同一个 DB 事务中。要么全成,要么全败。 | **Postgres** |
| **运维复杂度** | **** 需维护 Redis 实例、VPC 白名单、监控内存碎片率、持久化策略。 | **零** 复用现有 RDS。备份、监控、扩容全由阿里云 RDS 托管。 | **Postgres** |
| **备份与恢复** | **困难** Redis RDB/AOF 恢复可能会丢失最后几秒的数据。 | **完美** RDS 支持 PITR (按时间点恢复)。误删任务可精确回滚到 1秒前。 | **Postgres** |
| **成本** | **¥1000+/年** (Tair 基础版) | **¥0** (资源复用) | **Postgres** |
| **性能 (TPS)** | **极高** (10w+) | **** (5000+) 对于日均几万次 AI 调用的场景Postgres 性能绰绰有余。 | **Postgres** |
| **锁竞争问题** | **误解** 读写都需要网络往返高并发下Redis也会有竞争 | **真相** SELECT是快照读不加锁。Node.js单线程会先成为瓶颈。 | **误解澄清** |
| **缓存清理风险** | **存在** 内存溢出需要配置eviction策略不当配置会导致数据丢失 | **可控** 分批删除LIMIT 1000+ 懒惰删除,永远不会阻塞。 | **Postgres** |
| **学习曲线** | **陡峭** 需要学习Redis、BullMQ、ioredis、持久化策略、内存管理 | **平缓** 只需学习pg-bossAPI类似BullMQ其余都是熟悉的Postgres | **Postgres** |
| **<EFBFBD>唳旿銝<EFBFBD><EFBFBD><EFBFBD>?* | **撘?* (<28><><EFBFBD><EFBFBD><E98A9D><EFBFBD>折𠗕憸? 隞餃𦛚<E9A483>?Redis嚗䔶<E59A97><E494B6>銁 DB<44><42>𥅾 DB 鈭见𦛚<E8A781><EFBFBD>嚗朙edis 隞餃𦛚<E9A483><EFBFBD><E888AA><EFBFBD><E4ADBE><EFBFBD><E5A2A7>?| **撘?* (鈭见𦛚蝥批<E89DA5>摮鞉<E691AE>? 隞餃𦛚<E9A483>仿<EFBFBD>銝𦒘<E98A9D><F0A69298>⊥㺭<E28AA5><EFBFBD><E6A180>亙銁<E4BA99><EFBFBD>銝?DB 鈭见𦛚銝准<E98A9D><E58786><EFBFBD><EFBFBD><E98A8B><EFBFBD><EFBFBD><EFBFBD><E996AC><EFBFBD>刻揖<E588BB>?| **Postgres** |
| **餈鞟輕憭齿<EFBFBD>摨?* | **擃?* <20><>蝏湔擪 Redis 摰硺<E691B0><E7A1BA><EFBFBD>PC <20><EFBFBD><E8B3A2>𨰻<EFBFBD><F0A8B0BB><EFBFBD><EFBFBD><EFBFBD>摮条<E691AE><E69DA1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E98A8B>蝑𣇉裦<F0A38789>?| **<EFBFBD>?* 憭滨鍂<E6BBA8><EFBFBD> RDS<44><53><EFBFBD>隞賬<E99A9E><E8B3AC><EFBFBD><EFBFBD><EFBFBD><E689BC><EFBFBD>摰孵<E691B0><E5ADB5>梢燵<E6A2A2><EFBFBD> RDS <20>条恣<E69DA1>?| **Postgres** |
| **<EFBFBD>遢銝擧<EFBFBD>憭?* | **<EFBFBD>圈𠗕** Redis RDB/AOF <EFBFBD><EFBFBD><EFBFBD><EFBFBD>隡帋腺憭望<EFBFBD><EFBFBD>𤾸<EFBFBD>蝘垍<EFBFBD><EFBFBD>唳旿<EFBFBD>?| **摰𣬚<EFBFBD>** RDS <EFBFBD><EFBFBD> PITR (<EFBFBD>㗇𧒄<EFBFBD><EFBFBD><EFBFBD><EFBFBD>)<29><><EFBFBD>牐遙<E78990>虾蝎曄<E69B84><EFBFBD><E5A2A7>?1蝘鍦<E89D98><E98DA6>?| **Postgres** |
| **<EFBFBD>鞉𧋦** | **瞼1000+/撟?* (Tair <EFBFBD><EFBFBD><EFBFBD>? | **瞼0** (<EFBFBD><EFBFBD>憭滨鍂) | **Postgres** |
| **<EFBFBD><EFBFBD> (TPS)** | **<EFBFBD><EFBFBD><EFBFBD>** (10w+) | **擃?* (5000+) 撖嫣<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>甈?AI 靚<><EFBFBD><E98D82><EFBFBD><EFBFBD>Postgres <20><EFBFBD>蝏啁趕<E59581><EFBFBD><E58A90>?| **Postgres** |
| **<EFBFBD><EFBFBD><EFBFBD>鈭厰䔮憸?* | **霂航圾** 霂餃<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝏𨅯<EFBFBD>餈䈑<EFBFBD>擃睃僎<EFBFBD><EFBFBD>Redis銋煺<EFBFBD><EFBFBD><EFBFBD>鈭?| **<EFBFBD>毺㮾** SELECT<EFBFBD>臬翰<EFBFBD>扯粉嚗䔶<EFBFBD><EFBFBD>𣳇<EFBFBD><EFBFBD><EFBFBD>ode.js<6A>閧瑪蝔衤<E89D94><E8A1A4><EFBFBD><EFBFBD>銝箇𣂎憸<F0A3828E><E686B8>?| **霂航圾瞉<E59CBE><E79E89>** |
| **蝻枏<EFBFBD><EFBFBD><EFBFBD>憌𡡞埯** | **摮睃銁** <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝵容viction蝑𣇉裦嚗䔶<EFBFBD>敶㯄<EFBFBD>蝵桐<EFBFBD>撖潸稲<EFBFBD>唳旿銝仃 | **<EFBFBD>舀綉** <20><><EFBFBD>𣳇膄嚗𡿨IMIT 1000嚗? <20><EFBFBD><E59F9D>𣳇膄嚗峕偶餈靝<E9A488>隡𡁻獈憛𠺶<E6869B>?| **Postgres** |
| **摮虫<EFBFBD><EFBFBD>脩瑪** | **<EFBFBD>陪** <20><><EFBFBD>郎銋袠edis<EFBFBD><EFBFBD>ullMQ<EFBFBD><EFBFBD>oredis<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝑𣇉裦<EFBFBD><EFBFBD><EFBFBD>摮条恣<EFBFBD>?| **撟喟<EFBFBD>** <EFBFBD><EFBFBD>摮虫<EFBFBD>pg-boss嚗㇁PI蝐颱撮BullMQ嚗㚁<EFBFBD><EFBFBD><EFBFBD><EFBFBD>賣糓<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ostgres | **Postgres** |
### **撣貉<E692A3>霂航圾瞉<E59CBE><E79E89>**
#### **误解1Postgres并发性能差**
#### **霂航圾1嚗䥪ostgres撟嗅<EFBFBD><EFBFBD><EFBFBD>撌?*
```
事实:
- Postgres可处理5万+ QPS简单查询
鈭见<EFBFBD>嚗?- Postgres<65><EFBFBD><E887AC>?銝? QPS嚗<53><E59A97><EFBFBD>閙䰻霂<E99C82>
- <20><EFBFBD>摰鮋<E691B0>撟嗅<E6929F>: < 50 QPS
- SELECT<43>臬翰<E887AC>扯粉嚗㇈VCC嚗㚁<E59A97><E39A81>𣳇<EFBFBD>蝡硺<E89DA1>
- Node.js单线程1-2万QPS上限会先成为瓶颈
- Node.js<EFBFBD>閧瑪蝔页<EFBFBD>1-2銝𣘗PS銝𢠃<E98A9D>嚗劐<E59A97><E58A90><EFBFBD><EFBFBD>銝箇𣂎憸?
蝏栞捏嚗䥪ostgres銝齿糓<EFBFBD><EFBFBD>
```
#### **误解2DELETE会锁表阻塞**
#### **霂航圾2嚗鋽ELETE隡𡁻<EFBFBD>銵券獈憛?*
```
事实:
- DELETE是行级锁不是表锁
- LIMIT 1000毫秒级完成~5ms
- 配合懒惰删除,大部分过期数据在读取时已删除
- 即使有积压每分钟1000条1小时可清理6万条
鈭见<EFBFBD>嚗?- DELETE<54><EFBFBD>蝥折<E89DA5>嚗䔶<E59A97><E494B6>航”<E888AA>?- LIMIT 1000嚗峕神蝘垍漣摰峕<E691B0>嚗ǚ5ms嚗?- <20><EFBFBD><E6BB9A><EFBFBD><E59F9D>𣳇膄嚗<E88684><EFBFBD><EFBFBD><EFBFBD><E9A488><EFBFBD>唳旿<E594B3>刻粉<E588BB>𡝗𧒄撌脣<E6928C><E884A3>?- <20>喃蝙<E59683>厩妖<E58EA9><EFBFBD>瘥誩<E798A5><E8AAA9>?000<30><EFBFBD>1撠𤩺𧒄<F0A4A9BA><EFBFBD><E88880>?銝<>
结论:不会阻塞
```
蝏栞捏嚗帋<EFBFBD>隡𡁻獈憛?```
#### **霂航圾3嚗鑹edis<69><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD>摰𡁜翰**
```
事实:
- Redis: 网络延迟0.1ms + 读取0.05ms = 0.15ms
鈭见<EFBFBD>嚗?- Redis: 蝵𤑳<E89DB5>撱嗉<E692B1>0.1ms + 霂餃<E99C82>0.05ms = 0.15ms
- Postgres: 蝵𤑳<E89DB5>撱嗉<E692B1>0.5ms + <20>亥砭1ms = 1.5ms
- 撌桀<E6928C>: 1.35ms
- 但是总响应时间(含业务逻辑): 200ms
- 用户感知差异: 0%1.35/200 < 1%
-<><EFBFBD><EFBFBD>摨娍𧒄<E5A88D><EFBFBD><E6B99B><EFBFBD><E6809D><EFBFBD><EFBFBD>嚗? 200ms
- <20><EFBFBD><E586BD>毺䰻撌桀<E6928C>: 0%嚗?.35/200 < 1%嚗?
蝏栞捏嚗𡁏<EFBFBD><EFBFBD>撌桀<EFBFBD><EFBFBD>函鍂<EFBFBD><EFBFBD>撉䔶葉<EFBFBD><EFBFBD><EFBFBD>?```
结论:性能差异在用户体验中无感知
```
## **5\. <20><><EFBFBD>?撠𤩺𧒄<F0A4A9BA>蹂遙<E8B982><EFBFBD><EFBFBD><E89098><EFBFBD><E888AB><EFBFBD><E689AF>?*
## **5\. 针对“2小时长任务”的可靠性证明**
韐函<EFBFBD>嚗䥪ostgres <20><EFBFBD><E6AFBA><EFBFBD>霂?2 撠𤩺𧒄<F0A4A9BA><F0A79284><EFBFBD><EFBFBD>銝剜鱏<E5899C><EFBFBD>
<EFBFBD><EFBFBD>嚗?
1. **<2A><><EFBFBD><EFBFBD><EFBFBD><E7A2B6>?*嚗帋遙<E5B88B><EFBFBD><E288A9><EFBFBD>鈭歹<E988AD>API餈𥪜<E9A488> 200 OK嚗㚁<E59A97><E39A81><EFBFBD><E596B3><E4BAA6><EFBFBD><E5A1A9>朖雿?SAE <20><>黎銝衤<E98A9D>蝘鍦<E89D98><E98DA6><EFBFBD>隞餃𦛚霈啣<E99C88>靘萘<E99D98><E89098>冽㺭<E586BD><EFBFBD>銝准<E98A9D>?
2. **撏拇<E6928F><E68B87><EFBFBD><EFBCB7><EFBFBD>**嚗?
* **甇<><EFBFBD><E8999C><EFBFBD>**嚗阳orker <20><><EFBFBD>隞餃𦛚 \-\> <20><EFBFBD> 2 撠𤩺𧒄 \-\> <20>𣂷漱蝏𤘪<E89D8F> \-\> <20><>扇摰峕<E691B0><E5B395>?
* **撘<><EFBFBD><E8999C><EFBFBD> (SAE 蝻拙捆)**嚗阳orker <20><EFBFBD><E689AF>?1 撠𤩺𧒄鋡恍<E98BA1>瘥?\-\> <20>唳旿摨㯄<E691A8><E3AF84>?4 撠𤩺𧒄<F0A4A9BA><EFBFBD><E88898>?\-\> pg-boss 摰<>擪餈𤤿<E9A488><EFBFBD>瘚见<E7989A><EFBFBD><E9A488> \-\> 撠<><EFBFBD><EFBFBD><E28ABF><EFBFBD>霈唬蛹 Pending \-\> <20>?Worker 憸<><E686B8><EFBFBD><EFBFBD><E6BBA9>?
3. **<2A><EFBFBD>蝏凋<E89D8F>**嚗阳orker <20><EFBFBD><E887AC><EFBFBD><EFBFBD><EFBFBD><E68692> 10 <20><><EFBFBD>嚗㗇凒<E39787>唳㺭<E594B3><EFBFBD>銝剔<E98A9D> progress 摮埈挾<E59F88><E68CBE><EFBFBD>霂閙𧒄霂餃<E99C82> progress嚗䔶<E59A97><E494B6><EFBFBD>蝏抒賒<E68A92><EFBFBD><E689AF>?
**蝏栞捏**嚗𡁻<E59A97><F0A181BB>?pg-boss <20><>香靽⊿<E99DBD><E28ABF><EFBFBD>Dead Letter嚗匧<E59A97><E58CA7><EFBFBD>蝑𣇉裦嚗<E8A3A6><EFBFBD><EFBFBD><EFBFBD><E68A92>𣬚<EFBFBD><F0A3AC9A><EFBFBD>鈭?Redis嚗<73><E59A97>銝?Redis <20><><EFBFBD>枂憌𡡞埯<F0A1A19E>游之嚗剹<E59A97>?
## **6\. 摰墧鴌頝舐瑪<E88890>?*
质疑Postgres 真的能保证 2 小时的任务不中断吗?
证明:
### **<2A>嗆挾1嚗帋遙<E5B88B><EFBFBD><E28ABF>埈㺿<E59F88>𩤃<EFBFBD>Week 1嚗?*
1. **持久化保障**任务一旦提交API返回 200 OK即写入硬盘。即使 SAE 集群下一秒全灭,任务记录依然在数据库中。
2. **崩溃恢复机制**
* **正常情况**Worker 锁定任务 \-\> 执行 2 小时 \-\> 提交结果 \-\> 标记完成。
* **异常情况 (SAE 缩容)**Worker 执行到 1 小时被销毁 \-\> 数据库锁在 4 小时后过期 \-\> pg-boss 守护进程检测到过期 \-\> 将任务重新标记为 Pending \-\> 新 Worker 领取重试。
3. **断点续传**Worker 可定期(如每 10 分钟)更新数据库中的 progress 字段。重试时读取 progress从断点继续执行。
**结论**:配合 pg-boss 的死信队列Dead Letter和重试策略可靠性等同甚至高于 Redis因为 Redis 内存溢出风险更大)。
## **6\. 实施路线图**
### **阶段1任务队列改造Week 1**
#### **Step 1.1:安装依赖**
#### **Step 1.1嚗𡁜<EFBFBD><EFBFBD><EFBFBD>韏?*
```bash
cd backend
npm install pg-boss --save
```
#### **Step 1.2实现PgBossQueue适配器**
#### **Step 1.2嚗𡁜<EFBFBD><EFBFBD>gBossQueue<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?*
```typescript
// <20><>辣嚗颹ackend/src/common/jobs/PgBossQueue.ts
@@ -343,9 +302,7 @@ export class PgBossQueue implements JobQueue {
constructor() {
this.boss = new PgBoss({
connectionString: config.databaseUrl,
schema: 'job_queue', // 独立schema,不污染业务表
max: 5, // 连接池大小
// 关键配置设置锁的有效期为4小时
schema: 'job_queue', // <EFBFBD><EFBFBD>schema嚗䔶<EFBFBD>瘙⊥<EFBFBD>銝𡁜𦛚銵? max: 5, // 餈墧𦻖瘙惩之撠? // <20>喲睸<E596B2>滨蔭嚗朞挽蝵桅<E89DB5><E6A185><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>銝?撠𤩺𧒄
// 靽肽<E99DBD>2撠𤩺𧒄隞餃𦛚銝滩◤<E6BBA9>粥嚗䔶<E59A97>摰硺<E691B0>撏拇<E6928F><E68B87><EFBFBD><E88898>芸𢆡<E88AB8><EFBFBD>
expireInHours: 4,
});
@@ -361,7 +318,7 @@ export class PgBossQueue implements JobQueue {
await this.boss.start();
this.started = true;
logger.info('[PgBoss] 队列已启动');
logger.info('[PgBoss] <20><EFBFBD>撌脣鍳<E884A3>?);
}
async push<T = any>(type: string, data: T, options?: any): Promise<Job> {
@@ -369,9 +326,7 @@ export class PgBossQueue implements JobQueue {
const jobId = await this.boss.send(type, data, {
retryLimit: 3,
retryDelay: 60, // 失败后60秒重试
expireInHours: 4, // 4小时后过期
...options
retryDelay: 60, // 憭梯揖<EFBFBD>?0蝘㘾<E89D98>霂? expireInHours: 4, // 4撠𤩺𧒄<F0A4A9BA><EFBFBD><E88898>? ...options
});
logger.info('[PgBoss] 隞餃𦛚<E9A483>仿<EFBFBD>', { type, jobId });
@@ -387,7 +342,7 @@ export class PgBossQueue implements JobQueue {
process<T = any>(type: string, handler: JobHandler<T>): void {
this.boss.work(type, async (job: any) => {
logger.info('[PgBoss] 开始处理任务', {
logger.info('[PgBoss] 撘<>憪见<E686AA><E8A781><EFBFBD><EFBFBD>?, {
type,
jobId: job.id,
attemptsMade: job.data.__retryCount || 0
@@ -422,7 +377,7 @@ export class PgBossQueue implements JobQueue {
}
});
logger.info('[PgBoss] Worker已注册', { type });
logger.info('[PgBoss] Worker撌脫釣<EFBFBD>?, { type });
}
async getJob(id: string): Promise<Job | null> {
@@ -439,8 +394,7 @@ export class PgBossQueue implements JobQueue {
}
async updateProgress(id: string, progress: number, message?: string): Promise<void> {
// pg-boss暂不支持进度更新,可通过更新业务表实现
logger.debug('[PgBoss] 进度更新', { id, progress, message });
// pg-boss<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>餈𥕦漲<EFBFBD>湔鰵嚗<EFBFBD><EFBFBD><EFBFBD><EFBFBD>湔鰵銝𡁜𦛚銵典<EFBFBD><EFBFBD>? logger.debug('[PgBoss] 餈𥕦漲<F0A595A6>湔鰵', { id, progress, message });
}
async cancelJob(id: string): Promise<boolean> {
@@ -454,8 +408,7 @@ export class PgBossQueue implements JobQueue {
}
async cleanup(olderThan: number = 86400000): Promise<number> {
// pg-boss有自动清理机制
return 0;
// pg-boss<EFBFBD>㕑䌊<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? return 0;
}
private mapState(state: string): string {
@@ -469,7 +422,7 @@ export class PgBossQueue implements JobQueue {
async close(): Promise<void> {
await this.boss.stop();
logger.info('[PgBoss] 队列已关闭');
logger.info('[PgBoss] <20><EFBFBD>撌脣<E6928C><E884A3>?);
}
}
```
@@ -517,7 +470,7 @@ export class JobFactory {
}
```
#### **Step 1.4:更新环境变量**
#### **Step 1.4嚗𡁏凒<EFBFBD>啁㴓憓<EFBFBD><EFBFBD><EFBFBD>?*
```env
# backend/.env
QUEUE_TYPE=pgboss
@@ -526,19 +479,16 @@ DATABASE_URL=postgresql://user:password@host:5432/dbname
#### **Step 1.5嚗𡁏<EFBFBD>霂𤏪<EFBFBD>2撠𤩺𧒄<EFBFBD>蹂遙<EFBFBD><EFBFBD>**
```bash
# 提交1000篇文献筛选任务
curl -X POST http://localhost:3001/api/v1/asl/projects/:id/screening
# <20>𣂷漱1000蝭<30><E89DAD><EFBFBD><EFBFBD><E6A183>劐遙<E58A90>?curl -X POST http://localhost:3001/api/v1/asl/projects/:id/screening
# 等待处理到50% → 手动停止服务Ctrl+C
# 重启服务
# 蝑匧<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?0% <20>?<3F>见𢆡<E8A781>𨀣迫<F0A880A3>滚𦛚嚗㇃trl+C嚗?# <20>滚鍳<E6BB9A>滚𦛚
npm run dev
# 查看任务状态 → 应该自动恢复并继续处理
```
# <EFBFBD><EFBFBD>隞餃𦛚<EFBFBD><EFBFBD>?<3F>?摨磰砲<E7A3B0>芸𢆡<E88AB8><EFBFBD>撟嗥誧蝏剖<E89D8F><E58996>?```
---
### **阶段2缓存改造Week 2**
### **<EFBFBD>嗆挾2嚗𡁶<EFBFBD>摮䀹㺿<EFBFBD>𩤃<EFBFBD>Week 2嚗?*
#### **Step 2.1嚗𡁏溶<EFBFBD>蘯risma Schema**
```prisma
@@ -563,8 +513,7 @@ npx prisma migrate dev --name add_app_cache
```
#### **Step 2.2嚗𡁜<EFBFBD><EFBFBD>訐ostgresCacheAdapter**
(见上文"3.2 替代 Redis 缓存"部分)
<EFBFBD><EFBFBD>銝𦠜<EFBFBD>"3.2 <EFBFBD>蹂誨 Redis 蝻枏<EFBFBD>"<22><EFBFBD>嚗?
#### **Step 2.3嚗𡁏凒<EFBFBD>蚓acheFactory**
```typescript
// <20><>辣嚗颹ackend/src/common/cache/CacheFactory.ts
@@ -585,7 +534,7 @@ export class CacheFactory {
}
```
#### **Step 2.4:启动定时清理**
#### **Step 2.4嚗𡁜鍳<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?*
```typescript
// <20><>辣嚗颹ackend/src/index.ts
@@ -598,120 +547,88 @@ startCacheCleanupTask(); // 启动缓存清理
---
### **阶段3SAE部署Week 3**
### **<EFBFBD>嗆挾3嚗锭AE<EFBFBD>函蔡嚗Áeek 3嚗?*
1. **本地测试通过**ASL 1000篇文献 + DC 100份病历)
2. **数据库连接配置**SAE环境变量设置DATABASE_URL
3. **灰度发布**先1个实例观察24小时
4. **全量上线**扩容到2-3个实例
1. **<2A>砍𧑐瘚贝<E7989A><E8B49D><EFBFBD>**嚗㇁SL 1000<EFBFBD><EFBFBD><EFBFBD>?+ DC 100隞賜<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
2. **<2A>唳旿摨栞<E691A8><E6A09E>仿<EFBFBD>蝵?*嚗𠄎AE<41><EFBFBD><E887AC><EFBFBD>霈曄蔭DATABASE_URL嚗?3. **<2A>啣漲<E595A3><EFBFBD>**嚗<><E59A97>1銝芸<E98A9D>靘页<E99D98><EFBFBD><E996AB>24撠𤩺𧒄嚗?4. **<2A><EFBFBD>銝羓瑪**嚗<><E59A97>摰孵<E691B0>2-3銝芸<E98A9D>靘页<E99D98>
## **7\. 性能边界与扩展路径**
## **7\. <EFBFBD><EFBFBD>颲寧<EFBFBD>銝擧<EFBFBD>撅閗楝敺?*
### **7.1 <20><>鍂閫<E98D82>芋**
| 指标 | Postgres-Only方案上限 | 您的当前值 | 安全余量 |
| <EFBFBD><EFBFBD><EFBFBD> | Postgres-Only<EFBFBD><EFBFBD>銝𢠃<EFBFBD> | <20><EFBFBD>敶枏<E695B6><E69E8F>?| 摰匧<E691B0>雿䠷<E99BBF> |
|------|---------------------|-----------|---------|
| 日活用户 | 10| 500 | 200|
| 并发QPS | 5000 | < 50 | 100|
| 缓存容量 | 10GB | < 100MB | 100|
| 队列吞吐 | 1000任务/小时 | < 50任务/小时 | 20|
| <EFBFBD>交暑<EFBFBD><EFBFBD> | 10銝?| 500 | 200<EFBFBD>?|
| 撟嗅<EFBFBD>QPS | 5000 | < 50 | 100<EFBFBD>?|
| 蝻枏<EFBFBD>摰寥<EFBFBD> | 10GB | < 100MB | 100<EFBFBD>?|
| <EFBFBD><EFBFBD><EFBFBD>𧼮<EFBFBD> | 1000隞餃𦛚/撠𤩺𧒄 | < 50隞餃𦛚/撠𤩺𧒄 | 20<EFBFBD>?|
**结论在可预见的未来2-3年您不会超出这个上限。**
**蝏栞捏嚗𡁜銁<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>芣䔉嚗?-3撟湛<E6929F>嚗峕<E59A97>銝滢<E98A9D><EFBFBD>枂餈嗘葵銝𢠃<E98A9D><F0A2A083>?*
### **7.2 何时需要Redis**
只有在以下情况发生时才需要考虑引入Redis
### **7.2 雿閙𧒄<EFBFBD><EFBFBD><EFBFBD>edis嚗?*
<EFBFBD><EFBFBD><EFBFBD>其誑銝𧢲<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>𧒄嚗峕<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>撘訫<EFBFBD>Redis嚗?
```
閫血<EFBFBD><EFBFBD>∩辣嚗㇁NY嚗㚁<EFBFBD>
✅ 日活 > 5万
✅ 并发QPS > 1000
✅ Postgres CPU使用率持续 > 70%
✅ 缓存查询延迟 > 50msP99
✅ LLM API月成本 > ¥5000缓存命中率低
<EFBFBD>?<3F>交暑 > 5銝?<3F>?撟嗅<E6929F>QPS > 1000
<EFBFBD>?Postgres CPU雿輻鍂<E8BCBB><E98D82><EFBFBD>蝏?> 70%
<EFBFBD>?蝻枏<E89DBB><E69E8F>亥砭撱嗉<E692B1> > 50ms嚗㇊99嚗?<3F>?LLM API<50><49><EFBFBD><EFBFBD>?> 瞼5000嚗<30><E59A97>摮睃𦶢銝剔<E98A9D>雿𠬍<E99BBF>
迁移策略:
1. 先迁移LLM缓存到Redis高频读
2. 保持任务队列在Postgres强一致性
<EFBFBD>宏蝑𣇉裦嚗?1. <20><><EFBFBD>蝘腿LM蝻枏<E89DBB><E69E8F>訌edis嚗<73><E59A97>憸𤏸粉嚗?2. 靽脲<E99DBD>隞餃𦛚<E9A483><EFBFBD><E7AC94>沌ostgres嚗<73>撩銝<E692A9><E98A9D><EFBFBD><EFBFBD>
3. 銝𡁜𦛚蝻枏<E89DBB><E69E8F><EFBFBD><EFBFBD>
成本:
- 迁移工作量: 2-3天
- 运维增加: 可接受(已有经验)
```
<EFBFBD>鞉𧋦嚗?- 餈<>宏撌乩<E6928C><E4B9A9>? 2-3憭?- 餈鞟輕憓𧼮<E68693>: <20>舀𦻖<E88880><EFBFBD>撌脫<E6928C>蝏誯<E89D8F>嚗?```
### **7.3 <20><EFBFBD>頝臬<E9A09D>**
```
阶段1当前-5000用户: Postgres-Only
<EFBFBD>嗆挾1嚗<EFBFBD><EFBFBD><EFBFBD>?5000<30><EFBFBD>嚗? Postgres-Only
<20><EFBFBD> <20><EFBFBD>: pg-boss
├─ 缓存: Postgres
└─ 成本: ¥0
<EFBFBD><EFBFBD> 蝻枏<E89DBB>: Postgres銵? <20><EFBFBD> <20>鞉𧋦: 瞼0
阶段25000-5万用户: 混合架构
<EFBFBD>嗆挾2嚗?000-5銝<35><EFBFBD><EFBFBD>: 瘛瑕<E7989B><E79195><EFBFBD>
<20><EFBFBD> <20><EFBFBD>: pg-boss嚗<73><E59A97><EFBFBD><EFBFBD><EFBFBD>
<20><EFBFBD> LLM蝻枏<E89DBB>: Redis嚗<73><E59A97>蝘鳴<E89D98>
<20><EFBFBD> 銝𡁜𦛚蝻枏<E89DBB>: Postgres嚗<73><E59A97><EFBFBD><EFBFBD><EFBFBD>
└─ 成本: +¥1000/
阶段35万-50万用户: 全Redis
<EFBFBD><EFBFBD> <20>鞉𧋦: +1000/撟?
<EFBFBD>嗆挾3嚗?銝?50銝<30><EFBFBD><EFBFBD>: <20>沖edis
<20><EFBFBD> <20><EFBFBD>: BullMQ + Redis
<20><EFBFBD> 蝻枏<E89DBB>: Redis
└─ 成本: +¥5000/
```
<EFBFBD><EFBFBD> <20>鞉𧋦: +5000/撟?```
---
## **8\. FAQ嚗<51>虜閫<E8999C><E996AB><EFBFBD><EFBFBD>**
### **Q1: pg-boss会不会拖慢Postgres**
### **Q1: pg-boss隡帋<EFBFBD>隡𡁏<EFBFBD><EFBFBD>ostgres嚗?*
**A:** 不会。pg-boss的查询都有索引优化单次查询 < 5ms。即使100个Worker同时抢任务也只是500ms的额外负载对于5万QPS的Postgres来说可忽略。
### **Q2: 缓存表会不会无限增长?**
**A:** 不会。懒惰删除 + 分批清理过期数据会被自动清理。即使有积压每分钟1000条的清理速度足以应对。
**A:** 銝滢<E98A9D><E6BBA2><EFBFBD>g-boss<73><73>䰻霂<E99C82><EFBD81>厩揣撘蓥<E69298><E893A5><EFBFBD><E59094>閙活<E99699>亥砭 < 5ms<6D><73>朖雿?00銝杪orker<65>峕𧒄<E5B395><EFBCB6><EFBFBD>銋笔蘨<E7AC94>?00ms<6D><73><EFBFBD>憭𤥁<E686AD>頧踝<E9A0A7>撖嫣<E69296>5銝𣘗PS<50><53>ostgres<65>亥秩<E4BAA5>臬蕭<E887AC><EFBFBD>?
### **Q2: 蝻枏<E89DBB>銵其<E98AB5>銝滢<E98A9D><E6BBA2>𣳇<EFBFBD>憓鮋鵭嚗?*
**A:** 銝滢<E98A9D><E6BBA2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E595A3>?+ <20><>鸌皜<E9B88C><E79A9C>嚗諹<E59A97><E8ABB9><EFBFBD><EFBFBD><EFBFBD>鋡怨䌊<E680A8><EFBFBD><E586BD><EFBFBD><EFBFBD><EFBFBD>朖雿踵<E99BBF>蝘臬<E89D98>嚗峕<E59A97><E5B395><EFBFBD><EFBFBD>1000<30><EFBFBD><EFBFBD><E79A9C><EFBFBD>笔漲頞喃誑摨𥪜笆<F0A5AA9C>?
### **Q3: 憒<><E68692>Postgres<65><73><EFBFBD><EFBFBD>𦒘<EFBFBD><F0A69298><EFBFBD>**
**A:**
- **阿里云RDS**:高可用版自动主从切换,故障恢复 < 30秒
- **备份恢复**PITR可恢复到任意秒数据不丢失
- **降级策略**队列和缓存都在DB一起恢复无不一致风险
相比之下Redis挂了还需要担心数据不一致问题。
- **<2A><EFBFBD>鈭駵DS**嚗𡁻<E59A97><F0A181BB>舐鍂<E88890><E98D82><EFBFBD>其蜓隞𤾸<E99A9E><F0A4BEB8><EFBFBD><EFBD87><EFBFBD><EFBFBD><EFBFBD><EFBFBD> < 30蝘?- **憭<><EFBFBD><EFBFBD>**嚗䥪ITR<54><EFBFBD>憭滚<E686AD>隞餅<E99A9E>蝘𡜐<E89D98><F0A19C90>唳旿銝滢腺憭?- **<2A>滨漣蝑𣇉裦**嚗𡁻<E59A97><F0A181BB><EFBFBD>蝻枏<E89DBB><E69E8F>賢銁DB嚗䔶<E59A97>韏瑟<E99F8F>憭㵪<E686AD><E3B5AA><EFBFBD><EFBFBD><E98A9D><EFBFBD><E6B9A7>?
<EFBFBD><EFBFBD>銋衤<EFBFBD>嚗朙edis<EFBFBD><EFBFBD><EFBFBD>餈㗛<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>湧䔮憸塩<EFBFBD>?
### **Q4: 銝箔<E98A9D><EFBFBD><E98A8B><EFBFBD>沖edis嚗<73>㭂霂渲䌊撌望糓鈭穃<E988AD><E7A983><EFBFBD><EFBFBD>**
**A:** 云原生的核心是**状态外置**,不是**必须用Redis**
```
云原生的本质:
✅ 无状态应用(不依赖本地内存)
✅ 状态持久化(数据不丢失)
✅ 水平扩展(多实例协调)
Postgres-Only完全满足
✅ 状态存储在RDS外置
✅ 任务持久化(不丢失)
✅ pg-boss支持多实例SKIP LOCKED
Redis只是实现方式之一不是唯一方式。
**A:** 鈭穃<E988AD><E7A983><EFBFBD><E6AFBA><EFBFBD><E8A9A8>?*<2A><EFBFBD><E59786><EFBFBD>蝵?*嚗䔶<E59A97><E494B6>?*敹<><EFBFBD>edis**<EFBFBD>?
```
鈭穃<EFBFBD><EFBFBD><EFBFBD><EFBFBD>祈捶嚗?<3F>?<3F>删𠶖<E588A0><F0A0B696><EFBFBD><EFBFBD><EFBFBD>銝滢<E98A9D>韏𡝗𧋦<F0A19D97><EFBFBD>摮矋<E691AE>
<EFBFBD>?<3F><EFBFBD><E59786><EFBFBD><EFBFBD><E98A8B><EFBFBD><EFBFBD><EFBFBD>仃嚗?<3F>?瘞游像<E6B8B8><EFBFBD><EFBFBD><E59A97>摰硺<E691B0><E7A1BA><EFBFBD>嚗?
Postgres-Only摰<79><E691B0>皛∟雲嚗?<3F>?<3F><EFBFBD><E59786><EFBFBD><EFBFBD>典銁RDS嚗<53><E59A97>蝵殷<E89DB5>
<EFBFBD>?隞餃𦛚<E9A483><F0A69B9A><EFBFBD><EFBFBD><EFBFBD>銝滢腺憭梧<E686AD>
<EFBFBD>?pg-boss<73><EFBFBD>憭𡁜<E686AD>靘页<E99D98>SKIP LOCKED嚗?
Redis<EFBFBD>芣糓摰䂿緵<EFBFBD><EFBFBD>銋衤<EFBFBD>嚗䔶<EFBFBD><EFBFBD>臬𣈲銝<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?```
---
## **9\. 蝏栞祗**
对于 1-2 人规模的精益创业团队,**技术栈的坍缩Stack Collapse是降低熵增的最佳手段**。
撖嫣<EFBFBD> 1-2 鈭箄<EFBFBD>璅∠<EFBFBD>蝎曄<EFBFBD><EFBFBD>𥕢<EFBFBD><EFBFBD><EFBFBD>嚗?*<2A><><EFBFBD><EFBFBD><E88880><EFBFBD><EFBFBD>蝻抬<E89DBB>Stack Collapse嚗㗇糓<E39787><EFBFBD><E6BBA2><EFBFBD><E89084><EFBFBD><EFBFBD>雿單<E99BBF>畾?*<2A>?
<EFBFBD>㗇𥋘 Postgres-Only 銝齿糓<E9BDBF>牐蛹<E78990>睲賑<E79DB2><E8B391><EFBFBD>航氜<E888AA>𠬍<EFBFBD><F0A0AC8D>峕糓<E5B395>牐蛹<E78990>睲賑撖寞<E69296><E5AF9E><EFBFBD><E88880><EFBFBD><EFBFBD>湔楛<E6B994><EFBFBD><E9A48C><EFBFBD>圾嚗?
- <20>睲賑<E79DB2><E8B391>圾**撟嗅<E6929F><E59785><EFBFBD><EFBFBD>摰噼<E691B0>璅?*嚗<><E59A97><EFBFBD><EFBFBD><E888AA><EFBFBD><E5969F><EFBFBD>QPS嚗?- <20>睲賑<E79DB2><E8B391>圾**Postgres<65><73><EFBFBD><EFBFBD>𥡝器<F0A5A19D>?*嚗<><E59A97><EFBFBD>臬㫲鞊∩葉<E288A9>?<3F>?嚗?- <20>睲賑<E79DB2><E8B391>圾**<2A><EFBFBD><E59786><EFBFBD>瓲敹<E793B2>𤌍<EFBFBD>?*嚗<>迅摰𡁏<E691B0>?> <20><EFBFBD>嚗?- <20>睲賑<E79DB2><E8B391>圾**<2A><EFBFBD><EFBD81><EFBFBD><EFBFBD>摰噼<E691B0><E599BC>?*嚗<><E59A97>蝏渲<E89D8F><E6B8B2>?= 蝔喳<E89D94><E596B3><EFBFBD>
选择 Postgres-Only 不是因为我们技术落后,而是因为我们对技术有着更深刻的理解:
- 我们理解**并发的真实规模**不是臆想的百万QPS
- 我们理解**Postgres的能力边界**(不是印象中的"慢"
- 我们理解**架构的核心目标**(稳定性 > 炫技)
- 我们理解**团队的真实能力**(运维能力 = 稳定性)
我们选择用**架构的简洁性**来换取**运维的稳定性**,用**务实的判断**来换取**业务的快速迭代**。
**这不是妥协,这是智慧。**
<EFBFBD>睲賑<EFBFBD>㗇𥋘<EFBFBD>?*<2A><EFBFBD><E59786><EFBFBD><EFBFBD><EFBFBD><E798A3>?*<2A>交揢<E4BAA4>?*餈鞟輕<E99E9F><E8BC95>迅摰𡁏<E691B0>?*嚗𣬚鍂**<2A><EFBFBD><E288AA><EFBFBD>ế<EFBFBD>?*<2A>交揢<E4BAA4>?*銝𡁜𦛚<F0A1819C><F0A69B9A><EFBFBD>蠘翮隞?*<2A>?
**餈嗘<E9A488><E59798>臬戎<E887AC>𧶏<EFBFBD>餈蹱糓<E8B9B1><EFBFBD><E7AEB8>?*