- system/overview.md: 전체 아키텍처 개요 - system/api-structure.md: API 구조 (220 모델, 1027 엔드포인트, 18 라우트 도메인) - system/react-structure.md: React 구조 (249 페이지, 612 컴포넌트) - system/mng-structure.md: MNG 구조 (171 컨트롤러, 436 Blade 뷰) - system/docker-setup.md: Docker 7 컨테이너 구성 - system/database/README.md + 9개 도메인 스키마 (270+ 테이블) - core, hr, sales, production, finance, boards, files, system, erp-analysis Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7.7 KiB
SAM 10,000 테넌트 스케일링 로드맵
작성일: 2026-02-22 성격: 가상 시나리오 — 세계 최고 수준 엔지니어링 팀이 설계한다는 가정
1. 현재 상태 진단
1.1 현재 아키텍처 요약
브라우저 → Nginx → PHP-FPM(20 workers) → Laravel → MySQL 8.0 (단일)
서버: 2코어/3.8GB RAM | 배포: 수동 git pull | 모니터링: 없음 | 캐시: 없음
1.2 핵심 병목 지점
| 영역 | 현재 | 10,000 테넌트 시 문제 | 심각도 |
|---|---|---|---|
| DB | MySQL 단일 | 커넥션 폭발, 슬로우 쿼리 | 치명적 |
| 컴퓨팅 | FPM 20워커 | 동시 요청 20개 제한 | 치명적 |
| 캐시 | 없음 | 모든 요청이 DB 직행 | 치명적 |
| 큐 | DB 드라이버 | 큐 자체가 DB 압박 | 심각 |
| 검색 | SQL LIKE | 219개 테이블 풀스캔 | 심각 |
| 배포 | 수동 git pull | 다운타임, 롤백 불가 | 높음 |
| 모니터링 | 없음 | 장애 인지 불가 | 높음 |
1.3 가장 먼저 죽는 곳
- 동시 사용자 20명 → FPM 워커 전부 점유 → 504 Timeout
- 동시 사용자 200명 → MySQL
max_connections(151) 고갈 - 테넌트 1,000개 → 권한 UNION 3개 쿼리가 매 요청마다 실행
2. 5단계 로드맵 개요
Phase 1 (0~3개월) 캐시 + 모니터링 + 서버 업그레이드 → 100 테넌트
Phase 2 (3~6개월) DB 복제 + K8s + S3 + 검색 엔진 → 1,000 테넌트
Phase 3 (6~9개월) 마이크로서비스 + 이벤트 아키텍처 → 3,000 테넌트
Phase 4 (9~12개월) DB 샤딩 + 테넌트 티어링 + 멀티리전 → 10,000 테넌트
Phase 5 (12~18개월) 관측성 고도화 + 카오스 엔지니어링 → 10,000+ 테넌트
3. Phase 1: 기초 체력 (0~3개월) → 100 테넌트
3.1 Redis 도입 (최우선)
| 대상 | 캐시 TTL | 효과 |
|---|---|---|
| 세션 저장소 | 2시간 | DB 세션 테이블 부하 제거 |
| 권한 캐시 | 5분 | UNION 3개 쿼리 제거 (매 요청) |
| 메뉴 트리 | 10분 | 중첩 쿼리 제거 |
| 공통 코드 | 1시간 | common_codes 반복 조회 제거 |
| Laravel 큐 | - | database → redis 드라이버 전환 |
예상 효과: DB 쿼리 60~70% 감소, 응답 시간 3~5배 개선.
3.2 모니터링 구축
Grafana + Prometheus + Laravel Telescope + MySQL slow_log.
핵심 알림: FPM 워커 사용률 >80%, MySQL 커넥션 >100, 응답 시간 >2초, 큐 적체 >1000건 → Slack 알림.
3.3 서버 업그레이드 + CI/CD
| 항목 | 현재 | Phase 1 |
|---|---|---|
| CPU/RAM | 2코어/3.8GB | 8코어/32GB |
| 스토리지 | HDD | NVMe SSD |
| FPM | 20 워커 | 100 워커 |
| 배포 | 수동 git pull | Jenkins CI/CD (무중단 rolling) |
4. Phase 2: 수평 확장 (3~6개월) → 1,000 테넌트
4.1 아키텍처
브라우저 → LB(L7) → App Server ×N → Redis Cluster
→ MySQL Primary + Replica ×2
→ S3 + CDN (정적/업로드 파일)
4.2 핵심 변경
| 영역 | 변경 | 효과 |
|---|---|---|
| K8s | HPA 기반 오토스케일링 (API 3~10 pods) | 트래픽에 따라 자동 확장 |
| DB R/W 분리 | config/database.php에 read/write 설정 |
읽기 부하 80% Replica로 분산 |
| 파일 → S3 | Laravel Filesystem → S3 + CloudFront | 서버 간 파일 공유, CDN 가속 |
| 검색 엔진 | SQL LIKE → Meilisearch | 밀리초 응답, 형태소 분석, 오타 허용 |
5. Phase 3: 마이크로서비스 (6~9개월) → 3,000 테넌트
5.1 서비스 분리
모놀리스(sam-api) → Auth | Product | Order | MES | Finance | Notification
분리 순서: ① 알림 (독립적, 비동기) → ② MES (변경 빈도 높음) → ③ 인증 (가용성 최우선)
5.2 이벤트 기반 전환
동기 호출 체인을 이벤트 발행으로 전환한다. 주문 생성 시 재고 차감/알림/회계를 비동기 처리.
메시지 브로커: Redis Streams 또는 RabbitMQ. 응답 시간 2초 → 200ms.
5.3 API Gateway
Kong/Traefik으로 테넌트별 Rate Limiting, 인증 검증, 요청 라우팅, 응답 캐싱 통합.
6. Phase 4: 대규모 멀티테넌시 (9~12개월) → 10,000 테넌트
6.1 DB 샤딩
Shard Router (tenant_id 기반) → Shard 0 | Shard 1 | Shard 2 ...
각 Shard = Primary + Replica
tenant_id가 파티션 키이므로 크로스 샤드 조인 불필요 — SAM의 강점.
6.2 테넌트 티어링
| Tier | 자원 | SLA | Rate Limit |
|---|---|---|---|
| Enterprise | 전용 DB/Redis/Pod | 99.99% | 1000/분 |
| Business | 공유 (높은 우선순위) | 99.9% | 300/분 |
| Standard | 공유 | 99.5% | 60/분 |
6.3 멀티리전
한국(Primary) + 일본/동남아(Secondary) 리전. DB 복제 + Global Load Balancer로 지리적 라우팅.
7. Phase 5: 엔터프라이즈 성숙 (12~18개월) → 10,000+
| 영역 | 도입 | 목적 |
|---|---|---|
| 관측성 | Jaeger(분산추적) + Loki(중앙로그) + PagerDuty | 전체 서비스 체인 추적 |
| 카오스 엔지니어링 | DB 다운, Pod Kill, 네트워크 지연 주입 | 복원력 검증 |
| 데이터 파이프라인 | CDC(Debezium) → 데이터 웨어하우스 | 운영 DB에서 분석 쿼리 분리 |
| 배포 | Blue-Green + Canary (5% → 100%) | 30초 이내 롤백 |
8. 기술 스택 진화 요약
| 영역 | 현재 | Phase 1 | Phase 2 | Phase 4 |
|---|---|---|---|---|
| 서버 | 단일 2코어 | 단일 8코어 | K8s 3+ 노드 | 멀티리전 |
| DB | MySQL 단일 | + 쿼리 최적화 | Primary + Replica ×2 | Shard ×N |
| 캐시 | 없음 | Redis 단일 | Redis Cluster | 테넌트별 격리 |
| 큐 | DB | Redis | Redis | 티어별 큐 |
| 배포 | 수동 | Jenkins CI/CD | K8s Rolling | Canary |
| 모니터링 | 없음 | Grafana | + Telescope | + 카오스 |
9. 가장 중요한 3가지
1. Redis (=산소): 캐시 없이 10,000 테넌트는 절대 불가능. 권한 UNION 쿼리 3개 + 메뉴 + 세션이 매 요청마다 실행된다. Redis 하나로 DB 부하 60% 감소.
2. DB R/W 분리 (=심장): ERP 읽기:쓰기 = 8:2. Replica 2대 추가로 DB 부하 1/3 분산. Laravel config/database.php 변경만으로 적용.
3. 관측성 (=눈): 모니터링 없이 스케일링은 눈 감고 운전하는 것. 슬로우 쿼리 + 응답 시간 + 알림부터 시작.
10. SAM 특수 고려사항
10.1 tenant_id 기반 격리
- 강점:
BelongsToTenant스코프 일관 적용, 크로스 테넌트 조인 불필요 → 샤딩에 유리 - 개선 필요:
tenant_id인덱스 첫 번째 컬럼 여부 전수 검사,deleted_at누적 데이터 파티셔닝
10.2 권한 시스템 최적화
3중 UNION 쿼리가 매 요청 실행된다. 개선: ① Redis 권한 캐시(TTL 5분) → ② 변경 시 해당 사용자 캐시만 무효화 → ③ JWT 클레임에 권한 포함(DB 조회 0회).
10.3 219개 테이블 샤딩 분류
| 분류 | 예시 | 처리 |
|---|---|---|
| 테넌트 데이터 | orders, products | 샤딩 대상 |
| 시스템 공통 | permissions, common_codes | 공유 DB 유지 |
| 감사 로그 | audit_logs | 별도 시계열 DB |
관련 문서
| 문서 | 설명 |
|---|---|
| overview.md | 현재 시스템 아키텍처 |
| security-policy.md | 현재 보안 구조 |
| docker-setup.md | 현재 Docker 구성 |
| server-how-it-works.md | 서버 동작 원리 |
최종 업데이트: 2026-02-22