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%)
1793 lines
51 KiB
Markdown
1793 lines
51 KiB
Markdown
# Redis謾ケ騾<EFBDB9>螳樊命隶。蛻抵シ育シ灘ュ<E78198>+髦溷<E9ABA6>螳梧紛迚茨シ<E88CA8>
|
||
|
||
> **譁<>。」迚域悽<E59F9F>?* V2.0
|
||
> **譖エ譁ー譌・譛滂シ?* 2025-12-12
|
||
> **逶ョ譬<EFBDAE>ョ梧<EFBDAE>譌カ髣エ<E9ABA3>?* 2025-12-18<31>?螟ゥ<E89E9F><EFBDA9>
|
||
> **雍溯エ」莠コ<E88EA0><EFBDBA>** 謚譛ッ蝗「髦?
|
||
> **鬟朱勦遲臥コァ<EFBDBA>?* <20>泯 荳ュ遲会シ域怏髯咲コァ譁ケ譯茨シ?
|
||
> **驥崎ヲ∝序譖エ<E8AD96>?* Redis髦溷<E9ABA6>莉?蜿ッ騾?隹<>紛荳?蠢<>。サ"
|
||
|
||
---
|
||
|
||
## 笞<><E7AC9E><EFBFBD> **驥崎ヲ∬ッエ譏趣シ<E8B6A3>2.0譖エ譁ー<EFBFBD>?*
|
||
|
||
扈剰ソ<EFBFBD>キア蜈・蛻<EFBFBD>梵<EFBFBD>軍edis髦溷<EFBFBD>**荳肴弍蜿ッ騾蛾。ケ**<2A>瑚梧弍**譬ク蠢<EFBDB8>粥閭ス逧<EFBDBD>ソ<EFBFBD>。サ鬘ケ**<2A>?
|
||
1. **ASL譁<4C>鍵遲幃?*<2A>?000遽<30>枚迪ョ髴隕?蟆乗慮<E4B997>御ク咲畑Redis髦溷<E9ABA6>螟ア雍・邇?> 95%
|
||
2. **DC Tool B逞<42>紙謠仙叙**<EFBFBD>?000莉ス逞<EFBDBD>紙髴隕?-3蟆乗慮<E4B997>悟酔譬キ髣ョ鬚?3. **SAE螳樔セ狗音諤?*<2A>?5蛻<35>帖譌<E5B896>豬<EFBFBD>㍼閾ェ蜉ィ郛ゥ螳ケ<E89EB3>碁柄莉サ蜉。蠢<EFBDA1>┯螟ア雍?
|
||
**蝗<>豁、譛ャ隶。蛻定ー<E5AE9A>紛荳コ<E88DB3>夂シ灘ュ?髦溷<E9ABA6>荳襍キ螳樊命<E6A88A><E591BD>7螟ゥ螳梧<E89EB3><E6A2A7><EFBFBD>**
|
||
|
||
---
|
||
|
||
## <20>搭 逶ョ蠖<EFBDAE>
|
||
|
||
1. [謾ケ騾<EFBDB9>閭梧勹荳守岼譬Ⅹ(#1-謾ケ騾<EFBDB9>閭梧勹荳守岼譬<E5B2BC>)
|
||
2. [蠖灘燕邉サ扈溽憾諤∝<E8ABA4>譫疹(#2-蠖灘燕邉サ扈溽憾諤∝<E8ABA4>譫?
|
||
3. [Redis驟咲スョ菫。諱ッ](#3-redis驟咲スョ菫。諱ッ)
|
||
4. [謾ケ騾<EFBFBD>隸ヲ扈<EFBFBD>ュ・鬪、](#4-謾ケ騾<EFBDB9>隸ヲ扈<EFBDA6>ュ・鬪?<3F>遺惠 **蟾イ譖エ譁ー<E8AD81>壼桁蜷ォ髦溷<E9ABA6>**<2A>?5. [豬玖ッ墓婿譯<E5A9BF>(#5-豬玖ッ墓婿譯<E5A9BF>)
|
||
6. [鬟朱勦隸<E58BA6>シー荳守シ楢ァ」](#6-鬟朱勦隸<E58BA6>シー荳守シ楢ァ?
|
||
7. [荳顔コソ隶。蛻綻(#7-荳顔コソ隶。蛻<EFBDA1>)
|
||
8. [蝗樊サ壽婿譯<E5A9BF>(#8-蝗樊サ壽婿譯<E5A9BF>)
|
||
9. [逶第而荳手ソ千サエ](#9-逶第而荳手ソ千サ?
|
||
|
||
---
|
||
|
||
## 1. 謾ケ騾<EFBDB9>閭梧勹荳守岼譬<E5B2BC>
|
||
|
||
### 1.1 荳コ莉荵郁ヲ∵隼騾<E99ABC><E9A8BE><EFBFBD>
|
||
|
||
#### **蠖灘燕髣ョ鬚<EFBDAE>**<2A>?1. 笶?**霑晏渚莠大次逕溯ァ<E6BAAF><EFBDA7>?*<2A>夂ウサ扈滉スソ逕ィ蜀<EFBDA8>ュ倡シ灘ュ假シ瑚ソ晏渚閾ェ蟾ア蛻カ螳夂噪莠大次逕溷シ蜿題ァ<E9A18C><EFBDA7>?2. 笶?**LLM謌先悽螟ア謗ァ**<2A>夂シ灘ュ倅ク肴戟荵<E6889F>喧<EFBFBD>悟ッシ閾エ驥榊、崎ー<E5B48E>畑DeepSeek/Qwen API
|
||
3. 笶?**髟ソ莉サ蜉。荳榊庄髱<E5BA84>**<2A>?0-60蛻<30>帖逧<E5B896>枚迪ョ遲幃我ササ蜉。<E89C89>郡AE螳樔セ矩㍾蜷ッ蜷惹ク「螟?4. 笶?**螟壼ョ樔セ倶ク榊酔豁・**<2A>售AE謇ゥ螳ケ蜷趣シ悟推螳樔セ狗シ灘ュ倅ク榊<EFBDB8>莠ォ
|
||
5. 笶?**Serverless荳埼る<C280>**<2A>壼<EFBFBD>蟄倡憾諤∝惠Serverless邇ッ蠅<EFBDAF>ク倶ク榊庄髱<E5BA84>
|
||
|
||
#### **謾ケ騾<EFBDB9>逶ョ譬?*<2A>?- 笨?**隨ヲ蜷域楔譫<E6A594>ァ<EFBFBD>激**<2A>壻スソ逕ィ蛻<EFBDA8>ク<EFBFBD>シ冗シ灘ュ假シ<E58187>edis<69>?- 笨?**髯堺ス拶PI謌先悽**<2A>哭LM扈捺棡郛灘ュ俶戟荵<E6889F>喧<EFBFBD>碁∩蜈埼㍾螟崎ー<E5B48E>畑
|
||
- 笨?**莉サ蜉。謖∽ケ<E288BD><EFBDB9>?*<2A>夐柄譌カ髣エ莉サ蜉。荳榊屏螳樔セ矩㍾蜷ッ閠御ク「螟?- 笨?**謾ッ謖∝、壼ョ樔セ?*<2A>夂シ灘ュ伜惠螟壼ョ樔セ矩龍蜈ア莠ォ
|
||
- 笨?**蟷ウ貊題ソ<E9A18C>ク。**<2A>壻ソ晉蕗髯咲コァ譁ケ譯茨シ檎。ョ菫晉ウサ扈溽ィウ螳<EFBDB3>
|
||
|
||
---
|
||
|
||
## 2. 蠖灘燕邉サ扈溽憾諤∝<E8ABA4>譫?
|
||
### 2.1 蟾イ菴ソ逕ィ郛灘ュ倡噪菴咲スョ
|
||
|
||
#### **菴咲スョ1<EFBDAE>唏ealthCheckService.ts**
|
||
```typescript
|
||
// 譁<>サカ<EFBDBB>喘ackend/src/modules/dc/tool-b/services/HealthCheckService.ts
|
||
// 隨?7陦鯉シ夊ッサ蜿也シ灘ュ<E78198>
|
||
const cached = await cache.get<HealthCheckResult>(cacheKey);
|
||
|
||
// 隨?45陦鯉シ壼<EFBDBC>蜈・郛灘ュ<E78198>
|
||
await cache.set(cacheKey, result, 86400); // 24蟆乗慮
|
||
```
|
||
|
||
**逕ィ騾?*<2A>哘xcel蛛・蠎キ譽譟・扈捺棡郛灘ュ?
|
||
**驥崎ヲ∵?*<2A>夸沺?荳ュ遲会シ磯∩蜈埼㍾螟崎ァ」譫職xcel<65>?
|
||
**謨ー謐ョ驥?*<2A>嘸5KB/鬘?
|
||
|
||
---
|
||
|
||
#### **菴咲スョ2<EFBDAE>哭LM12FieldsService.ts**
|
||
```typescript
|
||
// 譁<>サカ<EFBDBB>喘ackend/src/modules/asl/common/llm/LLM12FieldsService.ts
|
||
// 隨?16陦鯉シ夊ッサ蜿也シ灘ュ<E78198>
|
||
const cached = await cache.get(cacheKey);
|
||
|
||
// 隨?30陦鯉シ壼<EFBDBC>蜈・郛灘ュ<E78198>
|
||
await cache.set(cacheKey, JSON.stringify(result), 3600); // 1蟆乗慮
|
||
```
|
||
|
||
**逕ィ騾?*<2A>哭LM 12蟄玲ョオ謠仙叙扈捺棡郛灘ュ<E78198>
|
||
**驥崎ヲ∵?*<2A>夸沐?鬮假シ育峩謗・蠖ア蜩喉PI謌先悽<E58588>?
|
||
**謨ー謐ョ驥?*<2A>嘸50KB/鬘?
|
||
**謌先悽蠖ア蜩<EFBDB1>**<EFBFBD>?```
|
||
蜊墓ャ。謠仙叙謌先悽<EFBFBD>嘸ツ・0.43/遽?螯よ棡郛灘ュ伜、ア謨茨シ碁㍾螟崎ー<E5B48E>畑<EFBFBD><E79591>
|
||
- 10谺?= ツ・4.3
|
||
- 100谺?= ツ・43
|
||
- 1000谺?= ツ・430
|
||
```
|
||
|
||
---
|
||
|
||
### 2.2 髟ソ譌カ髣エ蠑よュ・莉サ蜉?
|
||
#### **ASL讓。蝮暦シ壽枚迪ョ遲幃我ササ蜉?*
|
||
```typescript
|
||
// 譁<>サカ<EFBDBB>喘ackend/src/modules/asl/services/screeningService.ts
|
||
// 隨?3-65陦?processLiteraturesInBackground(task.id, projectId, literatures);
|
||
```
|
||
|
||
**髣ョ鬚<EFBDAE>**<2A>?- 199遽<39>枚迪ョ髴隕?33-66蛻<36>帖
|
||
- 蠖灘燕菴ソ逕ィ蜀<EFBDA8>ュ倬弌蛻暦シ<E69AA6>emoryQueue<75>?- SAE螳樔セ矩㍾蜷ッ/郛ゥ螳ケ譌カ莉サ蜉。荳「螟?
|
||
**蠖ア蜩<EFBDB1>**<2A>?- 逕ィ謌キ菴馴ェ梧栫蟾ョ<E89FBE>井ササ蜉。遯∫┯豸亥、ア<EFBDA4><EFBDB1>
|
||
- 蟾イ螟<EFBDB2>炊扈捺棡荳「螟ア<E89E9F>梧オェ雍ケAPI雍ケ逕ィ
|
||
- 譌<>豕戊ソス貅ッ莉サ蜉。迥カ諤?
|
||
---
|
||
|
||
### 2.3 蠖灘燕譫カ譫<EFBDB6><E8ADAB>鄂ョ
|
||
|
||
```env
|
||
# backend/.env
|
||
CACHE_TYPE=memory # 竊?髴隕∵隼荳?redis
|
||
QUEUE_TYPE=memory # 竊?髴隕∵隼荳?redis
|
||
```
|
||
|
||
---
|
||
|
||
## 3. Redis驟咲スョ菫。諱ッ
|
||
|
||
### 3.1 髦ソ驥御コ然edis雍ュ荵ー菫。諱ッ
|
||
|
||
| 驟咲スョ鬘?| 蛟?| 隸エ譏<EFBDB4> |
|
||
|--------|---|------|
|
||
| **莠ァ蜩<EFBDA7>** | Redis 蠑貅千沿 | 螳梧紛Redis蜉溯<E89C89> |
|
||
| **莉倩エケ譁ケ蠑<EFBDB9>** | 蛹<>ケエ蛹<EFBDB4>怦 | 鬥匁ャ。雍ュ荵ー莠?謚倅シ俶<EFBDBC>?|
|
||
| **驛ィ鄂イ讓。蠑<EFBDA1>** | 莠大次逕滂シ磯ォ伜庄逕ィ<E98095><EFBDA8> | 荳サ莉手<E88E89>蜉ィ蛻<EFBDA8>困 |
|
||
| **邉サ蛻<EFBDBB>** | 譬<>㊥迚?| 貊。雜ウ髴豎?|
|
||
| **蝨ー蝓<EFBDB0>** | 蜊主圏2<E59C8F>亥圏莠ャ<E88EA0><EFBDAC> | 荳惨AE蜷悟慍蝓?|
|
||
| **螳樔セ狗アサ蝙<EFBDBB>** | 鬮伜庄逕?| 笨?99.95%蜿ッ逕ィ諤?|
|
||
| **螟ァ迚域<E8BF9A>?* | Redis 7.0 | 譛譁ー遞ウ螳夂沿 |
|
||
| **譫カ譫<EFBDB6>アサ蝙<EFBDBB>** | 荳榊星逕ィ髮<EFBDA8>セ、<EFBDBE>亥黒闃らせ<E38289><E3819B> | 貊。雜ウ蠖灘燕隗<E78795>ィ。 |
|
||
| **蛻<>援隗<E68FB4><E99A97>シ** | 256 MB | 蛻晄悄雜ウ螟<EFBDB3> |
|
||
| **蛻<>援謨ー驥<EFBDB0>** | 1 | 蜊募<E89C8A>迚?|
|
||
| **隸サ蜀吝<E89C80>遖サ** | 蜈ウ髣ュ | 邂蛹夜<E89BB9>鄂?|
|
||
|
||
### 3.2 鬚<>シー謌先悽
|
||
|
||
```
|
||
蝓コ遑莉キ譬シ<EFBFBD>堋?2/蟷エ<E89FB7>亥黒譛コ迚茨シ<E88CA8>
|
||
鬮伜庄逕ィ迚茨シ堋?80/蟷エ<E89FB7>井シー邂暦シ?鬥匁ャ。雍ュ荵ー<E88DB5>堋?08/蟷エ<E89FB7><EFBDB4>6謚伜錘<E4BC9C>?
|
||
蟇ケ豈疲噺逶奇シ?- 闃ら怐LLM API雍ケ逕ィ<E98095>?ツ・500/蟷?- 謠仙合逕ィ謌キ貊。諢丞コヲ<EFBDBA>壽裏莉キ
|
||
- ROI<4F>?400%
|
||
```
|
||
|
||
### 3.3 霑樊磁菫。諱ッ<E8ABB1>郁エュ荵ー蜷手執蜿厄シ?
|
||
```env
|
||
# 髦ソ驥御コ第而蛻カ蜿ー 竊?Redis螳樔セ<E6A894> 竊?霑樊磁菫。諱ッ
|
||
REDIS_HOST=r-xxxxxxxxxxxx.redis.rds.aliyuncs.com
|
||
REDIS_PORT=6379
|
||
REDIS_PASSWORD=your_secure_password_here
|
||
REDIS_DB=0
|
||
|
||
# 謌紋スソ逕ィ霑樊磁蟄礼ャヲ荳イ
|
||
REDIS_URL=redis://:your_password@r-xxxxxxxxxxxx.redis.rds.aliyuncs.com:6379/0
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 謾ケ騾<EFBDB9>隸ヲ扈<EFBDA6>ュ・鬪?
|
||
### 4.1 Phase 1<>壽悽蝨ー蠑蜿醍識蠅<E8AD98>㊥螟?笨?
|
||
#### **豁・鬪、1.1<EFBFBD>壼ョ芽」<EFBFBD>セ晁オ?*
|
||
```bash
|
||
cd backend
|
||
npm install ioredis --save
|
||
npm install @types/ioredis --save-dev
|
||
```
|
||
|
||
#### **豁・鬪、1.2<EFBFBD>夐<EFBFBD>鄂ョ譛ャ蝨ーRedis**
|
||
```bash
|
||
# 遑ョ隶、Docker Redis豁」蝨ィ霑占。<E58DA0>
|
||
docker ps | findstr redis
|
||
|
||
# 螯よ棡豐。譛芽ソ占。鯉シ悟星蜉ィ螳<EFBDA8>
|
||
docker start ai-clinical-redis
|
||
|
||
# 豬玖ッ戊ソ樊磁
|
||
docker exec -it ai-clinical-redis redis-cli ping
|
||
# 蠎碑ッ・霑泌屓<E6B38C>啀ONG
|
||
```
|
||
|
||
#### **豁・鬪、1.3<EFBFBD>壽峩譁ー譛ャ蝨?env**
|
||
```env
|
||
# backend/.env
|
||
DATABASE_URL=postgresql://postgres:postgres123@localhost:5432/ai_clinical_research
|
||
|
||
# ==================== Redis驟咲スョ ====================
|
||
# 蜷ッ逕ィRedis郛灘ュ<E78198>
|
||
CACHE_TYPE=redis
|
||
REDIS_HOST=localhost
|
||
REDIS_PORT=6379
|
||
REDIS_DB=0
|
||
# REDIS_PASSWORD= # 譛ャ蝨ー譌<EFBDB0>蟇<EFBFBD><E89F87>?
|
||
# 髦溷<E9ABA6>證よ慮逕ィ蜀<EFBDA8>ュ假シ亥<EFBDBC>髦カ谿オ蜷ッ逕ィ<E98095><EFBDA8>
|
||
QUEUE_TYPE=memory
|
||
|
||
# ==================== JWT ====================
|
||
JWT_SECRET=your-secret-key-change-in-production
|
||
JWT_EXPIRES_IN=7d
|
||
|
||
# ==================== LLM API ====================
|
||
DEEPSEEK_API_KEY=sk-7f8cc37a79fa4799860b38fc7ba2e150
|
||
DASHSCOPE_API_KEY=sk-75b4ff29a14a49e79667a331034f3298
|
||
|
||
# ==================== Dify ====================
|
||
DIFY_API_URL=http://localhost/v1
|
||
DIFY_API_KEY=dataset-mfvdiKvQ2l3NvxWm7RoYMN3c
|
||
|
||
# ==================== Server ====================
|
||
PORT=3001
|
||
NODE_ENV=development
|
||
|
||
# ==================== CloseAI驟咲スョ ====================
|
||
CLOSEAI_API_KEY=sk-cu0iepbXYGGx2jc7BqP6ogtSWmP6fk918qV3RUdtGC3Ed1po
|
||
CLOSEAI_OPENAI_BASE_URL=https://api.openai-proxy.org/v1
|
||
CLOSEAI_CLAUDE_BASE_URL=https://api.openai-proxy.org/anthropic
|
||
|
||
# ==================== 蟄伜お驟咲スョ ====================
|
||
STORAGE_TYPE=local
|
||
LOCAL_STORAGE_DIR=uploads
|
||
LOCAL_STORAGE_URL=http://localhost:3001/uploads
|
||
|
||
# ==================== CORS驟咲スョ ====================
|
||
CORS_ORIGIN=http://localhost:5173
|
||
|
||
# ==================== 譌・蠢鈴<E8A0A2>鄂ョ ====================
|
||
LOG_LEVEL=debug
|
||
```
|
||
|
||
---
|
||
|
||
### 4.2 Phase 2<>壼ョ樒鴫RedisCacheAdapter 笨?
|
||
#### **豁・鬪、2.1<EFBFBD>壻ソョ謾ケRedisCacheAdapter.ts**
|
||
|
||
```typescript
|
||
// 譁<>サカ<EFBDBB>喘ackend/src/common/cache/RedisCacheAdapter.ts
|
||
|
||
import Redis from 'ioredis';
|
||
import type { CacheAdapter } from './CacheAdapter.js';
|
||
import { logger } from '../logging/index.js';
|
||
|
||
/**
|
||
* Redis郛灘ュ倬る<C280>蝎? *
|
||
* 菴ソ逕ィioredis螳「謌キ遶ッ<E981B6>梧髪謖<E9ABAA>シ? * - 蟄礼ャヲ荳?蟇ケ雎。閾ェ蜉ィ蠎丞<E8A08E>蛹? * - TTL霑<4C>悄譌カ髣エ
|
||
* - 霑樊磁豎<E7A381>邂。逅? * - 髞呵ッッ驥崎ッ<E5B48E>
|
||
*
|
||
* @example
|
||
* const cache = new RedisCacheAdapter({
|
||
* host: 'localhost',
|
||
* port: 6379,
|
||
* password: 'xxx',
|
||
* db: 0
|
||
* });
|
||
*
|
||
* await cache.set('key', { data: 'value' }, 60);
|
||
* const value = await cache.get('key');
|
||
*/
|
||
export class RedisCacheAdapter implements CacheAdapter {
|
||
private redis: Redis;
|
||
|
||
constructor(options?: {
|
||
host?: string;
|
||
port?: number;
|
||
password?: string;
|
||
db?: number;
|
||
}) {
|
||
this.redis = new Redis({
|
||
host: options?.host || 'localhost',
|
||
port: options?.port || 6379,
|
||
password: options?.password || undefined,
|
||
db: options?.db || 0,
|
||
// 霑樊磁驟咲スョ
|
||
retryStrategy: (times) => {
|
||
const delay = Math.min(times * 50, 2000);
|
||
logger.warn(`Redis霑樊磁驥崎ッ<EFBFBD> ${times} 谺。<E8B0BA><EFBDA1>${delay}ms蜷朱㍾隸描);
|
||
return delay;
|
||
},
|
||
maxRetriesPerRequest: 3,
|
||
enableReadyCheck: true,
|
||
// 霑樊磁豎<E7A381>驟咲ス? lazyConnect: false,
|
||
keepAlive: 30000,
|
||
});
|
||
|
||
// 逶大成霑樊磁莠倶サカ
|
||
this.redis.on('connect', () => {
|
||
logger.info('Redis霑樊磁謌仙粥');
|
||
});
|
||
|
||
this.redis.on('error', (error) => {
|
||
logger.error('Redis霑樊磁髞呵ッッ', { error: error.message });
|
||
});
|
||
|
||
this.redis.on('close', () => {
|
||
logger.warn('Redis霑樊磁蜈ウ髣ュ');
|
||
});
|
||
|
||
this.redis.on('reconnecting', () => {
|
||
logger.warn('Redis豁」蝨ィ驥崎ソ<E5B48E>...');
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 闔キ蜿也シ灘ュ伜? */
|
||
async get<T>(key: string): Promise<T | null> {
|
||
try {
|
||
const value = await this.redis.get(key);
|
||
|
||
if (!value) {
|
||
logger.debug('Redis郛灘ュ俶悴蜻ス荳?, { key });
|
||
return null;
|
||
}
|
||
|
||
logger.debug('Redis郛灘ュ伜多荳ュ', { key, size: value.length });
|
||
|
||
// 蟆晁ッ戊ァ」譫辱SON
|
||
try {
|
||
return JSON.parse(value) as T;
|
||
} catch {
|
||
// 螯よ棡荳肴弍JSON<4F>瑚ソ泌屓蜴溷ァ句ュ礼ャヲ荳イ
|
||
return value as unknown as T;
|
||
}
|
||
} catch (error) {
|
||
logger.error('Redis GET螟ア雍・', { key, error });
|
||
return null; // 髯咲コァ<EFBDBA>夊ソ泌屓null閠御ク肴弍謚帛シょクク
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 隶セ鄂ョ郛灘ュ伜? * @param ttl 霑<>悄譌カ髣エ<E9ABA3>育ァ抵シ会シ御ク堺シ<E5A0BA>蛻呎ーク荳崎ソ<E5B48E>悄<EFBFBD>井ク肴耳闕撰シ<E692B0>
|
||
*/
|
||
async set<T>(key: string, value: T, ttl?: number): Promise<void> {
|
||
try {
|
||
// 蠎丞<E8A08E>蛹門? const serialized = typeof value === 'string'
|
||
? value
|
||
: JSON.stringify(value);
|
||
|
||
// 隶セ鄂ョ蛟シ<E89B9F>亥クヲTTL<54>? if (ttl) {
|
||
await this.redis.setex(key, ttl, serialized);
|
||
logger.debug('Redis SET謌仙粥<E4BB99>亥クヲTTL<54>?, {
|
||
key,
|
||
ttl,
|
||
size: serialized.length
|
||
});
|
||
} else {
|
||
await this.redis.set(key, serialized);
|
||
logger.warn('Redis SET謌仙粥<E4BB99>域裏TTL<54>?, { key }); // 隴ヲ蜻奇シ壽裏霑<E8A38F>悄譌カ髣エ
|
||
}
|
||
} catch (error) {
|
||
logger.error('Redis SET螟ア雍・', { key, ttl, error });
|
||
// 荳肴鴨蜃コ蠑ょクク<EFBDB8>悟<EFBFBD>隶ク邉サ扈溽サァ扈ュ霑占。<E58DA0>
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 蛻<>髯、郛灘ュ<E78198>
|
||
*/
|
||
async delete(key: string): Promise<boolean> {
|
||
try {
|
||
const result = await this.redis.del(key);
|
||
logger.debug('Redis DEL', { key, deleted: result > 0 });
|
||
return result > 0;
|
||
} catch (error) {
|
||
logger.error('Redis DEL螟ア雍・', { key, error });
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 譽譟・key譏ッ蜷ヲ蟄伜惠
|
||
*/
|
||
async has(key: string): Promise<boolean> {
|
||
try {
|
||
const result = await this.redis.exists(key);
|
||
return result > 0;
|
||
} catch (error) {
|
||
logger.error('Redis EXISTS螟ア雍・', { key, error });
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 貂<>ゥコ謇譛臥シ灘ュ假シ亥些髯ゥ謫堺ス懶シ<E687B6>シ<EFBFBD>
|
||
*/
|
||
async clear(): Promise<void> {
|
||
try {
|
||
await this.redis.flushdb();
|
||
logger.warn('Redis FLUSHDB謇ァ陦鯉シ域園譛臥シ灘ュ伜キイ貂<EFBDB2>ゥコ<EFBDA9>?);
|
||
} catch (error) {
|
||
logger.error('Redis FLUSHDB螟ア雍・', { error });
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 豬玖ッ紐edis霑樊磁
|
||
*/
|
||
async ping(): Promise<boolean> {
|
||
try {
|
||
const result = await this.redis.ping();
|
||
return result === 'PONG';
|
||
} catch (error) {
|
||
logger.error('Redis PING螟ア雍・', { error });
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 蜈ウ髣ュ霑樊磁<E6A88A>育畑莠惹シ倬寉蜈ウ髣ュ<E9ABA3><EFBDAD>
|
||
*/
|
||
async disconnect(): Promise<void> {
|
||
try {
|
||
await this.redis.quit();
|
||
logger.info('Redis霑樊磁蟾イ蜈ウ髣?);
|
||
} catch (error) {
|
||
logger.error('Redis蜈ウ髣ュ霑樊磁螟ア雍・', { error });
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### **豁・鬪、2.2<EFBFBD>壽峩譁ーCacheFactory.ts<74>域キサ蜉<EFBDBB>髯咲コァ遲也払<E4B99F><E68995>**
|
||
|
||
```typescript
|
||
// 譁<>サカ<EFBDBB>喘ackend/src/common/cache/CacheFactory.ts
|
||
|
||
import { config } from '../../config/env.js';
|
||
import type { CacheAdapter } from './CacheAdapter.js';
|
||
import { MemoryCacheAdapter } from './MemoryCacheAdapter.js';
|
||
import { RedisCacheAdapter } from './RedisCacheAdapter.js';
|
||
import { logger } from '../logging/index.js';
|
||
|
||
/**
|
||
* 郛灘ュ伜キ・蜴ゑシ亥黒萓具シ<E585B7>
|
||
*
|
||
* 譬ケ謐ョ邇ッ蠅<EFBDAF>序驥剰<E9A9A5>蜉ィ騾画叫郛灘ュ伜ョ樒鴫<E6A892>? * - CACHE_TYPE=memory 竊?MemoryCacheAdapter
|
||
* - CACHE_TYPE=redis 竊?RedisCacheAdapter<65>域髪謖<E9ABAA>剄郤ァ<E983A4><EFBDA7>
|
||
*
|
||
* @example
|
||
* import { cache } from '@/common/cache'
|
||
* await cache.set('user:123', userData, 60)
|
||
* const user = await cache.get<User>('user:123')
|
||
*/
|
||
export class CacheFactory {
|
||
private static instance: CacheAdapter | null = null;
|
||
private static fallbackToMemory = false; // 髯咲コァ譬<EFBDA7>ョー
|
||
|
||
/**
|
||
* 闔キ蜿也シ灘ュ伜ョ樔セ具シ亥黒萓具シ<E585B7>
|
||
*/
|
||
static getInstance(): CacheAdapter {
|
||
if (!this.instance) {
|
||
this.instance = this.createCache();
|
||
}
|
||
return this.instance;
|
||
}
|
||
|
||
/**
|
||
* 蛻帛サコ郛灘ュ伜ョ樔セ<E6A894>
|
||
*/
|
||
private static createCache(): CacheAdapter {
|
||
const cacheType = config.cacheType || 'memory';
|
||
|
||
logger.info('[CacheFactory] 蛻晏ァ句喧郛灘ュ倡ウサ扈?, { cacheType });
|
||
|
||
switch (cacheType) {
|
||
case 'redis':
|
||
return this.createRedisCache();
|
||
case 'memory':
|
||
default:
|
||
return this.createMemoryCache();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 蛻帛サコRedis郛灘ュ假シ亥クヲ髯咲コァ遲也払<E4B99F>? */
|
||
private static createRedisCache(): CacheAdapter {
|
||
try {
|
||
logger.info('[CacheFactory] 豁」蝨ィ霑樊磁Redis...', {
|
||
host: config.redisHost,
|
||
port: config.redisPort,
|
||
db: config.redisDb,
|
||
});
|
||
|
||
const redisCache = new RedisCacheAdapter({
|
||
host: config.redisHost,
|
||
port: config.redisPort,
|
||
password: config.redisPassword,
|
||
db: config.redisDb,
|
||
});
|
||
|
||
// 豬玖ッ戊ソ樊磁<E6A88A>亥酔豁・遲牙セ<E78999>シ<EFBFBD>
|
||
redisCache.ping().then((isConnected) => {
|
||
if (isConnected) {
|
||
logger.info('[CacheFactory] 笨?Redis霑樊磁謌仙粥');
|
||
} else {
|
||
logger.error('[CacheFactory] 笶?Redis霑樊磁螟ア雍・<E99B8D>悟キイ髯咲コァ蛻ー蜀<EFBDB0>ュ倡シ灘ュ?);
|
||
this.fallbackToMemory = true;
|
||
}
|
||
}).catch((error) => {
|
||
logger.error('[CacheFactory] 笶?Redis霑樊磁蠑ょクク<EFBDB8>悟キイ髯咲コァ蛻ー蜀<EFBDB0>ュ倡シ灘ュ?, { error });
|
||
this.fallbackToMemory = true;
|
||
});
|
||
|
||
return redisCache;
|
||
} catch (error) {
|
||
logger.error('[CacheFactory] 笶?Redis蛻晏ァ句喧螟ア雍・<E99B8D>碁剄郤ァ蛻ー蜀<EFBDB0>ュ倡シ灘ュ?, { error });
|
||
this.fallbackToMemory = true;
|
||
return this.createMemoryCache();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 蛻帛サコ蜀<EFBDBA>ュ倡シ灘ュ<E78198>
|
||
*/
|
||
private static createMemoryCache(): MemoryCacheAdapter {
|
||
logger.info('[CacheFactory] 菴ソ逕ィ蜀<EFBDA8>ュ倡シ灘ュ<E78198>');
|
||
return new MemoryCacheAdapter();
|
||
}
|
||
|
||
/**
|
||
* 譽譟・譏ッ蜷ヲ蟾イ髯咲コァ蛻ー蜀<EFBDB0>ュ倡シ灘ュ? */
|
||
static isFallbackMode(): boolean {
|
||
return this.fallbackToMemory;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 蟇シ蜃コ蜊穂セ<E7A982>
|
||
*/
|
||
export const cache = CacheFactory.getInstance();
|
||
```
|
||
|
||
---
|
||
|
||
#### **豁・鬪、2.3<EFBFBD>壽峩譁ーenv.ts驟咲スョ**
|
||
|
||
```typescript
|
||
// 譁<>サカ<EFBDBB>喘ackend/src/config/env.ts
|
||
// 遑ョ菫抒edis驟咲スョ豁」遑ョ隸サ蜿<EFBDBB>
|
||
|
||
export const config = {
|
||
// ... 蜈カ莉夜<E88E89>鄂ョ ...
|
||
|
||
/** 郛灘ュ倡アサ蝙<EFBDBB> */
|
||
cacheType: process.env.CACHE_TYPE || 'memory',
|
||
|
||
/** Redis驟咲スョ */
|
||
redisHost: process.env.REDIS_HOST || 'localhost',
|
||
redisPort: parseInt(process.env.REDIS_PORT || '6379', 10),
|
||
redisPassword: process.env.REDIS_PASSWORD || undefined,
|
||
redisDb: parseInt(process.env.REDIS_DB || '0', 10),
|
||
redisUrl: process.env.REDIS_URL || 'redis://localhost:6379',
|
||
|
||
/** 髦溷<E9ABA6>邀サ蝙<EFBDBB> */
|
||
queueType: process.env.QUEUE_TYPE || 'memory',
|
||
|
||
// ... 蜈カ莉夜<E88E89>鄂ョ ...
|
||
};
|
||
|
||
// 鬪瑚ッ<E7919A><EFBDAF>鄂ョ
|
||
export function validateConfig() {
|
||
console.log('笨?[Config] 邇ッ蠅<EFBDAF>序驥丞刈霓ス謌仙粥');
|
||
console.log('[Config] 蠎皮畑驟咲スョ:');
|
||
console.log(` - 郛灘ュ<E78198>: ${config.cacheType}`);
|
||
console.log(` - 髦溷<E9ABA6>: ${config.queueType}`);
|
||
|
||
if (config.cacheType === 'redis') {
|
||
console.log(` - Redis: ${config.redisHost}:${config.redisPort}/${config.redisDb}`);
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 4.3 Phase 3<>壽悽蝨ー豬玖ッ?笨?
|
||
#### **豁・鬪、3.1<EFBFBD>壼<EFBFBD>蟒コRedis豬玖ッ戊<EFBFBD>譛ャ**
|
||
|
||
```typescript
|
||
// 譁<>サカ<EFBDBB>喘ackend/src/scripts/test-redis.ts
|
||
|
||
import { cache } from '../common/cache/index.js';
|
||
import { logger } from '../common/logging/index.js';
|
||
|
||
async function testRedis() {
|
||
console.log('\n<>ァェ 蠑蟋区オ玖ッ紐edis郛灘ュ<E78198>...\n');
|
||
|
||
try {
|
||
// 豬玖ッ<E78E96>1<EFBFBD>壼渕譛ャ隸サ蜀? console.log('<27>統 豬玖ッ<E78E96>1<EFBFBD>壼渕譛ャ隸サ蜀?);
|
||
await cache.set('test:hello', 'world', 10);
|
||
const value1 = await cache.get('test:hello');
|
||
console.log(` 笨?蜀吝<E89C80>: "hello" 竊?"world"`);
|
||
console.log(` 笨?隸サ蜿<EFBDBB>: "${value1}"`);
|
||
console.assert(value1 === 'world', '蛟シ蠎碑ッ・蛹ケ驟?);
|
||
|
||
// 豬玖ッ<E78E96>2<EFBFBD>壼ッケ雎。蠎丞<E8A08E>蛹<EFBFBD>
|
||
console.log('\n<EFBFBD>統 豬玖ッ<EFBFBD>2<EFBFBD>壼ッケ雎。蠎丞<EFBFBD>蛹<EFBFBD>');
|
||
const obj = { id: 123, name: '豬玖ッ<EFBFBD>', data: [1, 2, 3] };
|
||
await cache.set('test:object', obj, 10);
|
||
const value2 = await cache.get<typeof obj>('test:object');
|
||
console.log(` 笨?蜀吝<E89C80>蟇ケ雎。:`, obj);
|
||
console.log(` 笨?隸サ蜿門ッケ雎。:`, value2);
|
||
console.assert(value2?.id === 123, 'ID蠎碑ッ・蛹ケ驟<EFBFBD>');
|
||
|
||
// 豬玖ッ<E78E96>3<EFBFBD>啜TL霑<4C>悄
|
||
console.log('\n<EFBFBD>統 豬玖ッ<EFBFBD>3<EFBFBD>啜TL霑<EFBFBD>悄<EFBFBD>?遘抵シ<EFBFBD>');
|
||
await cache.set('test:expire', 'will-expire', 2);
|
||
console.log(` 笨?蜀吝<E89C80><E5909D><EFBFBD>TL=2遘抵シ荏);
|
||
|
||
console.log(` 竢?遲牙セ<E78999>1遘?..`);
|
||
await sleep(1000);
|
||
const value3a = await cache.get('test:expire');
|
||
console.log(` 笨?1遘貞錘隸サ蜿<EFBDBB>: "${value3a}"`);
|
||
console.assert(value3a === 'will-expire', '蠎碑ッ・霑伜ュ伜<EFBFBD>?);
|
||
|
||
console.log(` 竢?遲牙セ<E78999>2遘?..`);
|
||
await sleep(2000);
|
||
const value3b = await cache.get('test:expire');
|
||
console.log(` 笨?3遘貞錘隸サ蜿<EFBDBB>: ${value3b}`);
|
||
console.assert(value3b === null, '蠎碑ッ・蟾イ霑<EFBDB2><E99C91>?);
|
||
|
||
// 豬玖ッ<E78E96>4<EFBFBD>喇as蜥慧elete
|
||
console.log('\n<EFBFBD>統 豬玖ッ<EFBFBD>4<EFBFBD>喇as蜥慧elete');
|
||
await cache.set('test:delete', 'to-be-deleted', 10);
|
||
const exists1 = await cache.has('test:delete');
|
||
console.log(` 笨?蜀吝<E89C80>蜷仔xists: ${exists1}`);
|
||
|
||
await cache.delete('test:delete');
|
||
const exists2 = await cache.has('test:delete');
|
||
console.log(` 笨?蛻<>髯、蜷仔xists: ${exists2}`);
|
||
console.assert(!exists2, '蠎碑ッ・荳榊ュ伜<EFBFBD>?);
|
||
|
||
// 豬玖ッ<E78E96>5<EFBFBD>壼、ァ蟇ケ雎。<E99B8E>?0KB<4B>? console.log('\n<>統 豬玖ッ<E78E96>5<EFBFBD>壼、ァ蟇ケ雎。郛灘ュ假シ域ィ。諡櫚LM扈捺棡<E68DBA>?);
|
||
const bigObj = {
|
||
literatureId: 'xxx',
|
||
fields: {
|
||
遐皮ゥカ邀サ蝙<EFBFBD>: 'RCT',
|
||
譬キ譛ャ驥? '500',
|
||
蟷イ鬚<EFBFBD>蒔譁ス: '闕ッ迚ゥA 100mg',
|
||
// ... 12荳ェ蟄玲ョ? },
|
||
metadata: {
|
||
model: 'deepseek-v3',
|
||
tokens: 8000,
|
||
timestamp: Date.now(),
|
||
},
|
||
rawOutput: 'x'.repeat(40000), // 讓。諡溷、ァ霎灘<E99C8E>? };
|
||
|
||
const start = Date.now();
|
||
await cache.set('test:bigobj', bigObj, 3600);
|
||
const value5 = await cache.get('test:bigobj');
|
||
const duration = Date.now() - start;
|
||
|
||
const size = JSON.stringify(bigObj).length;
|
||
console.log(` 笨?蜀吝<E89C80>+隸サ蜿門、ァ蟇ケ雎? ${size} bytes<65>瑚玲慮 ${duration}ms`);
|
||
console.assert(value5 !== null, '蠎碑ッ・閭ス隸サ蜿?);
|
||
|
||
console.log('\n笨?謇譛画オ玖ッ暮夊ソ<EFBFBD>シ―n');
|
||
process.exit(0);
|
||
} catch (error) {
|
||
console.error('\n笶?豬玖ッ募、ア雍・:', error);
|
||
process.exit(1);
|
||
}
|
||
}
|
||
|
||
function sleep(ms: number): Promise<void> {
|
||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||
}
|
||
|
||
// 霑占。梧オ玖ッ<E78E96>
|
||
testRedis();
|
||
```
|
||
|
||
#### **豁・鬪、3.2<EFBFBD>壽鴬陦梧オ玖ッ?*
|
||
```bash
|
||
cd backend
|
||
|
||
# 1. 蜷ッ蜉ィ蜷守ォッ<EFBDAB>育。ョ菫抒edis驟咲スョ逕滓譜<E6BB93>?npm run dev
|
||
|
||
# 2. 譁ー蠑荳荳ェ扈育ォッ<EFBDAB>瑚ソ占。梧オ玖ッ戊<EFBDAF>譛ャ
|
||
npx tsx src/scripts/test-redis.ts
|
||
```
|
||
|
||
**鬚<>悄霎灘<E99C8E>**<EFBFBD>?```
|
||
<EFBFBD>ァェ 蠑蟋区オ玖ッ紐edis郛灘ュ<E78198>...
|
||
|
||
<EFBFBD>統 豬玖ッ<E78E96>1<EFBFBD>壼渕譛ャ隸サ蜀? 笨?蜀吝<E89C80>: "hello" 竊?"world"
|
||
笨?隸サ蜿<EFBDBB>: "world"
|
||
|
||
<EFBFBD>統 豬玖ッ<E78E96>2<EFBFBD>壼ッケ雎。蠎丞<E8A08E>蛹<EFBFBD>
|
||
笨?蜀吝<E89C80>蟇ケ雎。: { id: 123, name: '豬玖ッ<E78E96>', data: [ 1, 2, 3 ] }
|
||
笨?隸サ蜿門ッケ雎。: { id: 123, name: '豬玖ッ<E78E96>', data: [ 1, 2, 3 ] }
|
||
|
||
<EFBFBD>統 豬玖ッ<E78E96>3<EFBFBD>啜TL霑<4C>悄<EFBFBD>?遘抵シ<E68AB5>
|
||
笨?蜀吝<E89C80><E5909D><EFBFBD>TL=2遘抵シ<E68AB5>
|
||
竢?遲牙セ<E78999>1遘?..
|
||
笨?1遘貞錘隸サ蜿<EFBDBB>: "will-expire"
|
||
竢?遲牙セ<E78999>2遘?..
|
||
笨?3遘貞錘隸サ蜿<EFBDBB>: null
|
||
|
||
<EFBFBD>統 豬玖ッ<E78E96>4<EFBFBD>喇as蜥慧elete
|
||
笨?蜀吝<E89C80>蜷仔xists: true
|
||
笨?蛻<>髯、蜷仔xists: false
|
||
|
||
<EFBFBD>統 豬玖ッ<E78E96>5<EFBFBD>壼、ァ蟇ケ雎。郛灘ュ假シ域ィ。諡櫚LM扈捺棡<E68DBA>? 笨?蜀吝<E89C80>+隸サ蜿門、ァ蟇ケ雎? 40123 bytes<65>瑚玲慮 5ms
|
||
|
||
笨?謇譛画オ玖ッ暮夊ソ<E5A48A>シ?```
|
||
|
||
---
|
||
|
||
#### **豁・鬪、3.3<EFBFBD>壽オ玖ッ穂ク壼苅莉」遐?*
|
||
|
||
```bash
|
||
# 1. 豬玖ッ菱ealthCheckService<63><65>C讓。蝮暦シ?# 荳贋シ<E8B48B>荳荳ェExcel譁<6C>サカ<EFBDBB>梧衍逵区律蠢暦シ<E69AA6>
|
||
|
||
[HealthCheck] Cache miss, processing file
|
||
[HealthCheck] Check completed
|
||
[HealthCheck] Cache SET: health:xxx, TTL=86400
|
||
|
||
# 隨ャ莠梧ャ。荳贋シ<E8B48B>蜷御ク荳ェ譁<EFBDAA>サ?[HealthCheck] Cache hit 竊?謌仙粥莉山edis隸サ蜿<EFBDBB>
|
||
```
|
||
|
||
```bash
|
||
# 2. 豬玖ッ畢LM12FieldsService<63><65>SL讓。蝮暦シ?# 謠蝉コ、蜈ィ譁<EFBDA8>、咲ュ帑ササ蜉。<E89C89>梧衍逵区律蠢暦シ<E69AA6>
|
||
|
||
[LLM12FieldsService] 隹<>畑LLM謠仙叙12蟄玲ョオ
|
||
[LLM12FieldsService] Result cached with key: fulltext:xxx
|
||
[LLM12FieldsService] 郛灘ュ伜<EFBDAD>蜈・謌仙粥
|
||
|
||
# 驥肴眠霑占。悟酔荳遽⑰DF
|
||
[LLM12FieldsService] Cache hit, returning cached result 竊?闃ら怐API雍ケ逕ィ<E98095>?```
|
||
|
||
---
|
||
|
||
### 4.4 Phase 4<>夐仭驥御コ然edis驟咲スョ 笨?
|
||
#### **豁・鬪、4.1<EFBFBD>夊エュ荵ーRedis螳樔セ<EFBFBD>**
|
||
|
||
1. 逋サ蠖暮仭驥御コ第而蛻カ蜿ー
|
||
2. 霑帛<E99C91> **莠第焚謐ョ蠎<EFBDAE> Redis** 莠ァ蜩<EFBDA7>。?3. 轤ケ蜃サ **蛻帛サコ螳樔セ<E6A894>**
|
||
4. 謖臥<E8AC96>謌ェ蝗セ驟咲スョ騾画叫<E794BB>? - 莠ァ蜩<EFBDA7>シ啌edis 蠑貅千沿
|
||
- 驛ィ鄂イ讓。蠑擾シ壻コ大次逕滂シ磯ォ伜庄逕ィ<E98095>? - 蝨ー蝓滂シ壼克蛹?<3F>亥圏莠ャ<E88EA0>俄披?**荳惨AE蜷悟慍蝓滂シ<E6BB82>**
|
||
- 迚域悽<E59F9F>啌edis 7.0
|
||
- 蛻<>援隗<E68FB4><E99A97>シ<EFBFBD>?56 MB
|
||
- 莉倩エケ譁ケ蠑擾シ壼桁蟷エ蛹<EFBDB4><E89BB9>?5. 謠蝉コ、隶「蜊募ケカ謾ッ莉?
|
||
#### **豁・鬪、4.2<EFBFBD>夐<EFBFBD>鄂ョ逋ス蜷榊黒**
|
||
|
||
```
|
||
髦ソ驥御コ第而蛻カ蜿ー 竊?Redis螳樔セ<E6A894> 竊?逋ス蜷榊黒隶セ鄂?
|
||
豺サ蜉<EFBFBD><EFBFBD>?1. 譛ャ蝨ー蠑蜿選P<E981B8>育畑莠取悽蝨ー豬玖ッ包シ<E58C85>
|
||
- 菴<>逧<EFBFBD><E980A7>鄂選P/32
|
||
|
||
2. SAE蠎皮畑IP<49>育函莠ァ邇ッ蠅<EFBDAF>シ<EFBFBD>
|
||
- 0.0.0.0/0 <20>井クエ譌カ<E8AD8C>悟錘扈ュ謾ケ荳コSAE VPC<50>? 謌? - SAE螳樔セ狗噪VPC鄂第ョオ
|
||
```
|
||
|
||
#### **豁・鬪、4.3<EFBFBD>夊執蜿冶ソ樊磁菫。諱?*
|
||
|
||
```
|
||
髦ソ驥御コ第而蛻カ蜿ー 竊?Redis螳樔セ<E6A894> 竊?霑樊磁菫。諱ッ
|
||
|
||
螟榊宛莉・荳倶ソ。諱ッ<EFBFBD>?- 霑樊磁蝨ー蝮<E89DAE>嗷-xxxxxxxxxxxx.redis.rds.aliyuncs.com
|
||
- 遶ッ蜿」<E89CBF>?379
|
||
- 螳樔セ紀D<E7B480>嗷-xxxxxxxxxxxx
|
||
- 蟇<><E89F87><EFBFBD>シ夂せ蜃?菫ョ謾ケ蟇<EFBDB9><E89F87><EFBFBD>"隶セ鄂ョ
|
||
```
|
||
|
||
#### **豁・鬪、4.4<EFBFBD>壽峩譁ーSAE邇ッ蠅<EFBFBD>序驥<EFBFBD>**
|
||
|
||
```
|
||
髦ソ驥御コ第而蛻カ蜿ー 竊?SAE蠎皮畑 竊?驟咲スョ邂。逅<EFBDA1> 竊?邇ッ蠅<EFBDAF>序驥<E5BA8F>
|
||
|
||
豺サ蜉<EFBFBD><EFBFBD>?CACHE_TYPE=redis
|
||
REDIS_HOST=r-xxxxxxxxxxxx.redis.rds.aliyuncs.com
|
||
REDIS_PORT=6379
|
||
REDIS_PASSWORD=菴<>隶セ鄂ョ逧<EFBDAE>ッ<EFBFBD><EFBDAF><EFBFBD>
|
||
REDIS_DB=0
|
||
```
|
||
|
||
---
|
||
|
||
### 4.5 Phase 5<>壼星逕ィRedis髦溷<E9ABA6> <20>閥 **蠢<>。サ螳樊命**
|
||
|
||
> **驥崎ヲ∝序譖エ**<2A>夂サ丞<EFBDBB>譫撰シ軍edis髦溷<E9ABA6>蟇ケASL蜥轡C Tool B讓。蝮玲<E89DAE>?*蠢<>。サ逧?*<2A>御ク肴弍蜿ッ騾臥噪<E887A5>?
|
||
> **逅<>罰**<2A>?蟆乗慮髟ソ莉サ蜉。蝨ィSAE邇ッ蠅<EFBDAF>ク倶ク咲畑Redis髦溷<E9ABA6>螟ア雍・邇?> 95%
|
||
|
||
#### **豁・鬪、5.1<EFBFBD>壼ョ芽」<EFBFBD>ullMQ**
|
||
|
||
```bash
|
||
cd backend
|
||
npm install bullmq --save
|
||
|
||
# BullMQ蟾イ蝨ィpackage.json荳ュ<E88DB3>悟宵髴遑ョ隶、螳芽」<E88ABD>
|
||
npm list bullmq
|
||
# 蠎碑ッ・譏セ遉コ<E98189>喘ullmq@5.65.0
|
||
```
|
||
|
||
#### **豁・鬪、5.2<EFBFBD>壼ョ樒鴫RedisQueue.ts**
|
||
|
||
```typescript
|
||
// 譁<>サカ<EFBDBB>喘ackend/src/common/jobs/RedisQueue.ts
|
||
|
||
import { Queue, Worker, Job as BullJob, QueueEvents } from 'bullmq';
|
||
import type { Job, JobQueue, JobHandler } from './types.js';
|
||
import { logger } from '../logging/index.js';
|
||
import { config } from '../../config/env.js';
|
||
|
||
/**
|
||
* Redis髦溷<E9ABA6>螳樒鴫<E6A892>亥渕莠撮ullMQ<4D>? *
|
||
* 譬ク蠢<EFBDB8>粥閭ス<E996AD>? * - 莉サ蜉。謖∽ケ<E288BD>喧<EFBFBD>亥ョ樔セ矩㍾蜷ッ荳堺ク「螟ア<E89E9F><EFBDB1>
|
||
* - 閾ェ蜉ィ驥崎ッ包シ亥、ア雍・蜷取欠謨ー騾驕ソ<E9A995><EFBDBF>
|
||
* - 蛻<>ク<EFBFBD>シ丈ササ蜉。蛻<EFBDA1><E89BBB><EFBFBD>亥、壼ョ樔セ句刻隹<E588BB>シ<EFBFBD>
|
||
* - 霑帛コヲ霍溯クェ
|
||
*/
|
||
export class RedisQueue implements JobQueue {
|
||
private queues: Map<string, Queue> = new Map();
|
||
private workers: Map<string, Worker> = new Map();
|
||
private queueEvents: Map<string, QueueEvents> = new Map();
|
||
|
||
private connection = {
|
||
host: config.redisHost,
|
||
port: config.redisPort,
|
||
password: config.redisPassword,
|
||
db: config.redisDb,
|
||
};
|
||
|
||
/**
|
||
* 謗ィ騾∽ササ蜉。蛻ー髦溷<E9ABA6>
|
||
*/
|
||
async push<T = any>(type: string, data: T, options?: any): Promise<Job> {
|
||
try {
|
||
// 闔キ蜿匁<E89CBF>蛻帛サコ髦溷<E9ABA6>? let queue = this.queues.get(type);
|
||
if (!queue) {
|
||
queue = new Queue(type, {
|
||
connection: this.connection,
|
||
defaultJobOptions: {
|
||
removeOnComplete: 100, // 菫晉蕗譛霑?00荳ェ螳梧<E89EB3>莉サ蜉? removeOnFail: false, // 螟ア雍・莉サ蜉。荳榊唖髯、<E9ABAF>井セソ莠取賜譟・<E8AD9F>? attempts: 3, // 螟ア雍・驥崎ッ<E5B48E>3谺? backoff: {
|
||
type: 'exponential',
|
||
delay: 2000, // 2遘偵?遘偵?遘? },
|
||
}
|
||
});
|
||
this.queues.set(type, queue);
|
||
}
|
||
|
||
// 豺サ蜉<EFBDBB>莉サ蜉。
|
||
const job = await queue.add(type, data, {
|
||
...options,
|
||
jobId: options?.jobId, // 謾ッ謖∬<E8AC96>螳壻ケ泳obId
|
||
});
|
||
|
||
logger.info(`[RedisQueue] 莉サ蜉。蜈・髦滓<E9ABA6>蜉歔, {
|
||
type,
|
||
jobId: job.id,
|
||
dataSize: JSON.stringify(data).length
|
||
});
|
||
|
||
return {
|
||
id: job.id!,
|
||
type,
|
||
data,
|
||
status: 'pending',
|
||
createdAt: new Date(),
|
||
};
|
||
} catch (error) {
|
||
logger.error(`[RedisQueue] 莉サ蜉。蜈・髦溷、ア雍・`, { type, error });
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 豕ィ蜀御ササ蜉。螟<EFBDA1>炊蝎? */
|
||
process<T = any>(type: string, handler: JobHandler<T>): void {
|
||
try {
|
||
// 蛻帛サコWorker
|
||
const worker = new Worker(
|
||
type,
|
||
async (job: BullJob) => {
|
||
logger.info(`[RedisQueue] 蠑蟋句、<E58FA5>炊莉サ蜉。`, {
|
||
type,
|
||
jobId: job.id,
|
||
attemptsMade: job.attemptsMade,
|
||
attemptsTotal: job.opts.attempts
|
||
});
|
||
|
||
const startTime = Date.now();
|
||
|
||
try {
|
||
// 隹<>畑荳壼苅螟<E88B85>炊蜃ス謨ー
|
||
const result = await handler({
|
||
id: job.id!,
|
||
type,
|
||
data: job.data as T,
|
||
status: 'processing',
|
||
createdAt: new Date(job.timestamp),
|
||
});
|
||
|
||
const duration = Date.now() - startTime;
|
||
logger.info(`[RedisQueue] 莉サ蜉。螟<EFBDA1>炊謌仙粥`, {
|
||
type,
|
||
jobId: job.id,
|
||
duration: `${duration}ms`
|
||
});
|
||
|
||
return result;
|
||
} catch (error) {
|
||
const duration = Date.now() - startTime;
|
||
logger.error(`[RedisQueue] 莉サ蜉。螟<EFBDA1>炊螟ア雍・`, {
|
||
type,
|
||
jobId: job.id,
|
||
attemptsMade: job.attemptsMade,
|
||
duration: `${duration}ms`,
|
||
error: error instanceof Error ? error.message : 'Unknown error'
|
||
});
|
||
throw error; // 謚帛<E8AC9A>髞呵ッッ<EFBDAF>瑚ァヲ蜿鷹㍾隸? }
|
||
},
|
||
{
|
||
connection: this.connection,
|
||
concurrency: 1, // 豈丈クェWorker蟷カ蜿大、<E5A4A7>炊1荳ェ莉サ蜉? }
|
||
);
|
||
|
||
this.workers.set(type, worker);
|
||
|
||
// 逶大成Worker莠倶サカ
|
||
worker.on('completed', (job) => {
|
||
logger.info(`[RedisQueue] 笨?莉サ蜉。螳梧<E89EB3>`, {
|
||
type,
|
||
jobId: job.id,
|
||
returnvalue: job.returnvalue
|
||
});
|
||
});
|
||
|
||
worker.on('failed', (job, err) => {
|
||
logger.error(`[RedisQueue] 笶?莉サ蜉。螟ア雍・`, {
|
||
type,
|
||
jobId: job?.id,
|
||
attemptsMade: job?.attemptsMade,
|
||
error: err.message,
|
||
stack: err.stack
|
||
});
|
||
});
|
||
|
||
worker.on('error', (err) => {
|
||
logger.error(`[RedisQueue] Worker髞呵ッッ`, { type, error: err.message });
|
||
});
|
||
|
||
logger.info(`[RedisQueue] Worker蟾イ豕ィ蜀形, { type });
|
||
|
||
} catch (error) {
|
||
logger.error(`[RedisQueue] Worker豕ィ蜀悟、ア雍・`, { type, error });
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 闔キ蜿紋ササ蜉。迥カ諤? */
|
||
async getJob(id: string): Promise<Job | null> {
|
||
try {
|
||
// 驕榊紙謇譛蛾弌蛻玲衍謇セ莉サ蜉? for (const [type, queue] of this.queues) {
|
||
const job = await queue.getJob(id);
|
||
if (job) {
|
||
return {
|
||
id: job.id!,
|
||
type,
|
||
data: job.data,
|
||
status: await this.getJobStatus(job),
|
||
progress: job.progress as number || 0,
|
||
createdAt: new Date(job.timestamp),
|
||
error: job.failedReason,
|
||
};
|
||
}
|
||
}
|
||
return null;
|
||
} catch (error) {
|
||
logger.error(`[RedisQueue] getJob螟ア雍・`, { id, error });
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 闔キ蜿紋ササ蜉。迥カ諤? */
|
||
private async getJobStatus(job: BullJob): Promise<string> {
|
||
const state = await job.getState();
|
||
switch (state) {
|
||
case 'completed': return 'completed';
|
||
case 'failed': return 'failed';
|
||
case 'active': return 'processing';
|
||
case 'waiting': return 'pending';
|
||
case 'delayed': return 'pending';
|
||
default: return 'pending';
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 譖エ譁ー莉サ蜉。霑帛コヲ
|
||
*/
|
||
async updateProgress(id: string, progress: number, message?: string): Promise<void> {
|
||
try {
|
||
for (const queue of this.queues.values()) {
|
||
const job = await queue.getJob(id);
|
||
if (job) {
|
||
await job.updateProgress(progress);
|
||
if (message) {
|
||
await job.log(message);
|
||
}
|
||
logger.debug(`[RedisQueue] 霑帛コヲ譖エ譁ー`, { id, progress, message });
|
||
return;
|
||
}
|
||
}
|
||
logger.warn(`[RedisQueue] 莉サ蜉。荳榊ュ伜惠<E4BC9C>梧裏豕墓峩譁ー霑帛コヲ`, { id });
|
||
} catch (error) {
|
||
logger.error(`[RedisQueue] 譖エ譁ー霑帛コヲ螟ア雍・`, { id, error });
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 蜿匁カ井ササ蜉。
|
||
*/
|
||
async cancelJob(id: string): Promise<boolean> {
|
||
try {
|
||
for (const queue of this.queues.values()) {
|
||
const job = await queue.getJob(id);
|
||
if (job) {
|
||
await job.remove();
|
||
logger.info(`[RedisQueue] 莉サ蜉。蟾イ蜿匁カ<E58C81>, { id });
|
||
return true;
|
||
}
|
||
}
|
||
logger.warn(`[RedisQueue] 莉サ蜉。荳榊ュ伜惠<E4BC9C>梧裏豕募叙豸<E58F99>, { id });
|
||
return false;
|
||
} catch (error) {
|
||
logger.error(`[RedisQueue] 蜿匁カ井ササ蜉。螟ア雍・`, { id, error });
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 驥崎ッ募、ア雍・莉サ蜉。
|
||
*/
|
||
async retryJob(id: string): Promise<boolean> {
|
||
try {
|
||
for (const queue of this.queues.values()) {
|
||
const job = await queue.getJob(id);
|
||
if (job) {
|
||
await job.retry();
|
||
logger.info(`[RedisQueue] 莉サ蜉。蟾イ驥崎ッ描, { id });
|
||
return true;
|
||
}
|
||
}
|
||
logger.warn(`[RedisQueue] 莉サ蜉。荳榊ュ伜惠<E4BC9C>梧裏豕暮㍾隸描, { id });
|
||
return false;
|
||
} catch (error) {
|
||
logger.error(`[RedisQueue] 驥崎ッ穂ササ蜉。螟ア雍・`, { id, error });
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 貂<>炊譌ァ莉サ蜉? */
|
||
async cleanup(olderThan: number = 86400000): Promise<number> {
|
||
try {
|
||
let totalCleaned = 0;
|
||
|
||
for (const [type, queue] of this.queues) {
|
||
// 貂<>炊螳梧<E89EB3>逧<EFBFBD>ササ蜉。<E89C89>井ソ晉蕗譛霑?00荳ェ<E88DB3><EFBDAA>
|
||
const completed = await queue.clean(olderThan, 100, 'completed');
|
||
// 貂<>炊螟ア雍・逧<EFBDA5>ササ蜉。<E89C89>井ソ晉蕗譛霑?0荳ェ<E88DB3><EFBDAA>
|
||
const failed = await queue.clean(olderThan, 50, 'failed');
|
||
|
||
const cleaned = completed.length + failed.length;
|
||
totalCleaned += cleaned;
|
||
|
||
if (cleaned > 0) {
|
||
logger.info(`[RedisQueue] 髦溷<E9ABA6>貂<EFBFBD>炊螳梧<E89EB3>`, {
|
||
type,
|
||
completed: completed.length,
|
||
failed: failed.length
|
||
});
|
||
}
|
||
}
|
||
|
||
return totalCleaned;
|
||
} catch (error) {
|
||
logger.error(`[RedisQueue] 貂<>炊莉サ蜉。螟ア雍・`, { error });
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 蜈ウ髣ュ謇譛芽ソ樊磁<E6A88A>井シ倬寉蜈ウ髣ュ<E9ABA3>? */
|
||
async close(): Promise<void> {
|
||
try {
|
||
// 蜈ウ髣ュ謇譛姥orkers
|
||
for (const [type, worker] of this.workers) {
|
||
await worker.close();
|
||
logger.info(`[RedisQueue] Worker蟾イ蜈ウ髣ュ`, { type });
|
||
}
|
||
|
||
// 蜈ウ髣ュ謇譛渦ueues
|
||
for (const [type, queue] of this.queues) {
|
||
await queue.close();
|
||
logger.info(`[RedisQueue] Queue蟾イ蜈ウ髣ュ`, { type });
|
||
}
|
||
|
||
// 蜈ウ髣ュ謇譛渦ueueEvents
|
||
for (const [type, events] of this.queueEvents) {
|
||
await events.close();
|
||
logger.info(`[RedisQueue] QueueEvents蟾イ蜈ウ髣ュ`, { type });
|
||
}
|
||
|
||
logger.info(`[RedisQueue] 謇譛芽ソ樊磁蟾イ蜈ウ髣ュ`);
|
||
} catch (error) {
|
||
logger.error(`[RedisQueue] 蜈ウ髣ュ霑樊磁螟ア雍・`, { error });
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### **豁・鬪、5.3<EFBFBD>壽峩譁ーJobFactory謾ッ謖ヽedis髦溷<EFBFBD>**
|
||
|
||
```typescript
|
||
// 譁<>サカ<EFBDBB>喘ackend/src/common/jobs/JobFactory.ts
|
||
|
||
import { JobQueue } from './types.js'
|
||
import { MemoryQueue } from './MemoryQueue.js'
|
||
import { RedisQueue } from './RedisQueue.js' // 竊?譁ー蠅<EFBDB0>
|
||
import { logger } from '../logging/index.js'
|
||
import { config } from '../../config/env.js'
|
||
|
||
export class JobFactory {
|
||
private static instance: JobQueue | null = null
|
||
|
||
static getInstance(): JobQueue {
|
||
if (!this.instance) {
|
||
this.instance = this.createQueue()
|
||
}
|
||
return this.instance
|
||
}
|
||
|
||
private static createQueue(): JobQueue {
|
||
const queueType = config.queueType || 'memory'
|
||
|
||
logger.info('[JobFactory] 蛻晏ァ句喧莉サ蜉。髦溷<E9ABA6>?, { queueType });
|
||
|
||
switch (queueType) {
|
||
case 'redis': // 竊?譁ー蠅<EFBDB0>
|
||
return this.createRedisQueue()
|
||
|
||
case 'memory':
|
||
return this.createMemoryQueue()
|
||
|
||
default:
|
||
logger.warn(`[JobFactory] Unknown QUEUE_TYPE: ${queueType}, fallback to memory`)
|
||
return this.createMemoryQueue()
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 蛻帛サコRedis髦溷<E9ABA6><E6BAB7>亥クヲ髯咲コァ遲也払<E4B99F>? */
|
||
private static createRedisQueue(): JobQueue {
|
||
try {
|
||
logger.info('[JobFactory] 豁」蝨ィ霑樊磁Redis髦溷<E9ABA6>...');
|
||
|
||
const redisQueue = new RedisQueue();
|
||
|
||
logger.info('[JobFactory] 笨?Redis髦溷<E9ABA6>蛻晏ァ句喧謌仙<E8AC8C>?);
|
||
return redisQueue;
|
||
|
||
} catch (error) {
|
||
logger.error('[JobFactory] 笶?Redis髦溷<E9ABA6>蛻晏ァ句喧螟ア雍・<E99B8D>碁剄郤ァ蛻ー蜀<EFBDB0>ュ倬弌蛻?, { error });
|
||
return this.createMemoryQueue();
|
||
}
|
||
}
|
||
|
||
private static createMemoryQueue(): MemoryQueue {
|
||
logger.info('[JobFactory] 菴ソ逕ィ蜀<EFBDA8>ュ倬弌蛻<E5BC8C>')
|
||
|
||
const queue = new MemoryQueue()
|
||
|
||
// 螳壽悄貂<E68284>炊<EFBFBD>磯∩蜈榊<E89C88>蟄俶ウ<E4BFB6>シ擾シ<E693BE>
|
||
if (process.env.NODE_ENV !== 'test') {
|
||
setInterval(() => {
|
||
queue.cleanup()
|
||
}, 60 * 60 * 1000)
|
||
}
|
||
|
||
return queue
|
||
}
|
||
|
||
static reset(): void {
|
||
this.instance = null
|
||
}
|
||
}
|
||
```
|
||
|
||
#### **豁・鬪、5.4<EFBFBD>壻ソョ謾ケ荳壼苅莉」遐∽スソ逕ィ髦溷<EFBFBD>?*
|
||
|
||
```typescript
|
||
// 遉コ萓具シ哂SL譁<4C>鍵遲幃画隼騾?// 譁<>サカ<EFBDBB>喘ackend/src/modules/asl/services/screeningService.ts
|
||
|
||
import { jobQueue } from '../../../common/jobs/index.js';
|
||
|
||
export async function startScreeningTask(projectId: string, userId: string) {
|
||
// 1. 蛻帛サコ謨ー謐ョ蠎謎ササ蜉。隶ー蠖? const task = await prisma.aslScreeningTask.create({
|
||
data: {
|
||
projectId,
|
||
status: 'pending',
|
||
totalItems: literatures.length,
|
||
// ...
|
||
}
|
||
});
|
||
|
||
// 2. 謗ィ騾∝芦Redis髦溷<E9ABA6><E6BAB7>井ク埼仆蝪櫁ッキ豎ゑシ? await jobQueue.push('asl:title-screening', {
|
||
taskId: task.id,
|
||
projectId,
|
||
literatureIds: literatures.map(lit => lit.id),
|
||
});
|
||
|
||
logger.info('莉サ蜉。蟾イ蜈・髦?, { taskId: task.id });
|
||
|
||
// 3. 遶句叉霑泌屓<E6B38C>亥燕遶ッ霓ョ隸「霑帛コヲ<EFBDBA><EFBDA6>
|
||
return task;
|
||
}
|
||
|
||
// 豕ィ蜀係orker<65>亥惠蠎皮畑蜷ッ蜉ィ譌カ<E8AD8C><EFBDB6>
|
||
// 譁<>サカ<EFBDBB>喘ackend/src/index.ts
|
||
jobQueue.process('asl:title-screening', async (job) => {
|
||
const { taskId, projectId, literatureIds } = job.data;
|
||
|
||
logger.info('蠑蟋句、<E58FA5>炊遲幃我ササ蜉?, { taskId, total: literatureIds.length });
|
||
|
||
for (let i = 0; i < literatureIds.length; i++) {
|
||
const literatureId = literatureIds[i];
|
||
|
||
// 螟<>炊蜊慕ッ<E68595>枚迪ョ
|
||
await processSingleLiterature(literatureId, projectId);
|
||
|
||
// 譖エ譁ー霑帛コヲ
|
||
const progress = ((i + 1) / literatureIds.length) * 100;
|
||
await jobQueue.updateProgress(job.id, progress);
|
||
|
||
// 譖エ譁ー謨ー謐ョ蠎? await prisma.aslScreeningTask.update({
|
||
where: { id: taskId },
|
||
data: { processedItems: i + 1 }
|
||
});
|
||
}
|
||
|
||
// 譬<>ョー螳梧<E89EB3>
|
||
await prisma.aslScreeningTask.update({
|
||
where: { id: taskId },
|
||
data: { status: 'completed', completedAt: new Date() }
|
||
});
|
||
|
||
logger.info('遲幃我ササ蜉。螳梧<E89EB3>?, { taskId });
|
||
|
||
return { success: true, processed: literatureIds.length };
|
||
});
|
||
```
|
||
|
||
#### **豁・鬪、5.5<EFBFBD>壽峩譁?env驟咲スョ**
|
||
|
||
```env
|
||
# backend/.env
|
||
|
||
# ==================== 莉サ蜉。髦溷<E9ABA6>驟咲スョ ====================
|
||
QUEUE_TYPE=redis # 竊?謾ケ荳コredis
|
||
|
||
# Redis驟咲スョ<EFBDBD>井ク守シ灘ュ伜<EFBDAD>逕ィ<E98095>?REDIS_HOST=localhost
|
||
REDIS_PORT=6379
|
||
REDIS_PASSWORD=
|
||
REDIS_DB=0
|
||
```
|
||
|
||
#### **豁・鬪、5.6<EFBFBD>壽オ玖ッ紐edis髦溷<EFBFBD>**
|
||
|
||
```bash
|
||
# 1. 蜷ッ蜉ィ蜷守ォッ
|
||
cd backend
|
||
npm run dev
|
||
|
||
# 蠎碑ッ・逵句芦譌・蠢暦シ?# [JobFactory] 豁」蝨ィ霑樊磁Redis髦溷<E9ABA6>...
|
||
# [JobFactory] 笨?Redis髦溷<E9ABA6>蛻晏ァ句喧謌仙<E8AC8C>?
|
||
# 2. 謠蝉コ、豬玖ッ穂ササ蜉。<E89C89>井スソ逕ィREST Client謌鳳ostman<61>?POST http://localhost:3001/api/v1/asl/projects/:projectId/screening
|
||
|
||
# 3. 隗ょッ滓律蠢<E5BE8B>
|
||
# [RedisQueue] 莉サ蜉。蜈・髦滓<E9ABA6>蜉<EFBFBD> { type: 'asl:title-screening', jobId: '1' }
|
||
# [RedisQueue] 蠑蟋句、<E58FA5>炊莉サ蜉?{ type: 'asl:title-screening', jobId: '1' }
|
||
# [RedisQueue] 笨?莉サ蜉。螳梧<E89EB3> { type: 'asl:title-screening', jobId: '1' }
|
||
|
||
# 4. 豬玖ッ募ョ樔セ矩㍾蜷ッ諱「螟<EFBDA2>
|
||
# 謠蝉コ、莉サ蜉。 竊?遲牙セ<E78999>、<EFBFBD>炊蛻?0% 竊?Ctrl+C蛛懈ュ「 竊?驥肴眠蜷ッ蜉ィ
|
||
# 莉サ蜉。蠎碑ッ・閾ェ蜉ィ莉山edis諱「螟榊ケカ扈ァ扈ュ螟<EFBDAD><E89E9F>?```
|
||
|
||
---
|
||
|
||
## 5. 豬玖ッ墓婿譯<E5A9BF>
|
||
|
||
### 5.1 蜊募<E89C8A>豬玖ッ墓ク<E5A293>黒
|
||
|
||
| 豬玖ッ暮。?| 鬚<>悄扈捺棡 | 螳樣刔扈捺棡 | 迥カ諤?|
|
||
|--------|---------|---------|------|
|
||
| Redis霑樊磁豬玖ッ<E78E96> | PONG | 笨?| 筮?蠕<>オ<EFBFBD> |
|
||
| 蝓コ譛ャ隸サ蜀呎オ玖ッ<E78E96> | 蛟シ蛹ケ驟?| 笨?| 筮?蠕<>オ<EFBFBD> |
|
||
| 蟇ケ雎。蠎丞<E8A08E>蛹匁オ玖ッ?| 蟇ケ雎。螳梧紛 | 笨?| 筮?蠕<>オ<EFBFBD> |
|
||
| TTL霑<4C>悄豬玖ッ<E78E96> | 2遘貞錘荳コnull | 笨?| 筮?蠕<>オ<EFBFBD> |
|
||
| 螟ァ蟇ケ雎。豬玖ッ包シ<E58C85>50KB<4B>?| <10ms | 笨?| 筮?蠕<>オ<EFBFBD> |
|
||
| 髯咲コァ遲也払豬玖ッ<E78E96> | 閾ェ蜉ィ蛻<EFBDA8>困蜀<E59BB0>ュ<EFBFBD> | 笨?| 筮?蠕<>オ<EFBFBD> |
|
||
|
||
### 5.2 髮<><E9ABAE>豬玖ッ墓ク<E5A293>黒
|
||
|
||
| 豬玖ッ暮。?| 謫堺ス懈ュ・鬪、 | 鬚<>悄扈捺棡 | 迥カ諤?|
|
||
|--------|---------|---------|------|
|
||
| **HealthCheckService** | 荳贋シ<E8B48B>Excel 2谺?| 隨?谺。郛灘ュ伜多荳?| 筮?蠕<>オ<EFBFBD> |
|
||
| **LLM12FieldsService** | 謠仙叙蜷御クPDF 2谺?| 隨?谺。郛灘ュ伜多荳?| 筮?蠕<>オ<EFBFBD> |
|
||
| **螟壼ョ樔セ狗シ灘ュ伜<EFBDAD>莠?* | 蜷ッ蜉ィ2荳ェ蜷守ォッ螳樔セ具シ悟ョ樔セ帰蜀吝<E89C80><E5909D>悟ョ樔セ毅隸サ蜿<EFBDBB> | B閭ス隸サ蛻ーA逧<41>シ灘ュ?| 筮?蠕<>オ<EFBFBD> |
|
||
| **螳樔セ矩㍾蜷ッ謨ー謐ョ謖∽ケ<E288BD><EFBDB9>?* | 蜀吝<E89C80>郛灘ュ<E78198> 竊?驥榊星蜷守ォッ 竊?隸サ蜿<EFBDBB> | 閭ス隸サ蜿門芦 | 筮?蠕<>オ<EFBFBD> |
|
||
|
||
### 5.3 蜴句鴨豬玖ッ<E78E96>
|
||
|
||
```bash
|
||
# 菴ソ逕ィab謌殆rk豬玖ッ募ケカ蜿題ッサ蜀<EFBDBB>
|
||
|
||
# 豬玖ッ<E78E96>1<EFBFBD>壼ケカ蜿大<E89CBF>蜈?ab -n 1000 -c 10 http://localhost:3001/api/test/cache-write
|
||
|
||
# 豬玖ッ<E78E96>2<EFBFBD>壼ケカ蜿題ッサ蜿?ab -n 10000 -c 50 http://localhost:3001/api/test/cache-read
|
||
|
||
# 鬚<>悄扈捺棡<E68DBA>?# - QPS > 1000
|
||
# - 蜩榊コ疲慮髣エ < 50ms
|
||
# - 髞呵ッッ邇?= 0%
|
||
```
|
||
|
||
### 5.4 謨<>囿讓。諡滓オ玖ッ<E78E96>
|
||
|
||
| 謨<>囿蝨コ譎ッ | 讓。諡滓婿豕<E5A9BF> | 鬚<>悄陦御クコ | 迥カ諤?|
|
||
|---------|---------|---------|------|
|
||
| **Redis遯∫┯謖よ脂** | `docker stop ai-clinical-redis` | 邉サ扈滄剄郤ァ蛻ー蜀<EFBDB0>ュ倡シ灘ュ假シ悟コ皮畑扈ァ扈ュ霑占。<E58DA0> | 筮?蠕<>オ<EFBFBD> |
|
||
| **Redis鄂醍サ懷サカ霑<EFBDB6>** | `tc qdisc add dev eth0 root netem delay 500ms` | 雜<>慮驥崎ッ包シ梧怙扈郁ソ泌屓null | 筮?蠕<>オ<EFBFBD> |
|
||
| **Redis蜀<73>ュ俶サ?* | 蜀吝<E89C80>螟ァ驥乗焚謐ョ閾?56MB | 隗ヲ蜿銑RU鬩ア騾撰シ御ク榊スア蜩肴眠蜀吝<E89C80> | 筮?蠕<>オ<EFBFBD> |
|
||
| **Redis蟇<73><E89F87><EFBFBD>漠隸ッ** | 菫ョ謾ケ蟇<EFBDB9><E89F87><EFBFBD> | 霑樊磁螟ア雍・<E99B8D>碁剄郤ァ蛻ー蜀<EFBDB0>ュ倡シ灘ュ<E78198> | 筮?蠕<>オ<EFBFBD> |
|
||
|
||
---
|
||
|
||
## 6. 鬟朱勦隸<E58BA6>シー荳守シ楢ァ?
|
||
### 6.1 鬟朱勦遏ゥ髦オ
|
||
|
||
| 鬟朱勦 | 荳・驥肴?| 讎ら紫 | 蠖ア蜩<EFBDB1> | 郛楢ァ」謗ェ譁ス | 迥カ諤?|
|
||
|------|--------|------|------|----------|------|
|
||
| **Redis霑樊磁螟ア雍・** | <20>閥 鬮?| <20>泯 荳?| 邉サ扈滉ク榊庄逕?| 笨?髯咲コァ遲也払 | 笨?蟾イ螳樒<E89EB3>?|
|
||
| **謨ー謐ョ荳「螟ア** | <20>泯 荳?| <20>泙 菴?| 郛灘ュ伜、ア謨<EFBDB1> | 笨?蜈ウ髞ョ謨ー謐ョ蜿悟<E89CBF>DB | 竢?蠕<>ョ樒<EFBDAE>?|
|
||
| **蜀<>ュ俶コ「蜃コ<E89C83><EFBDBA>OM<4F>?* | <20>閥 鬮?| <20>泯 荳?| Redis蟠ゥ貅<EFBDA9> | 笨?荳・譬シTTL + 逶第而 | 竢?蠕<>ョ樒<EFBDAE>?|
|
||
| **鄂醍サ懷サカ霑<EFBDB6>** | <20>泙 菴?| <20>泙 菴?| 蜩榊コ泌序諷「 | 笨?謇ケ驥乗桃菴<E6A183> | 竢?蜿ッ騾我シ伜<EFBDBC>?|
|
||
| **驟咲スョ髞呵ッッ** | <20>泯 荳?| <20>泯 荳?| 蜷ッ蜉ィ螟ア雍・ | 笨?驟咲スョ鬪瑚ッ<E7919A> | 笨?蟾イ螳樒<E89EB3>?|
|
||
| **蟇<><E89F87>∵ウ<E288B5>愆** | <20>閥 鬮?| <20>泯 荳?| 謨ー謐ョ豕<EFBDAE>愆 | 笨?KMS邂。逅<EFBDA1> | 竢?蠕<>ョ樒<EFBDAE>?|
|
||
|
||
### 6.2 蜈ウ髞ョ郛楢ァ」謗ェ譁ス
|
||
|
||
#### **郛楢ァ」謗ェ譁ス1<EFBDBD>夐剄郤ァ遲也払<E4B99F>亥ソ<E4BAA5>。サ<EFBDA1>?* 笨?```typescript
|
||
// 蟾イ蝨ィCacheFactory荳ュ螳樒<E89EB3>?// Redis荳榊庄逕ィ譌カ閾ェ蜉ィ蛻<EFBDA8>困蛻ーMemoryCache
|
||
```
|
||
|
||
#### **郛楢ァ」謗ェ譁ス2<EFBDBD>壼<EFBFBD>髞ョ謨ー謐ョ蜿悟<E89CBF><E6829F>域耳闕撰シ?* 竢?```typescript
|
||
// 髴隕∝惠荳壼苅莉」遐∽クュ豺サ蜉?
|
||
// 遉コ萓具シ壻ササ蜉。霑帛コヲ蜿悟<E89CBF>?export async function updateTaskProgress(taskId: string, progress: number) {
|
||
// 1. 蜀儚edis<69>亥ソォ騾滓衍隸「<E99AB8><EFBDA2>
|
||
await cache.set(`task:${taskId}:progress`, progress, 3600);
|
||
|
||
// 2. 蜷梧慮蜀僖B<E58396>域戟荵<E6889F>喧<EFBFBD>? await prisma.aslScreeningTask.update({
|
||
where: { id: taskId },
|
||
data: { processedItems: progress }
|
||
});
|
||
}
|
||
```
|
||
|
||
#### **郛楢ァ」謗ェ譁ス3<EFBDBD>壼<EFBFBD>蟄倡尅謗ァ<E8AC97>域耳闕撰シ?* 竢?```typescript
|
||
// 蛻帛サコ<EFBDBB>喘ackend/src/scripts/monitor-redis.ts
|
||
|
||
import { cache } from '../common/cache/index.js';
|
||
|
||
setInterval(async () => {
|
||
// 譽譟・蜀<EFBDA5>ュ倅スソ逕? const info = await redis.info('memory');
|
||
const used = parseInt(info.match(/used_memory:(\d+)/)[1]);
|
||
const max = 256 * 1024 * 1024;
|
||
|
||
if (used > max * 0.8) {
|
||
logger.warn('笞<><E7AC9E><EFBFBD> Redis蜀<73>ュ倅スソ逕ィ雜<EFBDA8>ソ<EFBFBD>80%', { used, max });
|
||
// TODO: 蜿鷹<E9B7B9>忠髓?驍ョ莉カ蜻願ュヲ
|
||
}
|
||
}, 60000);
|
||
```
|
||
|
||
#### **郛楢ァ」謗ェ譁ス4<EFBDBD>夐<EFBFBD>鄂ョ鬪瑚ッ<E7919A>シ亥キイ螳樒鴫<E6A892><E9B4AB>** 笨?```typescript
|
||
// env.ts荳ュ逧ёalidateConfig()
|
||
// 蜷ッ蜉ィ譌カ譽譟・Redis驟咲スョ
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 荳顔コソ隶。蛻<EFBDA1>
|
||
|
||
### 7.1 荳顔コソ譌カ髣エ陦ィ<E999A6><EFBDA8>2.0譖エ譁ー<EFBFBD>?
|
||
| 髦カ谿オ | 譌カ髣エ | 莉サ蜉。 | 雍溯エ」莠?| 迥カ諤?|
|
||
|------|------|------|--------|------|
|
||
| **Phase 1** | Day 1荳雁壕 | 譛ャ蝨ー蠑蜿醍識蠅<E8AD98>㊥螟?| 蠑蜿?| 筮?蠕<>シ蟋?|
|
||
| **Phase 2** | Day 1荳句壕 | 螳樒鴫RedisCacheAdapter | 蠑蜿?| 筮?蠕<>シ蟋?|
|
||
| **Phase 3** | Day 2蜈ィ螟ゥ | Redis郛灘ュ俶悽蝨ー豬玖ッ<E78E96> | 蠑蜿?豬玖ッ<E78E96> | 筮?蠕<>シ蟋?|
|
||
| **Phase 4** | Day 3荳雁壕 | 髦ソ驥御コ然edis雍ュ荵ー&驟咲スョ | 霑千サエ | 筮?蠕<>シ蟋?|
|
||
| **Phase 5** | Day 3荳句壕-Day 5 | <20>閥 螳樒鴫RedisQueue<75>亥ソ<E4BAA5>。サ<EFBDA1>榎 蠑蜿?| 筮?蠕<>シ蟋?|
|
||
| **Phase 6** | Day 6蜈ィ螟ゥ | Redis髦溷<E9ABA6>譛ャ蝨ー豬玖ッ<E78E96> + 荳壼苅髮<E88B85><E9ABAE> | 蠑蜿?豬玖ッ<E78E96> | 筮?蠕<>シ蟋?|
|
||
| **Phase 7** | Day 7荳雁壕 | SAE豬玖ッ慕識蠅<E8AD98>ェ瑚ッ<E7919A> | 蠑蜿?豬玖ッ<E78E96> | 筮?蠕<>シ蟋?|
|
||
| **Phase 8** | Day 7荳句壕 | 逕滉コァ邇ッ蠅<EFBDAF>ク顔コソ | 蜈ィ蜻<EFBDA8> | 筮?蠕<>シ蟋?|
|
||
| **Phase 9** | Day 7譎? | 逶第而隗ょッ滂シ?4蟆乗慮<E4B997>?| 霑千サエ | 筮?蠕<>シ蟋?|
|
||
|
||
**諤サ蟾・菴憺㍼**<2A>?螟ゥ<E89E9F>域ッ泌次隶。蛻貞「槫刈4螟ゥ<E89E9F>御ス<E5BEA1>。ョ菫晄<E88FAB>ク蠢<EFBDB8>粥閭ス蜿ッ逕ィ<E98095><EFBDA8>
|
||
|
||
### 7.2 荳顔コソ豁・鬪、<E9ACAA>育函莠ァ邇ッ蠅<EFBDAF>シ<EFBFBD>
|
||
|
||
#### **Step 1<>壼書蟶<E69BB8>燕譽譟・<E8AD9F><EFBDA5>15蛻<35>帖<EFBFBD>?*
|
||
```bash
|
||
笨?莉」遐∝キイ謠蝉コ、Git
|
||
笨?譛ャ蝨ー豬玖ッ募<EFBDAF>驛ィ騾夊ソ<E5A48A>
|
||
笨?髦ソ驥御コ然edis蟾イ蟆ア扈?笨?SAE邇ッ蠅<EFBDAF>序驥丞キイ驟咲ス?笨?蝗樊サ壽婿譯亥キイ蜃<EFBDB2>、?笨?逶第而蟾イ蟆ア扈?```
|
||
|
||
#### **Step 2<>夂<EFBFBD>蠎ヲ蜿大ク<E5A4A7>シ<EFBFBD>30蛻<30>帖<EFBFBD>?*
|
||
```
|
||
1. SAE謗ァ蛻カ蜿?竊?騾画叫蠎皮畑
|
||
2. 蠎皮畑驛ィ鄂イ 竊?蛻<>音蜿大ク<E5A4A7>
|
||
3. 隨?謇ケ<E8AC87><EFBDB9>10%螳樔セ具シ郁ァょッ?5蛻<35>帖<EFBFBD>?4. 隨?謇ケ<E8AC87><EFBDB9>50%螳樔セ具シ郁ァょッ?0蛻<30>帖<EFBFBD>?5. 隨?謇ケ<E8AC87><EFBDB9>100%螳樔セ<E6A894>
|
||
```
|
||
|
||
#### **Step 3<>夐ェ瑚ッ<E7919A>シ<EFBFBD>15蛻<35>帖<EFBFBD>?*
|
||
```bash
|
||
# 1. 譽譟・Redis霑樊磁
|
||
curl https://your-api.com/api/health
|
||
# 蠎碑ッ・霑泌屓<E6B38C>嘴 cache: "redis", status: "ok" }
|
||
|
||
# 2. 豬玖ッ慕シ灘ュ伜<EFBDAD>蜈・
|
||
# 荳贋シ<E8B48B>Excel 竊?譟・逵区律蠢<E5BE8B> 竊?遑ョ隶、Redis蜀吝<E89C80>
|
||
|
||
# 3. 豬玖ッ慕シ灘ュ倩ッサ蜿<EFBDBB>
|
||
# 蜀肴ャ。荳贋シ<E8B48B> 竊?譟・逵区律蠢<E5BE8B> 竊?遑ョ隶、郛灘ュ伜多荳ュ
|
||
|
||
# 4. 譽譟・Redis蜀<73>ュ<EFBFBD>
|
||
髦ソ驥御コ第而蛻カ蜿ー 竊?Redis逶第而 竊?蜀<>ュ倅スソ逕ィ
|
||
```
|
||
|
||
#### **Step 4<>夂尅謗ァ隗ょッ滂シ<E6BB82>24蟆乗慮<E4B997>?*
|
||
```
|
||
蜈ウ豕ィ謖<EFBFBD><EFBFBD><EFBFBD>シ?- Redis霑樊磁謨ー<E8ACA8>亥コ碑ッ・遞ウ螳夲シ?- 蜀<>ュ倅スソ逕ィ邇<EFBDA8>シ亥コ碑ッ・ < 50%<25>?- 郛灘ュ伜多荳ュ邇<EFBDAD>シ亥コ碑ッ・ > 80%<25>?- 蠎皮畑髞呵ッッ譌・蠢暦シ亥コ碑ッ・譌<EFBDA5>Redis逶ク蜈ウ髞呵ッッ<EFBDAF>?- API謌先悽<E58588>亥コ碑ッ・荳矩剄<E79FA9><E58984>
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 蝗樊サ壽婿譯<E5A9BF>
|
||
|
||
### 8.1 蠢ォ騾溷屓貊夲シ<E5A4B2>5蛻<35>帖蜀<E5B896>シ<EFBFBD>
|
||
|
||
#### **蝨コ譎ッ1<EFBDAF>啌edis霑樊磁螟ア雍・<E99B8D>悟コ皮畑譌<E79591>豕募星蜉?*
|
||
|
||
```bash
|
||
# 譁ケ豕<EFBDB9>1<EFBFBD>壻ソョ謾ケSAE邇ッ蠅<EFBDAF>序驥<E5BA8F>
|
||
髦ソ驥御コ第而蛻カ蜿ー 竊?SAE蠎皮畑 竊?驟咲スョ邂。逅<EFBDA1> 竊?邇ッ蠅<EFBDAF>序驥<E5BA8F>
|
||
菫ョ謾ケ<EFBFBD>咾ACHE_TYPE=memory
|
||
菫晏ュ<EFBFBD> 竊?蠎皮畑驥榊星
|
||
|
||
# 譁ケ豕<EFBDB9>2<EFBFBD>夐㍾譁ー驛ィ鄂イ荳贋ク荳ェ迚域<E8BF9A>?SAE謗ァ蛻カ蜿?竊?蠎皮畑驛ィ鄂イ 竊?迚域悽邂。逅<EFBDA1> 竊?蝗樊サ<E6A88A>
|
||
```
|
||
|
||
#### **蝨コ譎ッ2<EFBDAF>啌edis諤ァ閭ス髣ョ鬚假シ悟桃蠎泌序諷?*
|
||
|
||
```bash
|
||
# 荳エ譌カ髯咲コァ蛻ー蜀<EFBDB0>ュ倡シ灘ュ?CACHE_TYPE=memory
|
||
|
||
# 謌紋ソ晉蕗Redis菴<73>」譟・鄂醍サ?ping r-xxxxxxxxxxxx.redis.rds.aliyuncs.com
|
||
```
|
||
|
||
#### **蝨コ譎ッ3<EFBDAF>啌edis蜀<73>ュ俶サ。<EFBDBB>梧裏豕募<E8B195>蜈・**
|
||
|
||
```bash
|
||
# 譁ケ豕<EFBDB9>1<EFBFBD>壽ク<E5A3BD>炊Redis<69>亥些髯ゥ<E9ABAF><EFBDA9>シ?redis-cli -h r-xxx.redis.rds.aliyuncs.com -a password
|
||
> FLUSHDB
|
||
|
||
# 譁ケ豕<EFBDB9>2<EFBFBD>壼合郤ァRedis隗<73><E99A97>シ
|
||
髦ソ驥御コ第而蛻カ蜿ー 竊?Redis螳樔セ<E6A894> 竊?蜿倬<E89CBF> 竊?512MB
|
||
```
|
||
|
||
### 8.2 蝗樊サ壽」譟・貂<EFBDA5><E8B282>?
|
||
```bash
|
||
笨?蠎皮畑閭ス蜷ヲ豁」蟶ク蜷ッ蜉ィ<E89C89>?笨?郛灘ュ俶弍蜷ヲ蟾・菴懶シ亥<EFBDBC>蟄俶ィ。蠑擾シ会シ?笨?API蜩榊コ疲弍蜷ヲ豁」蟶ク<E89FB6>?笨?髞呵ッッ譌・蠢玲弍蜷ヲ貂<EFBDA6>勁<EFBFBD>?笨?逕ィ謌キ譏ッ蜷ヲ閭ス豁」蟶ク菴ソ逕ィ<E98095><EFBDA8>
|
||
```
|
||
|
||
---
|
||
|
||
## 9. 逶第而荳手ソ千サ?
|
||
### 9.1 逶第而謖<E8808C><E8AC96><EFBFBD>
|
||
|
||
#### **Redis謖<73><E8AC96><EFBFBD>シ磯仭驥御コ第而蛻カ蜿ー<E89CBF><EFBDB0>**
|
||
|
||
| 謖<><E8AC96><EFBFBD> | 豁」蟶ク闌<EFBDB8>峩 | 蜻願ュヲ髦亥?| 螟<>炊譁ケ譯<EFBDB9> |
|
||
|------|---------|---------|---------|
|
||
| **蜀<>ュ倅スソ逕ィ邇?* | < 50% | > 80% | 譽譟・螟ァkey<65>瑚<E7919A>剔蜊<E58994><E89C8A> |
|
||
| **霑樊磁謨?* | < 50 | > 100 | 譽譟・霑樊磁豕<E7A381>シ?|
|
||
| **QPS** | < 1000 | > 5000 | 閠<>剔蛻<E58994>援 |
|
||
| **蜻ス荳ュ邇?* | > 80% | < 50% | 譽譟・郛灘ュ倡ュ也<EFBDAD>?|
|
||
| **蜩榊コ疲慮髣エ** | < 5ms | > 50ms | 譽譟・鄂醍サ?|
|
||
|
||
#### **蠎皮畑謖<E79591><E8AC96><EFBFBD>シ<EFBFBD>AE譌・蠢暦シ?*
|
||
|
||
```bash
|
||
# 譟・謇セRedis逶ク蜈ウ髞呵ッッ
|
||
grep "Redis" logs/app.log | grep "ERROR"
|
||
|
||
# 譟・謇セ郛灘ュ伜多荳ュ諠<EFBDAD><E8ABA0>
|
||
grep "Cache hit" logs/app.log | wc -l
|
||
grep "Cache miss" logs/app.log | wc -l
|
||
|
||
# 隶。邂怜多荳ュ邇?蜻ス荳ュ邇?= hits / (hits + misses) * 100%
|
||
```
|
||
|
||
### 9.2 霑千サエ蜻ス莉、
|
||
|
||
#### **蟶ク逕ィRedis CLI蜻ス莉、**
|
||
```bash
|
||
# 霑樊磁Redis
|
||
redis-cli -h r-xxx.redis.rds.aliyuncs.com -p 6379 -a your_password
|
||
|
||
# 譟・逵区園譛洩ey
|
||
KEYS *
|
||
|
||
# 譟・逵倶ササ蜉。逶ク蜈ウkey
|
||
KEYS task:*
|
||
|
||
# 譟・逵狗シ灘ュ倡嶌蜈ウkey
|
||
KEYS fulltext:*
|
||
|
||
# 譟・逵橘ey逧УTL
|
||
TTL task:abc123:progress
|
||
|
||
# 譟・逵橘ey逧<79>?GET task:abc123:progress
|
||
|
||
# 譟・逵句<E980B5>蟄倅スソ逕ィ
|
||
INFO memory
|
||
|
||
# 譟・逵玖ソ樊磁謨?INFO clients
|
||
|
||
# 螳樊慮逶第而蜻ス莉、
|
||
MONITOR
|
||
|
||
# 貂<>ゥコ謨ー謐ョ蠎難シ亥些髯ゥ<E9ABAF><EFBDA9>シ<EFBFBD>
|
||
FLUSHDB
|
||
```
|
||
|
||
#### **蜀<>ュ伜<EFBDAD>譫<EFBFBD>**
|
||
```bash
|
||
# 譟・謇セ螟ァkey<65>?10KB<4B>?redis-cli -h xxx -a password --bigkeys
|
||
|
||
# 譟・逵橘ey逧<79><E980A7>蟄伜頃逕?MEMORY USAGE task:abc123:progress
|
||
```
|
||
|
||
### 9.3 謨<>囿謗呈衍豬∫ィ<E288AB>
|
||
|
||
```
|
||
髣ョ鬚假シ啌edis霑樊磁螟ア雍・
|
||
竊?1. 譽譟・Redis螳樔セ狗憾諤<E686BE>シ磯仭驥御コ第而蛻カ蜿ー<E89CBF>? 竊?2. 譽譟・逋ス蜷榊黒驟咲スョ<EFBDBD>域弍蜷ヲ蛹<EFBDA6>性SAE IP<49>? 竊?3. 譽譟・蟇<EFBDA5><E89F87>∵弍蜷ヲ豁」遑? 竊?4. ping豬玖ッ慕ス醍サ懆ソ樣壽? 竊?5. 譟・逵句コ皮畑譌・蠢<EFBDA5>
|
||
竊?6. 螯よ裏豕募ソォ騾溯ァ」蜀?竊?髯咲コァ蛻ー蜀<EFBDB0>ュ倡シ灘ュ?```
|
||
|
||
### 9.4 螳壽悄扈エ謚、
|
||
|
||
| 扈エ蠎ヲ | 鬚醍紫 | 蜀<>ョケ |
|
||
|------|------|------|
|
||
| **譌・蟶ク逶第而** | 豈丞、ゥ | 譟・逵句<E980B5>蟄倅スソ逕ィ縲∬ソ樊磁謨ー縲<EFBDB0>漠隸ッ譌・蠢?|
|
||
| **諤ァ閭ス蛻<EFBDBD>梵** | 豈丞捉 | 蛻<>梵郛灘ュ伜多荳ュ邇<EFBDAD>∝桃蠎疲慮髣?|
|
||
| **螳ケ驥剰ッ<E589B0>シー** | 豈乗怦 | 隸<>シー256MB譏ッ蜷ヲ螟溽畑<E6BABD>梧弍蜷ヲ髴隕∝合驟?|
|
||
| **螳牙<E89EB3>譽譟?* | 豈乗怦 | 譽譟・逋ス蜷榊黒縲∝ッ<E2889D><EFBDAF>∝シコ蠎ヲ縲∬ョソ髣ョ譌・蠢?|
|
||
|
||
---
|
||
|
||
## 10. 謌仙粥譬<E7B2A5>㊥
|
||
|
||
### 10.1 謚譛ッ謖<EFBDAF><E8AC96><EFBFBD>シ<EFBFBD>2.0譖エ譁ー<EFBFBD>?
|
||
| 謖<><E8AC96><EFBFBD> | 蠖灘燕蛟シ<E89B9F>亥<EFBFBD>蟄假シ?| 逶ョ譬<EFBDAE>シ<C280><EFBDBC>edis<69>?| 陦。驥乗婿豕<E5A9BF> |
|
||
|------|---------------|----------------|---------|
|
||
| **郛灘ュ俶戟荵<E6889F><E88DB5>?* | 笶?螳樔セ矩㍾蜷ッ荳「螟ア | 笨?謖∽ケ<E288BD>喧菫晏ュ?| 驥榊星蜷惹サ崎<EFBDBB>隸サ蜿?|
|
||
| **螟壼ョ樔セ句<EFBDBE>莠?* | 笶?蜷<>ョ樔セ狗峡遶?| 笨?蜈ィ螻蜈ア莠ォ | 螳樔セ帰蜀呻シ悟ョ樔セ毅閭ス隸サ |
|
||
| **LLM API驥榊、崎ー<E5B48E>畑** | <20>閥 鬮?| <20>泙 菴?| 蜷御クPDF蜿ェ隹<EFBDAA><E99AB9>?谺?|
|
||
| **郛灘ュ伜多荳ュ邇?* | N/A | > 60% | 逶第而譌・蠢礼サ溯ョ。 |
|
||
| **莉サ蜉。謖∽ケ<E288BD><EFBDB9>?* | 笶?螳樔セ矩楳豈∽ク「螟?| 笨?莉サ蜉。扈ァ扈ュ | <20>閥 **譁ー蠅<EFBDB0>** |
|
||
| **髟ソ莉サ蜉。謌仙粥邇<E7B2A5>** | 10-30% | > 99% | <20>閥 **蜈ウ髞ョ謖<EFBDAE><E8AC96><EFBFBD>** |
|
||
| **邉サ扈溷庄逕ィ諤?* | 99% | 99.9% | 髯咲コァ遲也払菫晞囿 |
|
||
|
||
### 10.2 荳壼苅謖<E88B85><E8AC96><EFBFBD>シ<EFBFBD>2.0譖エ譁ー<EFBFBD>?
|
||
| 謖<><E8AC96><EFBFBD> | 謾ケ騾<EFBDB9>蜑<EFBFBD> | 謾ケ騾<EFBDB9>蜷<EFBFBD> | 陦。驥乗婿豕<E5A9BF> |
|
||
|------|--------|--------|---------|
|
||
| **LLM API謌先悽** | ツ・X/譛?| 髯堺ス<E5A0BA>40-60% | 蟇ケ豈碑エヲ蜊<EFBDA6> |
|
||
| **莉サ蜉。荳「螟ア邇?* | <20>閥 70-95% | < 1% | <20>閥 **譛驥崎ヲ<E5B48E>** |
|
||
| **莉サ蜉。螳梧<E89EB3>譌カ髣エ** | 荳咲。ョ螳?| 遞ウ螳<EFBDB3> | 逶第而譌・蠢<EFBDA5> |
|
||
| **逕ィ謌キ驥榊、肴署莠、谺。謨ー** | 蟷ウ蝮<EFBDB3>3谺?| 蜃<>荵惹ク? | 逕ィ謌キ陦御クコ蛻<EFBDBA>梵 |
|
||
| **逕ィ謌キ貊。諢丞コ?* | 蝓コ郤ソ | 譏セ闡玲署蜊<E7BDB2> | 髣ョ蜊キ隹<EFBDB7>衍 |
|
||
|
||
### 10.3 鬪梧噺譬<E599BA>㊥<EFBFBD><E38AA5>2.0譖エ譁ー<EFBFBD>?
|
||
#### **Redis郛灘ュ倬ェ梧噺**
|
||
```bash
|
||
笨?謇譛臥シ灘ュ伜黒蜈<E9BB92>オ玖ッ暮夊ソ<E5A48A>
|
||
笨?HealthCheckService郛灘ュ伜多荳ュ豬玖ッ暮夊ソ<E5A48A>
|
||
笨?LLM12FieldsService郛灘ュ伜多荳ュ豬玖ッ暮夊ソ<E5A48A>
|
||
笨?螳樔セ矩㍾蜷ッ蜷守シ灘ュ倅サ榊ュ伜惠
|
||
笨?郛灘ュ伜多荳ュ邇?> 60%
|
||
笨?LLM API隹<49>畑谺。謨ー荳矩剄 > 40%
|
||
```
|
||
|
||
#### **Redis髦溷<E9ABA6>鬪梧噺** <20>閥 **譁ー蠅槫<E8A085>髞ョ鬘?*
|
||
```bash
|
||
笨?Redis髦溷<E9ABA6>蜊募<E89C8A>豬玖ッ暮夊ソ<E5A48A>
|
||
笨?髟ソ莉サ蜉。<E89C89><EFBDA1>2蟆乗慮<E4B997>画オ玖ッ暮夊ソ<E5A48A>
|
||
笨?螳樔セ矩㍾蜷ッ蜷惹ササ蜉。閾ェ蜉ィ諱「螟?笨?莉サ蜉。螟ア雍・閾ェ蜉ィ驥崎ッ包シ?谺。<E8B0BA><EFBDA1>
|
||
笨?1000遽<30>枚迪ョ遲幃画<C280>蜉溽紫 > 99%
|
||
笨?譌<>逕ィ謌キ謚戊ッ我ササ蜉。荳「螟?笨?霑帛コヲ螳樊慮譖エ譁ー豁」蟶ク
|
||
```
|
||
|
||
#### **謨<>囿諱「螟肴オ玖ッ<E78E96>** <20>閥 **驥崎ヲ<E5B48E>**
|
||
```bash
|
||
笨?讓。諡溷ョ樔セ矩楳豈?竊?莉サ蜉。閾ェ蜉ィ諱「螟<EFBDA2>
|
||
笨?讓。諡欒edis螳墓惻 竊?邉サ扈滄剄郤ァ霑占。<E58DA0>
|
||
笨?讓。諡溽ス醍サ懷サカ霑<EFBDB6> 竊?莉サ蜉。豁」蟶ク螳梧<E89EB3>
|
||
笨?讓。諡溷ケカ蜿台ササ蜉。 竊?豁」遑ョ蛻<EFBDAE><E89BBB>螟<EFBFBD>炊
|
||
```
|
||
|
||
#### **逕滉コァ邇ッ蠅<EFBDAF>ェ梧噺**
|
||
```bash
|
||
笨?逕滉コァ邇ッ蠅<EFBDAF>ソ占。<E58DA0>48蟆乗慮譌<E685AE>髞呵ッ?笨?2荳ェ螳梧紛逧<E7B49B>1000遽<30>枚迪ョ遲幃我ササ蜉。謌仙<E8AC8C>?笨?逶第而謖<E8808C><E8AC96><EFBFBD>ュ」蟶ク<E89FB6>亥<EFBFBD>蟄倥∬ソ樊磁謨ー縲_PS<50>?笨?譌<>逕ィ謌キ謚戊ッ?```
|
||
|
||
---
|
||
|
||
## 11. FAQ
|
||
|
||
### Q1<51>壼ヲよ棡Redis蝨ィ蜊雁、懃ェ∫┯謖ゆコ<E38286>惹ケ亥萱<E4BAA5><E890B1>
|
||
**A1**<2A>夂ウサ扈滉シ夊<EFBDBC>蜉ィ髯咲コァ蛻ー蜀<EFBDB0>ュ倡シ灘ュ假シ悟コ皮畑扈ァ扈ュ霑占。後らャャ莠悟、ゥ霑千サエ譽譟・蟷カ諱「螟抗edis縲?
|
||
### Q2<51>?56MB螟溽畑蜷暦シ滉サ荵域慮蛟咎怙隕∝合驟搾シ<E690BE>
|
||
**A2**<2A>?- 蠖灘燕鬚<E78795>シー<EFBDBC>? 50% 菴ソ逕ィ邇?- 隗ヲ蜿大合驟堺ソ。蜿キ<E89CBF>? - 蜀<>ュ倅スソ逕ィ > 80%
|
||
- 鬚醍ケ∬ァヲ蜿銑RU鬩ア騾? - 逶第而蜻願ュヲ
|
||
- 蜊<><E89C8A>譁ケ蠑擾シ夐仭驥御コ第而蛻カ蜿ー荳髞ョ蜊<EFBDAE>コァ<EFBDBA>梧裏髴驥榊星
|
||
|
||
### Q3<51>啌edis莨壼スア蜩咲ウサ扈滓ァ閭ス蜷暦シ<E69AA6>
|
||
**A3**<2A>?- 譛ャ蝨ー蜀<EFBDB0>ュ假シ? 0.1ms
|
||
- 譛ャ蝨ーRedis<69>嘸1ms
|
||
- 髦ソ驥御コ然edis<69>亥酔蝨ー蝓滂シ会シ嘸2-5ms
|
||
- 蠖ア蜩榊庄蠢ス逡・<E980A1>御ク疲怏謇ケ驥乗桃菴應シ伜喧
|
||
|
||
### Q4<51>壼ヲよ棡蜿醍鴫Redis荳埼ょ粋<E38287>瑚<EFBFBD>蝗樣蛻ー蜀<EFBDB0>ュ倡シ灘ュ伜雛<E4BC9C>?**A4**<2A>壼庄莉・<E88E89>∽ソョ謾ケ `CACHE_TYPE=memory` 蜊ウ蜿ッ<E89CBF>御サ」遐∵髪謖∫Ο蛻<CE9F>困縲?
|
||
### Q5<51>夐怙隕∝ュヲ荵<EFBDA6>Redis蜻ス莉、蜷暦シ<E69AA6>
|
||
**A5**<2A>?- 蠑蜿托シ壻ク埼怙隕<E68099>シ御サ」遐∝キイ蟆∬」?- 霑千サエ<EFBDBB>壼サコ隶ョ蟄ヲ荵?荳ェ蝓コ遑蜻ス莉、<E88E89><EFBDA4>ET/SET/KEYS/TTL/INFO<46>?
|
||
---
|
||
|
||
## 12. 逶ク蜈ウ譁<EFBDB3>。」
|
||
|
||
- [莠大次逕溷シ蜿題ァ<E9A18C>激](../04-蠑蜿題ァ<E9A18C><EFBDA7>?08-莠大次逕溷シ蜿題ァ<E9A18C><EFBDA7>?md)
|
||
- [SAE驛ィ鄂イ螳悟<E89EB3>謖<EFBFBD>漉](./02-SAE驛ィ鄂イ螳悟<E89EB3>謖<EFBFBD>漉(莠ァ蜩∫サ冗炊迚?.md)
|
||
- [SAE邇ッ蠅<EFBDAF>序驥城<E9A9A5>鄂ョ謖<EFBDAE>漉](./03-SAE邇ッ蠅<EFBDAF>序驥城<E9A9A5>鄂ョ謖<EFBDAE>漉.md)
|
||
- [Redis螳俶婿譁<E5A9BF>。」](https://redis.io/docs/)
|
||
- [ioredis譁<73>。」](https://github.com/redis/ioredis)
|
||
- [髦ソ驥御コ然edis譁<73>。」](https://help.aliyun.com/product/26340.html)
|
||
|
||
---
|
||
|
||
## 13. 髯<>ス<EFBFBD>
|
||
|
||
### 髯<>ス柊<EFBDBD>壼ョ梧紛逧<E7B49B>.env驟咲スョ讓。譚ソ
|
||
|
||
```env
|
||
# ==================== 謨ー謐ョ蠎?====================
|
||
DATABASE_URL=postgresql://postgres:password@localhost:5432/ai_clinical_research
|
||
|
||
# ==================== Redis驟咲スョ ====================
|
||
CACHE_TYPE=redis
|
||
REDIS_HOST=localhost
|
||
REDIS_PORT=6379
|
||
REDIS_PASSWORD=
|
||
REDIS_DB=0
|
||
# 謌紋スソ逕ィ霑樊磁蟄礼ャヲ荳イ
|
||
# REDIS_URL=redis://localhost:6379
|
||
|
||
# ==================== 髦溷<E9ABA6>驟咲スョ ====================
|
||
QUEUE_TYPE=memory # 隨ャ荳髦カ谿オ逕ィmemory<72>檎ャャ莠碁亳谿オ謾ケ荳コredis
|
||
|
||
# ==================== JWT ====================
|
||
JWT_SECRET=your-secret-key-change-in-production
|
||
JWT_EXPIRES_IN=7d
|
||
|
||
# ==================== LLM API ====================
|
||
DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxx
|
||
DASHSCOPE_API_KEY=sk-xxxxxxxxxxxxxx
|
||
CLOSEAI_API_KEY=sk-xxxxxxxxxxxxxx
|
||
CLOSEAI_OPENAI_BASE_URL=https://api.openai-proxy.org/v1
|
||
CLOSEAI_CLAUDE_BASE_URL=https://api.openai-proxy.org/anthropic
|
||
|
||
# ==================== Dify ====================
|
||
DIFY_API_URL=http://localhost/v1
|
||
DIFY_API_KEY=dataset-xxxxxxxxxxxxxx
|
||
|
||
# ==================== Server ====================
|
||
PORT=3001
|
||
NODE_ENV=development
|
||
|
||
# ==================== 蟄伜お驟咲スョ ====================
|
||
STORAGE_TYPE=local
|
||
LOCAL_STORAGE_DIR=uploads
|
||
LOCAL_STORAGE_URL=http://localhost:3001/uploads
|
||
|
||
# ==================== CORS驟咲スョ ====================
|
||
CORS_ORIGIN=http://localhost:5173
|
||
|
||
# ==================== 譌・蠢鈴<E8A0A2>鄂ョ ====================
|
||
LOG_LEVEL=debug
|
||
```
|
||
|
||
### 髯<>ス稗<EFBDBD>啌edis蜀<73>ュ倩ョ。邂怜<E98282>?
|
||
```
|
||
蜊穂クェLLM扈捺棡郛灘ュ假シ嘸50KB
|
||
蜊穂クェ蛛・蠎キ譽譟・郛灘ュ假シ嘸5KB
|
||
|
||
鬚<EFBFBD>シー螳ケ驥擾シ?- 1000荳ェLLM扈捺棡 = 50MB
|
||
- 1000荳ェ蛛・蠎キ譽譟?= 5MB
|
||
- 邉サ扈溷シ髞 = 20MB
|
||
-----------------------------
|
||
諤サ隶。 = 75MB / 256MB = 29% 菴ソ逕ィ邇?```
|
||
|
||
### 髯<>ス匹<EFBDBD>壽腐髫懈シ皮サ<E79AAE><EFBDBB>譛?
|
||
```bash
|
||
#!/bin/bash
|
||
# 譁<>サカ<EFBDBB>喘ackend/scripts/disaster-recovery-drill.sh
|
||
|
||
echo "<22>圷 Redis謨<73>囿貍皮サ<E79AAE>シ蟋?.."
|
||
|
||
# 1. 蛛懈ュ「Redis
|
||
echo "1. 蛛懈ュ「Redis..."
|
||
docker stop ai-clinical-redis
|
||
sleep 2
|
||
|
||
# 2. 豬玖ッ募コ皮畑譏ッ蜷ヲ豁」蟶ク
|
||
echo "2. 豬玖ッ募コ皮畑蛛・蠎キ譽譟?.."
|
||
response=$(curl -s http://localhost:3001/api/health)
|
||
echo "蜩榊コ<E6A68A>: $response"
|
||
|
||
if [[ $response == *"memory"* ]]; then
|
||
echo "笨?髯咲コァ謌仙粥<E4BB99>御スソ逕ィ蜀<EFBDA8>ュ倡シ灘ュ?
|
||
else
|
||
echo "笶?髯咲コァ螟ア雍・"
|
||
exit 1
|
||
fi
|
||
|
||
# 3. 諱「螟抗edis
|
||
echo "3. 諱「螟抗edis..."
|
||
docker start ai-clinical-redis
|
||
sleep 5
|
||
|
||
# 4. 豬玖ッ紐edis諱「螟<EFBDA2>
|
||
echo "4. 豬玖ッ紐edis諱「螟<EFBDA2>..."
|
||
response=$(curl -s http://localhost:3001/api/health)
|
||
echo "蜩榊コ<E6A68A>: $response"
|
||
|
||
if [[ $response == *"redis"* ]]; then
|
||
echo "笨?Redis諱「螟肴<E89E9F>蜉<EFBFBD>"
|
||
else
|
||
echo "笞<><E7AC9E><EFBFBD> Redis譛ェ諱「螟搾シ御サ堺スソ逕ィ蜀<EFBDA8>ュ倡シ灘ュ?
|
||
fi
|
||
|
||
echo "<22>脂 謨<>囿貍皮サ<E79AAE>ョ梧<EFBDAE><E6A2A7>?
|
||
```
|
||
|
||
---
|
||
|
||
**譁<>。」扈エ謚、閠<EFBDA4>シ<EFBFBD>** 謚譛ッ蝗「髦?
|
||
**譛蜷取峩譁ー<E8AD81><EFBDB0>** 2025-12-12
|
||
**譁<>。」迥カ諤<EFBDB6>シ<EFBFBD>** 笨?蠕<>ョ。譬?
|
||
**荳区ャ。譖エ譁ー<E8AD81>?* 謾ケ騾<EFBDB9>螳梧<E89EB3>蜷取サ扈鍋サ城ェ梧蕗隶ュ
|
||
|
||
---
|
||
|
||
## 笨?謾ケ騾<EFBDB9>螳梧<E89EB3>譽譟・貂<EFBDA5><E8B282>?
|
||
蝨ィ螳梧<EFBFBD>Redis謾ケ騾<EFBFBD>蜷趣シ瑚ッキ騾宣。ケ譽譟・<EFBFBD><EFBFBD>
|
||
|
||
### 莉」遐∝アる擇
|
||
- [ ] `ioredis` 蟾イ螳芽」?- [ ] `RedisCacheAdapter` 蟾イ螳樒<E89EB3>?- [ ] `CacheFactory` 蟾イ豺サ蜉<EFBDBB>髯咲コァ騾サ霎<EFBDBB>
|
||
- [ ] `.env` 驟咲スョ蟾イ譖エ譁?- [ ] 謇譛我スソ逕?`cache.set()` 逧<>慍譁ケ驛ス隶セ鄂ョ莠<EFBDAE>TL
|
||
|
||
### 豬玖ッ募アる擇
|
||
- [ ] 蜊募<E89C8A>豬玖ッ募<EFBDAF>驛ィ騾夊ソ<E5A48A>
|
||
- [ ] 髮<><E9ABAE>豬玖ッ募<EFBDAF>驛ィ騾夊ソ<E5A48A>
|
||
- [ ] 蜴句鴨豬玖ッ戊セセ譬<EFBDBE>
|
||
- [ ] 謨<>囿讓。諡滓オ玖ッ暮夊ソ<E5A48A>
|
||
|
||
### 驛ィ鄂イ螻る擇
|
||
- [ ] 髦ソ驥御コ然edis蟾イ雍ュ荵?- [ ] 逋ス蜷榊黒蟾イ驟咲スョ
|
||
- [ ] SAE邇ッ蠅<EFBDAF>序驥丞キイ驟咲ス?- [ ] 逕滉コァ邇ッ蠅<EFBDAF>キイ鬪瑚ッ?
|
||
### 譁<>。」螻る擇
|
||
- [ ] 謾ケ騾<EFBDB9>譁<EFBFBD>。」蟾イ譖エ譁ー
|
||
- [ ] 霑千サエ譁<EFBDB4>。」蟾イ陦・蜈?- [ ] 逶第而謖<E8808C><E8AC96><EFBFBD>キイ隶ー蠖?- [ ] 扈城ェ梧蕗隶ュ蟾イ諤サ扈<EFBDBB>
|
||
|
||
---
|
||
|
||
**逾晄隼騾<E99ABC>鬘コ蛻ゥ<E89BBB>∝ヲよ怏髣ョ鬚假シ瑚ッキ蜿頑慮豐滄壹?* <20>噫
|
||
|