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:
@@ -1,115 +1,96 @@
|
||||
# **Postgres-Only <20>刻<EFBFBD><E588BB>嗆<EFBFBD>閫<EFBFBD><E996AB><EFBFBD>寞<EFBFBD>**
|
||||
|
||||
## **—— 面向微型 AI 团队的高可靠、低成本技术战略**
|
||||
## **<EFBFBD>婙<EFBFBD>?<3F>W<EFBFBD>敺桀<E695BA> AI <20>a<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>W<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>皞W枂<EFBCB7>屸<EFBFBD><E5B1B8>園<EFBFBD>瘥<EFBFBD><E798A5><EFBFBD><EFBFBD><EFBFBD>阡<EFBFBD>瘥<EFBFBD><E798A5><EFBFBD><EFBFBD><EFBFBD>銝剔<E98A9D>隞餃𦛚餈𥕦漲<F0A595A6>喳<EFBFBD>銝W仃嚗<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 结果缓存(避免重复调用 LLM),Postgres 的查询速度(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><>䰻霂a<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>閙䰻霂g<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]) // 蝝W<EFBFBD><EFBFBD>其<EFBFBD>敹恍<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>㺭<EFBFBD>? @@index([key, expiresAt]) // 憭滚<E686AD>蝝W<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. **蝝W<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-boss(API类似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>W<EFBFBD><EFBFBD>航<EFBFBD>隡帋腺憭望<EFBFBD><EFBFBD>𤾸<EFBFBD>蝘垍<EFBFBD><EFBFBD>唳旿<EFBFBD>?| **摰𣬚<EFBFBD>** RDS <EFBFBD>舀<EFBFBD> PITR (<EFBFBD>㗇𧒄<EFBFBD>渡<EFBFBD><EFBFBD>W<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>皞W枂<EFBFBD><EFBFBD>閬<EFBFBD><EFBFBD>蝵容viction蝑𣇉裦嚗䔶<EFBFBD>敶㯄<EFBFBD>蝵桐<EFBFBD>撖潸稲<EFBFBD>唳旿銝W仃 | **<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>**
|
||||
|
||||
#### **误解1:Postgres并发性能差**
|
||||
#### **霂航圾1嚗䥪ostgres撟嗅<EFBFBD><EFBFBD>扯<EFBFBD>撌?*
|
||||
```
|
||||
事实:
|
||||
- Postgres可处理5万+ QPS(简单查询)
|
||||
鈭见<EFBFBD>嚗?- Postgres<65>臬<EFBFBD><E887AC>?銝? QPS嚗<53><E59A97><EFBFBD>閙䰻霂g<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>
|
||||
```
|
||||
|
||||
#### **误解2:DELETE会锁表阻塞**
|
||||
#### **霂航圾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>W<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>皞W枂憌𡡞埯<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>Z粥嚗䔶<E59A97>摰硺<E691B0>撏拇<E6928F><E68B87>舘<EFBFBD><E88898>芸𢆡<E88AB8>W<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>W<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(); // 启动缓存清理
|
||||
|
||||
---
|
||||
|
||||
### **阶段3:SAE部署(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%
|
||||
✅ 缓存查询延迟 > 50ms(P99)
|
||||
✅ 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
|
||||
|
||||
阶段2(5000-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/年
|
||||
|
||||
阶段3(5万-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>䰻霂a<E99C82><EFBD81>厩揣撘蓥<E69298><E893A5>吔<EFBFBD><E59094>閙活<E99699>亥砭 < 5ms<6D><73>朖雿?00銝杪orker<65>峕𧒄<E5B395>V遙<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>g<EFBFBD><EFBD87><EFBFBD><EFBFBD><EFBFBD>W<EFBFBD> < 30蝘?- **憭<>遢<EFBFBD>W<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>銝W仃嚗?<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>a<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>a<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>?*
|
||||
Reference in New Issue
Block a user