diff --git a/design/backend/sequence/inner/content-이미지생성.puml b/design/backend/sequence/inner/content-이미지생성.puml index 5a386fa..f00284d 100644 --- a/design/backend/sequence/inner/content-이미지생성.puml +++ b/design/backend/sequence/inner/content-이미지생성.puml @@ -12,7 +12,7 @@ participant "ImageStyleFactory" as Factory participant "StableDiffusion\nAPI Client" as SDClient participant "DALL-E\nAPI Client" as DALLEClient participant "Circuit Breaker" as CB -participant "CDNUploader" as CDN +participant "BlobStorage\nUploader" as BlobStorage participant "JobStatusManager" as JobStatus database "Redis Cache" as Redis @@ -64,12 +64,13 @@ else 캐시 MISS (새로운 이미지 생성) note over SDClient: Circuit Breaker 적용\nRetry: 최대 3회\nTimeout: 20초 alt API 성공 - SDClient --> Generator: 심플 이미지 URL + SDClient --> Generator: 심플 이미지 데이터 deactivate SDClient - Generator -> CDN: CDN 업로드 요청\n{imageUrl, eventId, style: SIMPLE} - activate CDN - CDN --> Generator: CDN URL (심플) - deactivate CDN + Generator -> BlobStorage: Blob 업로드 요청\n{imageData, eventId, style: SIMPLE}\nRetry: 3회, Timeout: 30초 + activate BlobStorage + note right of BlobStorage: SAS Token 생성\n(유효기간 7일) + BlobStorage --> Generator: Blob SAS URL (심플) + deactivate BlobStorage else API 실패 (Timeout/Error) SDClient --> Generator: 실패 응답 deactivate SDClient @@ -85,12 +86,13 @@ else 캐시 MISS (새로운 이미지 생성) Generator -> DALLEClient: Fallback - DALL-E API 호출\n{prompt, style: SIMPLE}\nTimeout: 20초 activate DALLEClient alt Fallback 성공 - DALLEClient --> Generator: 심플 이미지 URL + DALLEClient --> Generator: 심플 이미지 데이터 deactivate DALLEClient - Generator -> CDN: CDN 업로드 요청\n{imageUrl, eventId, style: SIMPLE} - activate CDN - CDN --> Generator: CDN URL (심플) - deactivate CDN + Generator -> BlobStorage: Blob 업로드 요청\n{imageData, eventId, style: SIMPLE}\nRetry: 3회, Timeout: 30초 + activate BlobStorage + note right of BlobStorage: SAS Token 생성\n(유효기간 7일) + BlobStorage --> Generator: Blob SAS URL (심플) + deactivate BlobStorage else Fallback 실패 DALLEClient --> Generator: 실패 응답 deactivate DALLEClient @@ -113,24 +115,26 @@ else 캐시 MISS (새로운 이미지 생성) activate SDClient alt API 성공 - SDClient --> Generator: 화려한 이미지 URL + SDClient --> Generator: 화려한 이미지 데이터 deactivate SDClient - Generator -> CDN: CDN 업로드 요청\n{imageUrl, eventId, style: FANCY} - activate CDN - CDN --> Generator: CDN URL (화려한) - deactivate CDN + Generator -> BlobStorage: Blob 업로드 요청\n{imageData, eventId, style: FANCY}\nRetry: 3회, Timeout: 30초 + activate BlobStorage + note right of BlobStorage: SAS Token 생성\n(유효기간 7일) + BlobStorage --> Generator: Blob SAS URL (화려한) + deactivate BlobStorage else API 실패 SDClient --> Generator: 실패 응답 deactivate SDClient Generator -> DALLEClient: Fallback - DALL-E API 호출 activate DALLEClient alt Fallback 성공 - DALLEClient --> Generator: 화려한 이미지 URL + DALLEClient --> Generator: 화려한 이미지 데이터 deactivate DALLEClient - Generator -> CDN: CDN 업로드 - activate CDN - CDN --> Generator: CDN URL (화려한) - deactivate CDN + Generator -> BlobStorage: Blob 업로드\n{imageData, eventId, style: FANCY}\nRetry: 3회, Timeout: 30초 + activate BlobStorage + note right of BlobStorage: SAS Token 생성\n(유효기간 7일) + BlobStorage --> Generator: Blob SAS URL (화려한) + deactivate BlobStorage else Fallback 실패 DALLEClient --> Generator: 실패 응답 deactivate DALLEClient @@ -156,24 +160,26 @@ else 캐시 MISS (새로운 이미지 생성) activate SDClient alt API 성공 - SDClient --> Generator: 트렌디 이미지 URL + SDClient --> Generator: 트렌디 이미지 데이터 deactivate SDClient - Generator -> CDN: CDN 업로드 요청\n{imageUrl, eventId, style: TRENDY} - activate CDN - CDN --> Generator: CDN URL (트렌디) - deactivate CDN + Generator -> BlobStorage: Blob 업로드 요청\n{imageData, eventId, style: TRENDY}\nRetry: 3회, Timeout: 30초 + activate BlobStorage + note right of BlobStorage: SAS Token 생성\n(유효기간 7일) + BlobStorage --> Generator: Blob SAS URL (트렌디) + deactivate BlobStorage else API 실패 SDClient --> Generator: 실패 응답 deactivate SDClient Generator -> DALLEClient: Fallback - DALL-E API 호출 activate DALLEClient alt Fallback 성공 - DALLEClient --> Generator: 트렌디 이미지 URL + DALLEClient --> Generator: 트렌디 이미지 데이터 deactivate DALLEClient - Generator -> CDN: CDN 업로드 - activate CDN - CDN --> Generator: CDN URL (트렌디) - deactivate CDN + Generator -> BlobStorage: Blob 업로드\n{imageData, eventId, style: TRENDY}\nRetry: 3회, Timeout: 30초 + activate BlobStorage + note right of BlobStorage: SAS Token 생성\n(유효기간 7일) + BlobStorage --> Generator: Blob SAS URL (트렌디) + deactivate BlobStorage else Fallback 실패 DALLEClient --> Generator: 실패 응답 deactivate DALLEClient @@ -189,9 +195,9 @@ else 캐시 MISS (새로운 이미지 생성) deactivate Generator == 결과 캐싱 및 Job 완료 == - Handler -> Cache: 이미지 URL 캐싱\nkey: content:image:{eventDraftId}\nTTL: 7일 + Handler -> Cache: Blob SAS URL 캐싱\nkey: content:image:{eventDraftId}\nTTL: 7일 activate Cache - Cache -> Redis: SET content:image:{eventDraftId}\n{simple, fancy, trendy}\nTTL: 604800 (7일) + Cache -> Redis: SET content:image:{eventDraftId}\n{simple: SAS_URL, fancy: SAS_URL, trendy: SAS_URL}\nTTL: 604800 (7일) Redis --> Cache: 저장 완료 Cache --> Handler: 캐싱 완료 deactivate Cache @@ -204,9 +210,10 @@ else 캐시 MISS (새로운 이미지 생성) Handler --> Consumer: 처리 완료 note over Handler - 이미지 URL은 Redis에만 저장됨 + Blob SAS URL은 Redis에만 저장됨 Event Service는 폴링을 통해 Redis에서 결과 조회 + SAS Token 유효기간: 7일 end note end @@ -214,22 +221,35 @@ deactivate Handler note over Consumer, Redis **Resilience 패턴 적용** -- Circuit Breaker: 실패율 50% 초과 시 Open -- Timeout: 20초 +- Circuit Breaker: 실패율 50% 초과 시 Open (AI API용) +- AI API Timeout: 20초 - Fallback: Stable Diffusion 실패 시 DALL-E, 모두 실패 시 기본 템플릿 +- Blob Storage Retry: 최대 3회 (Exponential Backoff: 1s, 2s, 4s) +- Blob Storage Timeout: 30초 (대용량 이미지 고려) - Cache-Aside: Redis 캐싱 (TTL 7일) **처리 시간** - 캐시 HIT: 0.1초 -- 캐시 MISS: 5초 이내 (병렬 처리) +- 캐시 MISS: 5.2초 이내 (병렬 처리) + └─ AI 생성: 3-5초 + Blob 업로드: 0.15-0.3초 **병렬 처리** - 3가지 스타일 동시 생성 (par 블록) - 독립적인 스레드 풀 사용 -**CDN 업로드** -- 이미지 생성 후 CDN 업로드 -- CDN URL 반환 및 캐싱 +**Blob Storage 업로드** +- Azure Blob Storage (Korea Central) +- SAS Token 기반 접근 제어 (읽기 전용) +- SAS Token 유효기간: 7일 (Redis TTL과 동기화) +- Public Access 비활성화 (보안 강화) +- Container: event-images +- URL 형식: https://{account}.blob.core.windows.net/event-images/{id}-{style}.png?{sas_token} + +**보안** +- Storage Account Public Access 비활성화 +- SAS Token 기반 URL 생성 (읽기 전용 권한) +- Firewall 규칙: K8s Cluster IP만 허용 +- HTTPS 강제 (TLS 1.2 이상) end note @enduml