Solo Fullstack Project

Co-Talk

KakaoTalk 스타일의 실시간 메시징 플랫폼. 백엔드 아키텍처 설계, 크로스플랫폼 모바일/데스크톱 클라이언트(Android/iOS/macOS/Windows), 프로덕션 인프라 구축 및 운영까지 1인 풀스택 개발.

Java 25Spring Boot 3.5FlutterPostgreSQL 16Redis 7DockerWebSocketPrometheusGrafanaZipkinMinIO
GitHub에서 보기

핵심 기술 구현

실시간 메시징, 멀티 인스턴스 확장, 크로스플랫폼까지 — 메시징 플랫폼의 핵심 과제 해결

실시간 채팅

WebSocket(STOMP) + Redis Pub/Sub으로 멀티 인스턴스 환경에서도 실시간 메시지 동기화. 타이핑 인디케이터, 읽음 확인, 이모지 리액션.

멀티 인스턴스 스케일링

3개 인스턴스 수평 확장. Nginx 로드밸런싱 + Redis Pub/Sub으로 인스턴스 간 메시지 브로드캐스팅.

크로스플랫폼

Flutter 단일 코드베이스로 Android, iOS, macOS, Windows 지원. BLoC 상태관리 + Drift SQLite 오프라인 캐시.

모니터링 파이프라인

Prometheus + Grafana + Loki + Zipkin 통합 Observability. 14개 알림 규칙으로 장애 조기 감지.

카나리아 배포

app-1 카나리아 → Prometheus 메트릭 검증 → 5xx > 5% 시 자동 롤백. 순차적 롤아웃.

1,400+ 테스트

82% 커버리지. ArchUnit 아키텍처 테스트, Testcontainers 통합 테스트, k6 부하 테스트 5개 시나리오.

아키텍처 하이라이트

01

Hexagonal Architecture

ArchUnit 9개 규칙 자동 검증. 도메인 외부 의존성 제로. 65개 UseCase(1:1 Service). InMemory 어댑터로 인프라 없이 단위 테스트 가능.

domain/ → application/ → adapter/
02

Redis Pub/Sub Message Broadcast

SimpleBroker 인스턴스 로컬 한계를 Redis Pub/Sub으로 해결. StompBrokerRelay + RabbitMQ 없이 이미 사용 중인 Redis로 추가 인프라 비용 제로 멀티 인스턴스 동기화.

chat:room:{id} · chat:room:{id}:reaction · chat:room:{id}:event
03

Snowflake ID Generator

Twitter 스타일 분산 ID. 41-bit timestamp + 5-bit DC + 5-bit worker + 12-bit sequence. Redis SETNX Worker ID 원자적 할당으로 멀티 인스턴스 충돌 없는 고유 ID 생성.

epoch: 2024-01-01 · 4,096 IDs/ms/instance
04

Dual Rate Limiting

Nginx L7에서 DDoS 1차 차단(30r/s, 인증 5r/m). Bucket4j-Redis에서 사용자별 비즈니스 제한 2차 적용. 역할 분리로 각 레이어가 최적의 제한 전략 수행.

nginx limit_req + bucket4j-redis
05

Canary Deployment

Prometheus 메트릭 기반 자동 롤백. :latest → :previous 백업 → app-1 카나리아 → 60초 검증 → 순차 롤아웃. Graceful Shutdown 30초로 진행 중인 WebSocket 연결 안전 종료.

scripts/deploy.sh · 5xx > 5% → auto rollback
16
DB Tables
65
UseCases
14
Alert Rules
4
Platforms
82%
Coverage
1.4K+
Tests

기술적 의사결정

DECISION 01

왜 Hexagonal Architecture인가

Layered에서 도메인이 프레임워크에 강결합. Hexagonal로 도메인 외부 의존성 제로. InMemory 어댑터로 인프라 없이 테스트. ArchUnit 9개 규칙 CI 자동 검증.

