1166 lines
36 KiB
Markdown
1166 lines
36 KiB
Markdown
# KT AI 기반 소상공인 이벤트 자동 생성 서비스 - 클라우드 아키텍처 패턴 적용 방안
|
|
|
|
## 문서 정보
|
|
- **작성일**: 2025-10-22
|
|
- **버전**: 3.0 (Azure Kubernetes 기반)
|
|
- **적용 패턴**: 4개 핵심 패턴
|
|
- **인프라 환경**: Azure Kubernetes Service (AKS)
|
|
- **목표**: 빠른 MVP 출시와 안정적 서비스 제공
|
|
|
|
---
|
|
|
|
## 1. 요구사항 분석
|
|
|
|
### 1.1 기능적 요구사항
|
|
|
|
**User 서비스**
|
|
- 회원가입/로그인 및 프로필 관리
|
|
- 사업자번호 검증 (국세청 API)
|
|
|
|
**Event 서비스**
|
|
- 이벤트 CRUD 및 상태 관리
|
|
- 이벤트 목적 선택 → AI 추천 → 콘텐츠 생성 → 배포 → 분석 플로우
|
|
|
|
**AI 서비스**
|
|
- 트렌드 분석 (업종/지역/시즌)
|
|
- 3가지 이벤트 기획안 자동 생성
|
|
- Claude API/GPT-4 API 연동
|
|
|
|
**Content 서비스**
|
|
- 3가지 스타일 SNS 이미지 자동 생성
|
|
- Stable Diffusion/DALL-E API 연동
|
|
- 플랫폼별 이미지 최적화 (Instagram, Naver, Kakao)
|
|
|
|
**Distribution 서비스**
|
|
- 다중 채널 동시 배포 (우리동네TV, 링고비즈, 지니TV, SNS)
|
|
- 7개 외부 API 연동
|
|
|
|
**Participation 서비스**
|
|
- 이벤트 참여 접수 및 당첨자 추첨
|
|
|
|
**Analytics 서비스**
|
|
- 실시간 성과 대시보드
|
|
- 채널별 성과 분석
|
|
|
|
### 1.2 비기능적 요구사항
|
|
|
|
**성능 요구사항**
|
|
- AI 트렌드 분석 + 이벤트 추천: **10초 이내**
|
|
- SNS 이미지 생성: **5초 이내**
|
|
- 대시보드 데이터 업데이트: **5분 간격**
|
|
- 다중 채널 배포: **1분 이내**
|
|
|
|
**가용성 요구사항**
|
|
- 시스템 가용성: **99% 이상** (MVP 목표)
|
|
- 외부 API 장애 시 서비스 지속 가능
|
|
|
|
**확장성 요구사항**
|
|
- 초기 사용자: **100명**
|
|
- 동시 이벤트: **50개**
|
|
- 캐시 히트율: **80% 이상**
|
|
|
|
**보안 요구사항**
|
|
- JWT 기반 인증/인가
|
|
- API Gateway를 통한 중앙집중식 보안
|
|
|
|
### 1.3 외부 API 의존성
|
|
|
|
| 서비스 | 외부 API | 용도 | 응답시간 |
|
|
|--------|----------|------|----------|
|
|
| User | 국세청 사업자등록정보 진위확인 API | 사업자번호 검증 | 2-3초 |
|
|
| AI | Claude API / GPT-4 API | 트렌드 분석 및 이벤트 추천 | 5-10초 |
|
|
| Content | Stable Diffusion / DALL-E API | SNS 이미지 생성 | 3-5초 |
|
|
| Distribution | 우리동네TV API | 영상 업로드 및 송출 | 1-2초 |
|
|
| Distribution | 링고비즈 API | 연결음 업데이트 | 1초 |
|
|
| Distribution | 지니TV 광고 API | 광고 등록 | 1-2초 |
|
|
| Distribution | SNS API (Instagram, Naver, Kakao) | 자동 포스팅 | 1-3초 |
|
|
|
|
---
|
|
|
|
## 2. 적용 패턴 개요
|
|
|
|
### 2.1 선정된 4가지 핵심 패턴
|
|
|
|
| 패턴 | 적용 목적 | Azure 서비스 | 우선순위 |
|
|
|------|----------|-------------|---------|
|
|
| **Cache-Aside** | AI 응답 시간 단축 및 비용 절감 | Azure Cache for Redis | 🔴 Critical |
|
|
| **API Gateway** | 중앙집중식 보안 및 라우팅 | Azure API Management / Nginx Ingress | 🔴 Critical |
|
|
| **Asynchronous Request-Reply** | 장시간 작업 응답 시간 개선 | Azure Service Bus / RabbitMQ | 🔴 Critical |
|
|
| **Circuit Breaker** | 외부 API 장애 격리 | Resilience4j / Polly | 🟡 Optional |
|
|
|
|
### 2.2 Azure Kubernetes 환경 고려사항
|
|
|
|
**인프라 구성**:
|
|
- **AKS (Azure Kubernetes Service)**: 컨테이너 오케스트레이션
|
|
- **Azure Cache for Redis**: 분산 캐시
|
|
- **Azure Container Registry (ACR)**: 컨테이너 이미지 저장소
|
|
- **Azure Database for PostgreSQL**: 관계형 데이터베이스
|
|
- **Azure Service Bus**: 메시지 큐 (Optional, RabbitMQ 대체 가능)
|
|
- **Azure Monitor + Application Insights**: 모니터링 및 로깅
|
|
- **Azure API Management**: API Gateway (Optional, Nginx Ingress 대체 가능)
|
|
|
|
**개발 환경 vs 운영 환경**:
|
|
- **개발 환경**: AKS 개발 클러스터, Redis Standard tier, PostgreSQL Basic tier
|
|
- **운영 환경**: AKS 운영 클러스터 (다중 노드), Redis Premium tier (HA), PostgreSQL General Purpose (HA)
|
|
|
|
---
|
|
|
|
## 3. 패턴별 상세 설계
|
|
|
|
### 3.1 Cache-Aside 패턴
|
|
|
|
#### 3.1.1 개요
|
|
|
|
**목적**: AI API 호출 비용 절감 및 응답 시간 단축
|
|
|
|
**적용 대상**:
|
|
- AI 서비스: 트렌드 분석 결과, 이벤트 추천 결과
|
|
- Content 서비스: 생성된 SNS 이미지
|
|
- User 서비스: 사업자번호 검증 결과
|
|
|
|
#### 3.1.2 Azure 구현 방식
|
|
|
|
**Azure Cache for Redis 구성**:
|
|
```yaml
|
|
# 개발 환경
|
|
tier: Standard
|
|
capacity: C1 (1GB)
|
|
availability: Single instance
|
|
|
|
# 운영 환경
|
|
tier: Premium
|
|
capacity: P1 (6GB)
|
|
availability: Zone redundant (고가용성)
|
|
```
|
|
|
|
**동작 흐름**:
|
|
```
|
|
1. 요청 수신 → Redis GET {key}
|
|
2. Cache HIT:
|
|
- 즉시 반환 (응답 시간 ~100ms)
|
|
3. Cache MISS:
|
|
- 외부 API 호출 (응답 시간 5-10초)
|
|
- Redis SET {key} {value} EX {TTL}
|
|
- 결과 반환
|
|
```
|
|
|
|
**캐시 키 설계**:
|
|
```
|
|
ai:trend:{industry}:{region}:{season}
|
|
ai:recommendation:{industry}:{region}:{purpose}
|
|
content:image:{event_id}:{style}
|
|
user:business:{business_number}
|
|
```
|
|
|
|
**TTL 정책**:
|
|
- AI 트렌드 분석: **24시간** (트렌드 변화 주기 고려)
|
|
- AI 이벤트 추천: **12시간** (빈번한 업데이트)
|
|
- 생성 이미지: **7일** (재사용 가능성)
|
|
- 사업자번호 검증: **30일** (변경 빈도 낮음)
|
|
|
|
#### 3.1.3 Kubernetes 배포
|
|
|
|
```yaml
|
|
# redis-deployment.yaml (개발/운영 공통)
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: redis-cache
|
|
spec:
|
|
type: LoadBalancer
|
|
ports:
|
|
- port: 6379
|
|
selector:
|
|
app: redis
|
|
|
|
---
|
|
# Azure Cache for Redis 연결 시 Secret
|
|
apiVersion: v1
|
|
kind: Secret
|
|
metadata:
|
|
name: redis-secret
|
|
type: Opaque
|
|
data:
|
|
connection-string: <base64-encoded-connection-string>
|
|
```
|
|
|
|
#### 3.1.4 기대 효과
|
|
|
|
| 지표 | Before | After (캐시 히트) | 개선율 |
|
|
|------|--------|-----------------|--------|
|
|
| AI 응답 시간 | 10초 | 0.1초 | **99%** |
|
|
| 이미지 생성 시간 | 5초 | 0.1초 | **98%** |
|
|
| AI API 비용 | $600/월 | $120/월 | **80% 절감** |
|
|
| 이미지 API 비용 | $600/월 | $120/월 | **80% 절감** |
|
|
|
|
---
|
|
|
|
### 3.2 API Gateway 패턴
|
|
|
|
#### 3.2.1 개요
|
|
|
|
**목적**: 중앙집중식 인증, 라우팅, Rate Limiting
|
|
|
|
**주요 기능**:
|
|
1. **인증/인가**: JWT 토큰 검증
|
|
2. **라우팅**: URL 기반 서비스 라우팅
|
|
3. **Rate Limiting**: API 호출 제한
|
|
4. **로깅**: 중앙집중식 접근 로그
|
|
5. **SSL 종료**: HTTPS 처리
|
|
|
|
#### 3.2.2 Azure 구현 옵션
|
|
|
|
**옵션 1: Azure API Management (권장 - 운영 환경)**
|
|
```yaml
|
|
특징:
|
|
- 완전 관리형 서비스
|
|
- 내장 인증/인가, Rate Limiting
|
|
- Azure Monitor 통합
|
|
- 높은 비용 (약 $50/월 이상)
|
|
|
|
장점:
|
|
- 운영 부담 최소화
|
|
- 기업급 기능 (개발자 포털, API 버전 관리)
|
|
- Azure 생태계 통합
|
|
|
|
단점:
|
|
- 비용 부담
|
|
- 커스터마이징 제한
|
|
```
|
|
|
|
**옵션 2: Nginx Ingress Controller (권장 - 개발 환경 / 비용 절감)**
|
|
```yaml
|
|
특징:
|
|
- AKS 내장 Ingress Controller
|
|
- 무료 (AKS 비용에 포함)
|
|
- 높은 커스터마이징
|
|
|
|
장점:
|
|
- 비용 효율적
|
|
- Kubernetes 네이티브
|
|
- 유연한 설정
|
|
|
|
단점:
|
|
- 수동 설정 필요
|
|
- 운영 부담
|
|
```
|
|
|
|
#### 3.2.3 Nginx Ingress 구현 (권장)
|
|
|
|
```yaml
|
|
# nginx-ingress.yaml
|
|
apiVersion: networking.k8s.io/v1
|
|
kind: Ingress
|
|
metadata:
|
|
name: api-gateway-ingress
|
|
annotations:
|
|
nginx.ingress.kubernetes.io/rewrite-target: /
|
|
nginx.ingress.kubernetes.io/rate-limit: "100" # 100 req/min
|
|
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
|
spec:
|
|
ingressClassName: nginx
|
|
tls:
|
|
- hosts:
|
|
- api.kt-event.com
|
|
secretName: tls-secret
|
|
rules:
|
|
- host: api.kt-event.com
|
|
http:
|
|
paths:
|
|
- path: /api/users
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: user-service
|
|
port:
|
|
number: 8080
|
|
- path: /api/events
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: event-service
|
|
port:
|
|
number: 8080
|
|
- path: /api/ai
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: ai-service
|
|
port:
|
|
number: 8080
|
|
- path: /api/content
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: content-service
|
|
port:
|
|
number: 8080
|
|
- path: /api/distribution
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: distribution-service
|
|
port:
|
|
number: 8080
|
|
- path: /api/participation
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: participation-service
|
|
port:
|
|
number: 8080
|
|
- path: /api/analytics
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: analytics-service
|
|
port:
|
|
number: 8080
|
|
```
|
|
|
|
**JWT 인증 미들웨어** (각 서비스에서 구현):
|
|
```java
|
|
// Spring Boot 예시
|
|
@Component
|
|
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|
|
|
@Override
|
|
protected void doFilterInternal(HttpServletRequest request,
|
|
HttpServletResponse response,
|
|
FilterChain filterChain) {
|
|
String token = extractToken(request);
|
|
if (token != null && validateToken(token)) {
|
|
// 인증 성공
|
|
filterChain.doFilter(request, response);
|
|
} else {
|
|
// 401 Unauthorized
|
|
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 3.2.4 기대 효과
|
|
|
|
| 항목 | 효과 |
|
|
|------|------|
|
|
| 개발 생산성 | 각 서비스 인증 로직 제거 → 개발 시간 **30% 단축** |
|
|
| 보안 강화 | 중앙집중식 보안 정책 관리 |
|
|
| 운영 효율 | 통합 모니터링 및 로깅 |
|
|
| 비용 절감 | Nginx Ingress 사용 시 **무료** (vs Azure API Management $50/월) |
|
|
|
|
---
|
|
|
|
### 3.3 Asynchronous Request-Reply 패턴
|
|
|
|
#### 3.3.1 개요
|
|
|
|
**목적**: 장시간 작업의 사용자 대기 시간 제거
|
|
|
|
**적용 대상**:
|
|
- AI 서비스: 트렌드 분석 및 이벤트 추천 (10초 소요)
|
|
- Content 서비스: SNS 이미지 생성 (5초 소요)
|
|
|
|
#### 3.3.2 Azure 구현 방식
|
|
|
|
**옵션 1: Azure Service Bus (권장 - 운영 환경)**
|
|
```yaml
|
|
특징:
|
|
- 완전 관리형 메시지 큐
|
|
- 높은 안정성 및 가용성
|
|
- Azure Monitor 통합
|
|
|
|
비용:
|
|
- Basic tier: $0.05/million operations
|
|
- Standard tier: $10/월 기본 + $0.80/million operations
|
|
|
|
장점:
|
|
- 운영 부담 최소화
|
|
- 엔터프라이즈급 안정성
|
|
- Azure 생태계 통합
|
|
```
|
|
|
|
**옵션 2: RabbitMQ (권장 - 개발 환경 / 비용 절감)**
|
|
```yaml
|
|
특징:
|
|
- 오픈소스 메시지 브로커
|
|
- AKS에 직접 배포
|
|
- 무료 (인프라 비용만)
|
|
|
|
장점:
|
|
- 비용 효율적
|
|
- 높은 커스터마이징
|
|
- Kubernetes 네이티브 배포
|
|
|
|
단점:
|
|
- 운영 부담 (HA, 백업)
|
|
```
|
|
|
|
#### 3.3.3 RabbitMQ 구현 (권장)
|
|
|
|
**Kubernetes 배포**:
|
|
```yaml
|
|
# rabbitmq-deployment.yaml
|
|
apiVersion: apps/v1
|
|
kind: StatefulSet
|
|
metadata:
|
|
name: rabbitmq
|
|
spec:
|
|
serviceName: rabbitmq
|
|
replicas: 1 # 개발: 1, 운영: 3 (HA)
|
|
selector:
|
|
matchLabels:
|
|
app: rabbitmq
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: rabbitmq
|
|
spec:
|
|
containers:
|
|
- name: rabbitmq
|
|
image: rabbitmq:3.12-management
|
|
ports:
|
|
- containerPort: 5672
|
|
name: amqp
|
|
- containerPort: 15672
|
|
name: management
|
|
env:
|
|
- name: RABBITMQ_DEFAULT_USER
|
|
value: "admin"
|
|
- name: RABBITMQ_DEFAULT_PASS
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: rabbitmq-secret
|
|
key: password
|
|
volumeMounts:
|
|
- name: rabbitmq-data
|
|
mountPath: /var/lib/rabbitmq
|
|
volumeClaimTemplates:
|
|
- metadata:
|
|
name: rabbitmq-data
|
|
spec:
|
|
accessModes: [ "ReadWriteOnce" ]
|
|
resources:
|
|
requests:
|
|
storage: 10Gi
|
|
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: rabbitmq
|
|
spec:
|
|
ports:
|
|
- port: 5672
|
|
name: amqp
|
|
- port: 15672
|
|
name: management
|
|
selector:
|
|
app: rabbitmq
|
|
```
|
|
|
|
**동작 흐름**:
|
|
```
|
|
1. 클라이언트 요청
|
|
→ 즉시 Job ID 반환 (응답 시간 ~100ms)
|
|
|
|
2. 백그라운드 처리
|
|
→ RabbitMQ에 Job 메시지 발행
|
|
→ Worker가 Job 처리 (10초)
|
|
→ 결과를 Redis에 저장
|
|
|
|
3. 클라이언트 폴링
|
|
→ GET /api/jobs/{id}
|
|
→ Redis에서 Job 상태 확인
|
|
→ 완료 시 결과 반환
|
|
```
|
|
|
|
**Job 상태 관리** (Redis):
|
|
```
|
|
job:{job_id}:status = "pending" | "processing" | "completed" | "failed"
|
|
job:{job_id}:result = {result_data}
|
|
job:{job_id}:progress = 0-100 (%)
|
|
TTL: 1시간
|
|
```
|
|
|
|
#### 3.3.4 Spring Boot 구현 예시
|
|
|
|
```java
|
|
// AI 서비스 - Job 생성
|
|
@PostMapping("/api/ai/recommendations")
|
|
public ResponseEntity<JobResponse> createRecommendationJob(@RequestBody RecommendationRequest request) {
|
|
String jobId = UUID.randomUUID().toString();
|
|
|
|
// Redis에 Job 상태 저장
|
|
redisTemplate.opsForValue().set("job:" + jobId + ":status", "pending", 1, TimeUnit.HOURS);
|
|
|
|
// RabbitMQ에 Job 발행
|
|
rabbitTemplate.convertAndSend("ai.queue", new JobMessage(jobId, request));
|
|
|
|
return ResponseEntity.ok(new JobResponse(jobId, "pending"));
|
|
}
|
|
|
|
// Worker - Job 처리
|
|
@RabbitListener(queues = "ai.queue")
|
|
public void processRecommendationJob(JobMessage message) {
|
|
String jobId = message.getJobId();
|
|
|
|
// Job 상태 업데이트: processing
|
|
redisTemplate.opsForValue().set("job:" + jobId + ":status", "processing");
|
|
|
|
try {
|
|
// AI API 호출 (10초 소요)
|
|
String result = callClaudeAPI(message.getRequest());
|
|
|
|
// 결과 저장
|
|
redisTemplate.opsForValue().set("job:" + jobId + ":result", result, 1, TimeUnit.HOURS);
|
|
redisTemplate.opsForValue().set("job:" + jobId + ":status", "completed");
|
|
|
|
// 캐시에도 저장 (Cache-Aside)
|
|
String cacheKey = "ai:recommendation:" + getCacheKey(message.getRequest());
|
|
redisTemplate.opsForValue().set(cacheKey, result, 24, TimeUnit.HOURS);
|
|
|
|
} catch (Exception e) {
|
|
redisTemplate.opsForValue().set("job:" + jobId + ":status", "failed");
|
|
redisTemplate.opsForValue().set("job:" + jobId + ":error", e.getMessage());
|
|
}
|
|
}
|
|
|
|
// Job 상태 조회
|
|
@GetMapping("/api/jobs/{jobId}")
|
|
public ResponseEntity<JobStatusResponse> getJobStatus(@PathVariable String jobId) {
|
|
String status = redisTemplate.opsForValue().get("job:" + jobId + ":status");
|
|
|
|
if ("completed".equals(status)) {
|
|
String result = redisTemplate.opsForValue().get("job:" + jobId + ":result");
|
|
return ResponseEntity.ok(new JobStatusResponse(jobId, status, result));
|
|
} else {
|
|
return ResponseEntity.ok(new JobStatusResponse(jobId, status, null));
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 3.3.5 기대 효과
|
|
|
|
| 지표 | Before | After | 개선 |
|
|
|------|--------|-------|------|
|
|
| 사용자 대기 시간 | 10초 | 0.1초 (즉시 응답) | **99% 개선** |
|
|
| 동시 처리 가능 요청 | 10 req/sec | 50 req/sec | **5배 증가** |
|
|
| 서버 리소스 효율 | 동기 대기로 낭비 | 최적화 | **30% 절감** |
|
|
|
|
---
|
|
|
|
### 3.4 Circuit Breaker 패턴 (Optional)
|
|
|
|
#### 3.4.1 개요
|
|
|
|
**목적**: 외부 API 장애 시 서비스 격리 및 빠른 실패
|
|
|
|
**적용 대상**:
|
|
- 모든 외부 API 연동 지점 (7개 API)
|
|
|
|
#### 3.4.2 구현 방식 (Resilience4j)
|
|
|
|
**의존성 추가** (Spring Boot):
|
|
```xml
|
|
<dependency>
|
|
<groupId>io.github.resilience4j</groupId>
|
|
<artifactId>resilience4j-spring-boot3</artifactId>
|
|
<version>2.1.0</version>
|
|
</dependency>
|
|
```
|
|
|
|
**설정** (application.yml):
|
|
```yaml
|
|
resilience4j:
|
|
circuitbreaker:
|
|
configs:
|
|
default:
|
|
slidingWindowSize: 10
|
|
minimumNumberOfCalls: 5
|
|
failureRateThreshold: 50 # 50% 실패 시 Open
|
|
waitDurationInOpenState: 30s
|
|
permittedNumberOfCallsInHalfOpenState: 3
|
|
instances:
|
|
claudeAPI:
|
|
baseConfig: default
|
|
stableDiffusionAPI:
|
|
baseConfig: default
|
|
taxAPI:
|
|
baseConfig: default
|
|
distributionAPIs:
|
|
baseConfig: default
|
|
```
|
|
|
|
**코드 예시**:
|
|
```java
|
|
@Service
|
|
public class ClaudeAPIClient {
|
|
|
|
@CircuitBreaker(name = "claudeAPI", fallbackMethod = "getRecommendationFallback")
|
|
public String getRecommendation(RecommendationRequest request) {
|
|
// Claude API 호출
|
|
return restTemplate.postForObject(CLAUDE_API_URL, request, String.class);
|
|
}
|
|
|
|
// Fallback: 캐시된 결과 반환 또는 기본 메시지
|
|
public String getRecommendationFallback(RecommendationRequest request, Exception e) {
|
|
log.warn("Claude API circuit breaker activated, using fallback", e);
|
|
|
|
// 캐시에서 유사한 이전 결과 조회
|
|
String cachedResult = getCachedRecommendation(request);
|
|
|
|
if (cachedResult != null) {
|
|
return cachedResult;
|
|
}
|
|
|
|
// 기본 메시지
|
|
return "AI 서비스가 일시적으로 이용 불가합니다. 잠시 후 다시 시도해주세요.";
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 3.4.3 Fallback 전략
|
|
|
|
| 서비스 | 외부 API | Fallback 전략 |
|
|
|--------|---------|--------------|
|
|
| AI | Claude API | 캐시된 이전 추천 결과 + 안내 메시지 |
|
|
| Content | Stable Diffusion | 기본 템플릿 이미지 + 안내 메시지 |
|
|
| User | 국세청 API | 사업자번호 검증 스킵 (수동 확인으로 대체) |
|
|
| Distribution | 각 채널 API | 해당 채널 배포 스킵 + 알림 |
|
|
|
|
#### 3.4.4 모니터링 (Azure Monitor)
|
|
|
|
**커스텀 메트릭**:
|
|
```java
|
|
@Component
|
|
public class CircuitBreakerMetrics {
|
|
|
|
private final MeterRegistry meterRegistry;
|
|
private final CircuitBreakerRegistry circuitBreakerRegistry;
|
|
|
|
@PostConstruct
|
|
public void registerMetrics() {
|
|
circuitBreakerRegistry.getAllCircuitBreakers().forEach(cb -> {
|
|
Gauge.builder("circuit.breaker.state", cb,
|
|
this::getStateValue)
|
|
.tag("name", cb.getName())
|
|
.register(meterRegistry);
|
|
|
|
cb.getEventPublisher()
|
|
.onStateTransition(event -> {
|
|
log.info("Circuit Breaker {} state changed: {} -> {}",
|
|
event.getCircuitBreakerName(),
|
|
event.getStateTransition().getFromState(),
|
|
event.getStateTransition().getToState());
|
|
});
|
|
});
|
|
}
|
|
|
|
private int getStateValue(CircuitBreaker cb) {
|
|
switch (cb.getState()) {
|
|
case CLOSED: return 0;
|
|
case OPEN: return 1;
|
|
case HALF_OPEN: return 2;
|
|
default: return -1;
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 3.4.5 기대 효과
|
|
|
|
| 지표 | Before | After | 개선 |
|
|
|------|--------|-------|------|
|
|
| 시스템 가용성 | 95% | 99% | **+4%p** |
|
|
| 장애 복구 시간 | 5분 (수동) | 30초 (자동) | **90% 단축** |
|
|
| 외부 API 장애 격리 | ❌ 전체 중단 | ✅ 독립 동작 | - |
|
|
|
|
---
|
|
|
|
## 4. 전체 아키텍처
|
|
|
|
### 4.1 Azure Kubernetes 기반 아키텍처
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ Azure Cloud │
|
|
│ │
|
|
│ ┌────────────────────────────────────────────────────────────┐ │
|
|
│ │ Azure Kubernetes Service (AKS) │ │
|
|
│ │ │ │
|
|
│ │ ┌─────────────────────────────────────────────────────┐ │ │
|
|
│ │ │ Nginx Ingress Controller │ │ │
|
|
│ │ │ - JWT 인증 │ │ │
|
|
│ │ │ - Rate Limiting │ │ │
|
|
│ │ │ - SSL 종료 │ │ │
|
|
│ │ └─────────────────────────────────────────────────────┘ │ │
|
|
│ │ │ │ │
|
|
│ │ ┌──────────────────────┼──────────────────────┐ │ │
|
|
│ │ │ │ │ │ │
|
|
│ │ ┌─▼───┐ ┌─────┐ ┌─────▼──┐ ┌────────┐ ┌───▼────┐ │ │
|
|
│ │ │User │ │Event│ │ AI │ │Content │ │ Dist │ │ │
|
|
│ │ │ Svc │ │ Svc │ │ Svc │ │ Svc │ │ Svc │ │ │
|
|
│ │ └──┬──┘ └──┬──┘ └───┬────┘ └───┬────┘ └───┬────┘ │ │
|
|
│ │ │ │ │ │ │ │ │
|
|
│ │ └────────┴──────────┴────────────┴───────────┘ │ │
|
|
│ │ │ │ │
|
|
│ │ ┌────▼─────┐ │ │
|
|
│ │ │RabbitMQ │ (Async Request-Reply) │ │
|
|
│ │ │ Worker │ │ │
|
|
│ │ └──────────┘ │ │
|
|
│ └──────────────────────────────────────────────────────────── │ │
|
|
│ │
|
|
│ ┌────────────────────────────────────────────────────────────┐ │
|
|
│ │ Azure Cache for Redis (Cache-Aside) │ │
|
|
│ │ - AI 결과 캐시 │ │
|
|
│ │ - 이미지 캐시 │ │
|
|
│ │ - Job 상태 관리 │ │
|
|
│ └────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌────────────────────────────────────────────────────────────┐ │
|
|
│ │ Azure Database for PostgreSQL │ │
|
|
│ │ - 사용자 데이터 │ │
|
|
│ │ - 이벤트 데이터 │ │
|
|
│ └────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌────────────────────────────────────────────────────────────┐ │
|
|
│ │ Azure Monitor + Application Insights │ │
|
|
│ │ - 로그 수집 │ │
|
|
│ │ - 메트릭 모니터링 │ │
|
|
│ │ - 알람 │ │
|
|
│ └────────────────────────────────────────────────────────────┘ │
|
|
└───────────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ 외부 API (Circuit Breaker 적용) │
|
|
├─────────────────────────────────────────────────────────────────┤
|
|
│ 국세청 API │ Claude API │ Stable Diffusion │ 우리동네TV │... │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 4.2 시퀀스 다이어그램 (AI 추천 플로우)
|
|
|
|
```
|
|
클라이언트 → Nginx Ingress: POST /api/ai/recommendations
|
|
Nginx Ingress → AI Service: JWT 검증 후 라우팅
|
|
|
|
AI Service → Redis: GET ai:recommendation:{key}
|
|
|
|
alt Cache HIT
|
|
Redis → AI Service: 캐시된 결과
|
|
AI Service → 클라이언트: 즉시 반환 (0.1초)
|
|
else Cache MISS
|
|
AI Service → Redis: SET job:{id}:status = pending
|
|
AI Service → RabbitMQ: 발행 Job Message
|
|
AI Service → 클라이언트: Job ID 반환 (0.1초)
|
|
|
|
RabbitMQ → Worker: Job 수신
|
|
Worker → Redis: SET job:{id}:status = processing
|
|
|
|
Worker → Claude API: AI 요청 (Circuit Breaker)
|
|
|
|
alt API 성공
|
|
Claude API → Worker: 결과 반환 (10초)
|
|
Worker → Redis: SET ai:recommendation:{key} (TTL 24h)
|
|
Worker → Redis: SET job:{id}:result
|
|
Worker → Redis: SET job:{id}:status = completed
|
|
else API 실패 (Circuit Open)
|
|
Worker → Redis: GET 유사 캐시 결과
|
|
Worker → Redis: SET job:{id}:result (Fallback)
|
|
Worker → Redis: SET job:{id}:status = completed
|
|
end
|
|
|
|
loop 5초 간격 폴링
|
|
클라이언트 → Nginx Ingress: GET /api/jobs/{id}
|
|
Nginx Ingress → AI Service: 라우팅
|
|
AI Service → Redis: GET job:{id}:status
|
|
|
|
alt completed
|
|
Redis → AI Service: status + result
|
|
AI Service → 클라이언트: 최종 결과
|
|
else processing
|
|
Redis → AI Service: status + progress
|
|
AI Service → 클라이언트: 진행 상황 (70%)
|
|
end
|
|
end
|
|
end
|
|
```
|
|
|
|
---
|
|
|
|
## 5. 개발/운영 환경 구성
|
|
|
|
### 5.1 개발 환경
|
|
|
|
**AKS 클러스터**:
|
|
```yaml
|
|
name: aks-dev-cluster
|
|
node_pool:
|
|
vm_size: Standard_B2s (2 vCPU, 4GB RAM)
|
|
node_count: 2
|
|
auto_scaling: false
|
|
|
|
estimated_cost: ~$100/월
|
|
```
|
|
|
|
**Azure Cache for Redis**:
|
|
```yaml
|
|
tier: Standard
|
|
capacity: C1 (1GB)
|
|
availability: Single instance
|
|
|
|
estimated_cost: ~$20/월
|
|
```
|
|
|
|
**Azure Database for PostgreSQL**:
|
|
```yaml
|
|
tier: Basic
|
|
compute: B_Gen5_1 (1 vCore)
|
|
storage: 50GB
|
|
|
|
estimated_cost: ~$30/월
|
|
```
|
|
|
|
**RabbitMQ**:
|
|
```yaml
|
|
deployment: StatefulSet (1 replica)
|
|
storage: 10GB PVC
|
|
|
|
estimated_cost: 포함 (AKS 노드)
|
|
```
|
|
|
|
**총 예상 비용**: **~$150/월**
|
|
|
|
### 5.2 운영 환경
|
|
|
|
**AKS 클러스터**:
|
|
```yaml
|
|
name: aks-prod-cluster
|
|
node_pool:
|
|
vm_size: Standard_D2s_v3 (2 vCPU, 8GB RAM)
|
|
node_count: 3 (다중 가용 영역)
|
|
auto_scaling: true (min: 3, max: 10)
|
|
|
|
estimated_cost: ~$300/월 (기본), ~$1,000/월 (최대)
|
|
```
|
|
|
|
**Azure Cache for Redis**:
|
|
```yaml
|
|
tier: Premium
|
|
capacity: P1 (6GB)
|
|
availability: Zone redundant (고가용성)
|
|
|
|
estimated_cost: ~$250/월
|
|
```
|
|
|
|
**Azure Database for PostgreSQL**:
|
|
```yaml
|
|
tier: General Purpose
|
|
compute: GP_Gen5_2 (2 vCore)
|
|
storage: 100GB
|
|
availability: Zone redundant
|
|
|
|
estimated_cost: ~$150/월
|
|
```
|
|
|
|
**RabbitMQ**:
|
|
```yaml
|
|
deployment: StatefulSet (3 replicas, HA)
|
|
storage: 30GB PVC per replica
|
|
|
|
estimated_cost: 포함 (AKS 노드)
|
|
```
|
|
|
|
**Azure Monitor + Application Insights**:
|
|
```yaml
|
|
estimated_cost: ~$50/월
|
|
```
|
|
|
|
**총 예상 비용**: **~$750/월** (기본), **~$1,450/월** (최대)
|
|
|
|
---
|
|
|
|
## 6. 구현 로드맵
|
|
|
|
### 6.1 MVP 일정 (12주)
|
|
|
|
| 주차 | 작업 내용 | 패턴 적용 | 담당 |
|
|
|------|----------|-----------|------|
|
|
| **1주** | Azure 인프라 구축 | - | DevOps |
|
|
| | - AKS 클러스터 생성 (개발/운영) | | |
|
|
| | - Azure Cache for Redis 생성 | | |
|
|
| | - Azure Database for PostgreSQL 생성 | | |
|
|
| | - Azure Container Registry 생성 | | |
|
|
| **2주** | API Gateway 구축 | API Gateway | DevOps + Backend |
|
|
| | - Nginx Ingress Controller 배포 | | |
|
|
| | - SSL 인증서 설정 | | |
|
|
| | - JWT 인증 미들웨어 구현 | | |
|
|
| **3-4주** | User/Event 서비스 | Cache-Aside | Backend |
|
|
| | - 회원가입/로그인 구현 | | |
|
|
| | - 사업자번호 검증 + 캐싱 | | |
|
|
| | - 이벤트 CRUD 구현 | | |
|
|
| **5-6주** | AI 서비스 | Async + Cache-Aside | Backend |
|
|
| | - Claude API 연동 | | |
|
|
| | - RabbitMQ 배포 및 Worker 구현 | | |
|
|
| | - Job 기반 비동기 처리 | | |
|
|
| | - AI 결과 캐싱 (24h TTL) | | |
|
|
| **7-8주** | Content 서비스 | Async + Cache-Aside | Backend |
|
|
| | - Stable Diffusion API 연동 | | |
|
|
| | - 이미지 생성 Job 처리 | | |
|
|
| | - 이미지 캐싱 및 Azure Blob Storage | | |
|
|
| **9-10주** | Distribution 서비스 | Circuit Breaker | Backend |
|
|
| | - 7개 외부 API 연동 | | |
|
|
| | - Resilience4j Circuit Breaker 적용 | | |
|
|
| | - Fallback 전략 구현 | | |
|
|
| **11주** | Participation/Analytics | Cache-Aside | Backend |
|
|
| | - 참여자 관리 및 추첨 | | |
|
|
| | - 대시보드 데이터 캐싱 (5분 TTL) | | |
|
|
| **12주** | 테스트 및 출시 | 전체 패턴 검증 | 전체 팀 |
|
|
| | - 부하 테스트 (k6, 100명) | | |
|
|
| | - 장애 시나리오 테스트 | | |
|
|
| | - Azure Monitor 알람 설정 | | |
|
|
| | - MVP 출시 | | |
|
|
|
|
### 6.2 기술 스택
|
|
|
|
**백엔드**:
|
|
- Java 17 + Spring Boot 3.2
|
|
- Resilience4j 2.1 (Circuit Breaker)
|
|
- Spring Data JPA + PostgreSQL
|
|
- Spring Data Redis
|
|
- Spring AMQP + RabbitMQ
|
|
|
|
**컨테이너 & 오케스트레이션**:
|
|
- Docker 24
|
|
- Kubernetes 1.28 (AKS)
|
|
- Nginx Ingress Controller 1.9
|
|
- Helm 3.13
|
|
|
|
**Azure 서비스**:
|
|
- Azure Kubernetes Service (AKS)
|
|
- Azure Cache for Redis
|
|
- Azure Database for PostgreSQL
|
|
- Azure Container Registry (ACR)
|
|
- Azure Monitor + Application Insights
|
|
- Azure Blob Storage (이미지 저장)
|
|
|
|
**모니터링 & 로깅**:
|
|
- Azure Monitor (메트릭)
|
|
- Application Insights (APM)
|
|
- Grafana (대시보드)
|
|
- Azure Log Analytics (로그 쿼리)
|
|
|
|
---
|
|
|
|
## 7. 예상 성과
|
|
|
|
### 7.1 성능 개선
|
|
|
|
| 항목 | Before | After (캐시 히트) | 개선율 |
|
|
|------|--------|-----------------|--------|
|
|
| AI 응답 시간 | 10초 | 0.1초 | **99%** |
|
|
| 이미지 생성 시간 | 5초 | 0.1초 | **98%** |
|
|
| 대시보드 로딩 시간 | 3초 | 0.5초 | **83%** |
|
|
| 동시 처리 가능 요청 | 10 req/sec | 50 req/sec | **5배** |
|
|
|
|
### 7.2 비용 절감
|
|
|
|
**AI API 비용** (캐시 히트율 80% 가정):
|
|
- Before: $600/월
|
|
- After: $120/월
|
|
- **절감액**: $480/월 (**80% 절감**)
|
|
|
|
**이미지 API 비용** (캐시 히트율 80% 가정):
|
|
- Before: $600/월
|
|
- After: $120/월
|
|
- **절감액**: $480/월 (**80% 절감**)
|
|
|
|
**총 API 비용 절감**: **$960/월** (**80% 절감**)
|
|
|
|
**Azure 인프라 비용**:
|
|
- 개발 환경: ~$150/월
|
|
- 운영 환경: ~$750/월 (기본), ~$1,450/월 (최대)
|
|
|
|
### 7.3 가용성 개선
|
|
|
|
| 지표 | Before | After | 개선 |
|
|
|------|--------|-------|------|
|
|
| 시스템 가용성 | 95% | 99% | **+4%p** |
|
|
| 외부 API 장애 시 서비스 지속 | ❌ 불가 | ✅ 가능 | - |
|
|
| 장애 자동 복구 시간 | 5분 (수동) | 30초 (자동) | **90% 단축** |
|
|
|
|
---
|
|
|
|
## 8. 모니터링 및 운영
|
|
|
|
### 8.1 Azure Monitor 메트릭
|
|
|
|
**AKS 클러스터**:
|
|
- CPU/메모리 사용률
|
|
- 노드 상태
|
|
- Pod 상태
|
|
- Ingress 요청 수 및 응답 시간
|
|
|
|
**Azure Cache for Redis**:
|
|
- 캐시 히트율 (목표: 80% 이상)
|
|
- 메모리 사용률 (목표: 70% 이하)
|
|
- 응답 시간 (목표: 100ms 이하)
|
|
- 연결 수
|
|
|
|
**Azure Database for PostgreSQL**:
|
|
- CPU/메모리 사용률
|
|
- 디스크 I/O
|
|
- 활성 연결 수
|
|
- 슬로우 쿼리
|
|
|
|
**Application Insights (APM)**:
|
|
- 서비스별 응답 시간
|
|
- 의존성 호출 (외부 API)
|
|
- 예외 및 에러
|
|
- 사용자 트래픽
|
|
|
|
### 8.2 커스텀 메트릭
|
|
|
|
**Circuit Breaker**:
|
|
- API별 실패율
|
|
- Circuit 상태 (Closed/Open/Half-Open)
|
|
- Fallback 호출 횟수
|
|
|
|
**Async Jobs**:
|
|
- Job 처리 시간
|
|
- 동시 Job 수
|
|
- Job 완료율
|
|
- Queue 길이 (RabbitMQ)
|
|
|
|
### 8.3 알람 임계값
|
|
|
|
| 지표 | Warning | Critical | 액션 |
|
|
|------|---------|----------|------|
|
|
| 캐시 히트율 | < 70% | < 50% | 캐시 전략 검토 |
|
|
| Redis 메모리 | > 80% | > 90% | 스케일업 |
|
|
| API 응답 시간 | > 500ms | > 1000ms | 성능 조사 |
|
|
| Circuit Breaker Open | 1개 | 3개 이상 | 긴급 대응 |
|
|
| Pod CPU | > 70% | > 90% | Pod 스케일아웃 |
|
|
| Pod 메모리 | > 80% | > 95% | Pod 재시작 |
|
|
|
|
### 8.4 로그 수집 및 분석
|
|
|
|
**Azure Log Analytics**:
|
|
```kusto
|
|
// 에러 로그 분석
|
|
ContainerLog
|
|
| where LogEntry contains "ERROR"
|
|
| summarize count() by Computer, ContainerID
|
|
| order by count_ desc
|
|
|
|
// API 응답 시간 분석
|
|
requests
|
|
| where url contains "/api/"
|
|
| summarize avg(duration), percentile(duration, 95) by name
|
|
| order by avg_duration desc
|
|
|
|
// Circuit Breaker 상태 변화 추적
|
|
traces
|
|
| where message contains "Circuit Breaker"
|
|
| project timestamp, message, severityLevel
|
|
| order by timestamp desc
|
|
```
|
|
|
|
---
|
|
|
|
## 9. 장애 대응 절차
|
|
|
|
### 9.1 Circuit Breaker Open 발생
|
|
|
|
**대응 절차**:
|
|
1. 알람 수신 (Azure Monitor → Slack/Email)
|
|
2. Application Insights에서 해당 외부 API 호출 현황 확인
|
|
3. Fallback 전략 정상 동작 확인 (로그 분석)
|
|
4. 30초 후 자동 Half-Open 전환 확인
|
|
5. 복구 실패 시:
|
|
- 외부 API 제공사 상태 확인
|
|
- 긴급 연락
|
|
- 장기 장애 시 사용자 공지
|
|
|
|
### 9.2 캐시 장애
|
|
|
|
**대응 절차**:
|
|
1. Azure Cache for Redis 상태 확인 (Azure Portal)
|
|
2. Zone Redundancy 자동 Failover 확인 (운영 환경)
|
|
3. 캐시 미스로 전환 (성능 저하 허용)
|
|
4. Redis 복구:
|
|
- 개발: 인스턴스 재시작
|
|
- 운영: Azure 자동 복구 대기 또는 수동 Failover
|
|
|
|
### 9.3 AKS 노드 장애
|
|
|
|
**대응 절차**:
|
|
1. Azure Monitor에서 노드 상태 확인
|
|
2. Kubernetes 자동 재스케줄링 확인
|
|
3. Pod가 정상 노드로 이동 확인
|
|
4. 장애 노드 제거 및 새 노드 추가 (Auto Scaling)
|
|
|
|
---
|
|
|
|
## 10. 체크리스트
|
|
|
|
### 10.1 패턴 적용 완료 확인
|
|
|
|
- [ ] **Cache-Aside**: AI 결과, 이미지, 사업자번호 검증 캐싱 완료
|
|
- [ ] **API Gateway**: Nginx Ingress + JWT 인증 + Rate Limiting 완료
|
|
- [ ] **Asynchronous Request-Reply**: RabbitMQ + Worker 기반 Job 처리 완료
|
|
- [ ] **Circuit Breaker**: Resilience4j 적용 및 Fallback 전략 구현 완료
|
|
|
|
### 10.2 성능 목표 달성 확인
|
|
|
|
- [ ] AI 응답 시간: 10초 이내 (캐시 미스), 0.1초 (캐시 히트)
|
|
- [ ] 캐시 히트율: 80% 이상
|
|
- [ ] 시스템 가용성: 99% 이상
|
|
- [ ] 동시 처리 가능 요청: 50 req/sec 이상
|
|
|
|
### 10.3 Azure 인프라 구축 완료 확인
|
|
|
|
- [ ] AKS 클러스터 생성 (개발/운영)
|
|
- [ ] Azure Cache for Redis 구성 및 연결
|
|
- [ ] Azure Database for PostgreSQL 구성 및 연결
|
|
- [ ] Azure Container Registry 구성 및 CI/CD 연동
|
|
- [ ] Nginx Ingress Controller 배포 및 설정
|
|
- [ ] SSL 인증서 적용
|
|
- [ ] Azure Monitor + Application Insights 통합
|
|
|
|
### 10.4 운영 준비 완료 확인
|
|
|
|
- [ ] 모니터링 대시보드 구축 (Azure Monitor + Grafana)
|
|
- [ ] 알람 설정 완료 (Slack/Email)
|
|
- [ ] 장애 대응 매뉴얼 작성
|
|
- [ ] 부하 테스트 완료 (k6, 100명)
|
|
- [ ] 장애 시나리오 테스트 완료 (Circuit Breaker, 캐시 장애)
|
|
|
|
---
|
|
|
|
## 11. 다음 단계 (Phase 2 이후)
|
|
|
|
**MVP 이후 확장 계획** (선택 사항):
|
|
|
|
- **Retry 패턴**: 일시적 오류 자동 재시도 (현재는 Circuit Breaker로 커버)
|
|
- **Queue-Based Load Leveling**: 트래픽 폭증 시 부하 분산
|
|
- **Saga 패턴**: 복잡한 분산 트랜잭션 관리 (이벤트 생성 플로우)
|
|
- **CQRS**: 읽기/쓰기 분리로 대시보드 성능 최적화
|
|
- **Event Sourcing**: 이벤트 변경 이력 추적 및 감사
|
|
- **Service Mesh (Istio)**: 고급 트래픽 관리 및 보안
|
|
- **Azure Front Door**: 글로벌 CDN 및 WAF
|
|
- **Azure Key Vault**: 시크릿 관리 강화
|
|
|
|
---
|
|
|
|
## 참고 문서
|
|
|
|
- [유저스토리](../userstory.md)
|
|
- [UI/UX 설계서](../uiux/uiux.md)
|
|
- [클라우드 디자인 패턴 개요](../../claude/cloud-design-patterns.md)
|
|
- [Azure Kubernetes Service 공식 문서](https://learn.microsoft.com/ko-kr/azure/aks/)
|
|
- [Azure Cache for Redis 공식 문서](https://learn.microsoft.com/ko-kr/azure/azure-cache-for-redis/)
|
|
- [Resilience4j 공식 문서](https://resilience4j.readme.io/)
|
|
- [백업 파일](./backup/) - 이전 버전
|