36 KiB
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 구성:
# 개발 환경
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 배포
# 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
주요 기능:
- 인증/인가: JWT 토큰 검증
- 라우팅: URL 기반 서비스 라우팅
- Rate Limiting: API 호출 제한
- 로깅: 중앙집중식 접근 로그
- SSL 종료: HTTPS 처리
3.2.2 Azure 구현 옵션
옵션 1: Azure API Management (권장 - 운영 환경)
특징:
- 완전 관리형 서비스
- 내장 인증/인가, Rate Limiting
- Azure Monitor 통합
- 높은 비용 (약 $50/월 이상)
장점:
- 운영 부담 최소화
- 기업급 기능 (개발자 포털, API 버전 관리)
- Azure 생태계 통합
단점:
- 비용 부담
- 커스터마이징 제한
옵션 2: Nginx Ingress Controller (권장 - 개발 환경 / 비용 절감)
특징:
- AKS 내장 Ingress Controller
- 무료 (AKS 비용에 포함)
- 높은 커스터마이징
장점:
- 비용 효율적
- Kubernetes 네이티브
- 유연한 설정
단점:
- 수동 설정 필요
- 운영 부담
3.2.3 Nginx Ingress 구현 (권장)
# 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 인증 미들웨어 (각 서비스에서 구현):
// 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 (권장 - 운영 환경)
특징:
- 완전 관리형 메시지 큐
- 높은 안정성 및 가용성
- Azure Monitor 통합
비용:
- Basic tier: $0.05/million operations
- Standard tier: $10/월 기본 + $0.80/million operations
장점:
- 운영 부담 최소화
- 엔터프라이즈급 안정성
- Azure 생태계 통합
옵션 2: RabbitMQ (권장 - 개발 환경 / 비용 절감)
특징:
- 오픈소스 메시지 브로커
- AKS에 직접 배포
- 무료 (인프라 비용만)
장점:
- 비용 효율적
- 높은 커스터마이징
- Kubernetes 네이티브 배포
단점:
- 운영 부담 (HA, 백업)
3.3.3 RabbitMQ 구현 (권장)
Kubernetes 배포:
# 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 구현 예시
// 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):
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
<version>2.1.0</version>
</dependency>
설정 (application.yml):
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
코드 예시:
@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)
커스텀 메트릭:
@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 클러스터:
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:
tier: Standard
capacity: C1 (1GB)
availability: Single instance
estimated_cost: ~$20/월
Azure Database for PostgreSQL:
tier: Basic
compute: B_Gen5_1 (1 vCore)
storage: 50GB
estimated_cost: ~$30/월
RabbitMQ:
deployment: StatefulSet (1 replica)
storage: 10GB PVC
estimated_cost: 포함 (AKS 노드)
총 예상 비용: ~$150/월
5.2 운영 환경
AKS 클러스터:
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:
tier: Premium
capacity: P1 (6GB)
availability: Zone redundant (고가용성)
estimated_cost: ~$250/월
Azure Database for PostgreSQL:
tier: General Purpose
compute: GP_Gen5_2 (2 vCore)
storage: 100GB
availability: Zone redundant
estimated_cost: ~$150/월
RabbitMQ:
deployment: StatefulSet (3 replicas, HA)
storage: 30GB PVC per replica
estimated_cost: 포함 (AKS 노드)
Azure Monitor + Application Insights:
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:
// 에러 로그 분석
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 발생
대응 절차:
- 알람 수신 (Azure Monitor → Slack/Email)
- Application Insights에서 해당 외부 API 호출 현황 확인
- Fallback 전략 정상 동작 확인 (로그 분석)
- 30초 후 자동 Half-Open 전환 확인
- 복구 실패 시:
- 외부 API 제공사 상태 확인
- 긴급 연락
- 장기 장애 시 사용자 공지
9.2 캐시 장애
대응 절차:
- Azure Cache for Redis 상태 확인 (Azure Portal)
- Zone Redundancy 자동 Failover 확인 (운영 환경)
- 캐시 미스로 전환 (성능 저하 허용)
- Redis 복구:
- 개발: 인스턴스 재시작
- 운영: Azure 자동 복구 대기 또는 수동 Failover
9.3 AKS 노드 장애
대응 절차:
- Azure Monitor에서 노드 상태 확인
- Kubernetes 자동 재스케줄링 확인
- Pod가 정상 노드로 이동 확인
- 장애 노드 제거 및 새 노드 추가 (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: 시크릿 관리 강화