DECISION 02

왜 SimpleBroker + Redis Pub/Sub인가

StompBrokerRelay + RabbitMQ는 추가 인프라 필요. 이미 Redis 사용 중이었으므로 Redis Pub/Sub으로 추가 비용 제로 멀티 인스턴스 동기화.

DECISION 03

왜 Snowflake ID인가

AUTO_INCREMENT는 멀티 인스턴스 충돌, UUID는 정렬 불가 + 인덱스 비효율. Snowflake는 시간순 정렬 + DB 비의존 + 멀티 인스턴스 안전.

DECISION 04

왜 이중 Rate Limiting인가

단일 레이어는 DDoS와 비즈니스 로직 제한을 동시에 처리 어려움. Nginx(DDoS방어) + Bucket4j-Redis(비즈니스제한) 역할 분리.

DECISION 05

NAS 8GB에서 3-인스턴스 운영

인스턴스당 768MB 최적화. Redis maxmemory 256MB + LRU eviction. ~4.5GB/8GB. Prometheus 알림으로 Heap > 85% 조기 경고.

DECISION 06

왜 Java 25 + Spring Boot 3.5 업그레이드인가

WebSocket 메시지 처리에 Virtual Threads를 도입했으나, synchronized 블록 진입 시 carrier thread가 pinning되어 처리량 저하 발생. Java 25에서 synchronized pinning 문제가 해결되어 업그레이드. Spring Boot 3.5로 함께 올려 Virtual Threads 네이티브 지원 최적화.

실전 트러블슈팅

TROUBLESHOOT 01

멀티 인스턴스 메시지 전달 파이프라인의 Observability 설계

문제 정의

Redis Pub/Sub 멀티 인스턴스 브로드캐스팅에서 "메시지가 정말 모든 사용자에게 잘 전달되고 있는가?"를 증명할 방법이 없었음. 장애가 발생해도 사용자 리포트 전까지 감지 불가.

설계 과정

메시지 전달 경로를 Service → Redis PUBLISH → Redis SUBSCRIBE → WebSocket SEND 4단계로 분리. 각 단계에 Micrometer 카운터/게이지 삽입. type(message/reaction/event) + result(success/failure) 태그로 차원 분리.

핵심 설계

10개 커스텀 메트릭 + 파이프라인 전용 알림 3개: RedisPublishFailureRate(발행 실패 > 1%), WebSocketDeliveryFailureRate(전달 실패 > 1%), MessageDeliveryImbalance(인스턴스 간 전달량 50%+ 편차 — 부분 장애 감지). Critical: 전체 파이프라인 실패율 > 10%.

결과

"메시지가 전달되고 있다"를 숫자로 증명하는 체계 확보. DeliveryImbalance 알림으로 "3개 중 1개만 장애"인 부분 장애까지 선제적 감지.

TROUBLESHOOT 02

카나리아 배포 자동화와 "안전한 배포"의 기준 정의

문제 정의

Blue-Green 배포에서 트래픽 전환 시 전체 서비스가 동시에 영향받는 위험. "이 배포가 안전한가?"를 판단하는 객관적 기준이 없었고, 수동 확인에 의존.

설계 과정

"안전한 배포"를 정량적으로 정의: 5xx 에러율 5% 이하를 임계값. 검증 시간 윈도우 60초(오탐 vs 장애 확대 트레이드오프).

핵심 설계

3단계 파이프라인 — 1) :latest → :previous 이미지 백업, 2) app-1 카나리아 → 헬스체크(120초) → 60초 대기 → Prometheus HTTP API로 5xx rate 자동 쿼리, 3) 초과 → :previous 자동 롤백 / 통과 → app-2, app-3 순차 배포. Graceful Shutdown 30초.

결과

배포 안전성 정량적 기준 확립. 장애 영향 전체 → 1/3 축소. 수동 판단 제거로 human error 방지.