Backend & Infrastructure Engineer
Portfolio
단단한 시스템 엔진과 변화에 유연한 서스펜션을 갖춘 엔지니어 한지운입니다.
9,000+
실사용자 서버 운영
1,000대
동시 처리 시스템 설계
KCI
논문 공동연구
HAN JIWOON
2003.07.05
About
Education
한성대학교
컴퓨터공학부 학사
GPA : 3.76 / 4.5
2022.03 – 2026.08
Certifications
정보처리기사
2025.09
TOEIC Speaking IM3
2026.03
Publications
GraphRAG를 활용한 EPUB 기반 추론형 리더기
공동저자 및 연구
2024.12
Experiences
현대오토에버 모빌리티 SW스쿨 (클라우드) *
- › 부회장으로서 팀별 기술 공유 세션, 멘토링(20인), 알고리즘 맟 취업 스터디(7명)를 직접 기획하며 함께 성장하는 환경을 주도적으로 설계
- › K3s 클러스터 기반 1,000대 차량 에이전트 OTA 검증 플랫폼 1인 개발 (진행 중)
교내 스쿨버스 앱 서버 유지보수 *
2024.06 – 2024.12- › 9,000+ 실사용자 대상 앱 서버 유지보수 — 일일 API 호출량 30% 감소, 위치 매칭 실패율 87% 감소, API 응답속도 200ms 이하 유지
학부연구생
2024.03 – 2025.02컴퓨터공학부 교과 교육 조교
2025.09 – 2025.12- › 학생들이 반복적으로 막히는 핵심 개념 · 빈출 오류를 문서화해 실습 효율 향상
IT연합동아리 멋쟁이사자처럼 백엔드
2024.03 – 2024.12학습능력향상튜터링 튜터
2023.02 – 2025.12컴퓨터공학부 동계 코딩캠프 튜터
2025.01Projects
주요 프로젝트 상세 소개
Project
OTA Dependency Validator
커넥티드 카 무선 업데이트 안정성 확보를 위한 시스템 진단 및 검증 플랫폼
차량 소프트웨어 무선 업데이트(OTA) 시, 부품 간 버전 호환성을 업데이트 이전에 자동 검증하여 업데이트 실패로 인한 차량 고장을 원천 차단하는 플랫폼입니다.
KEY RESULTS
// PROJECT OVERVIEW
커넥티드 카 1,000대 규모 OTA 사전 검증 시스템
01 프로젝트 목적
warning RISK – 해결해야 할 문제
ECU 간 HW-SW 버전 의존성이 사전에 검증되지 않으면,
OTA 업데이트 실패 및 차량 불능(Bricking)이 발생해 리콜 · 인명사고로 직결됨
check SOLUTION – 구현 방향
배포 전 DB 레이어에서 호환성을 사전 검증하는 End-to-End 관리 플랫폼을 구축하여 Bricking 리스크를 시스템 레벨에서 원천 차단
1,000대 규모 분산 차량 에이전트를 양산 환경과 유사한 조건으로 시뮬레이션하고, Kafka → Redis → SAP HANA로 이어지는 3단 실시간 파이프라인 위에서 ISO 24089 기반 자동 롤백 · 에러 감지 메커니즘을 구현한다.
1,000대 규모의 동시 요청 환경에서 데이터 정합성을 보장하는 것을 목표로 한다.
03 주요 업무 및 상세 역할
분산 인프라 설계
- › K3s 마스터-워커-4-VM 클러스터 아키텍처 설계
- › 1,000개 차량 Pod 배포 전략 및 워크로드 격리
- › Go 1,000 고루틴 Lock-Free Atomic 동시성 제어
- › K8s HPA 기반 탄력적 스케일링 정책 수립
데이터 파이프라인 구현
- › Kafka 3-Node 클러스터 구축 및 Consumer Group 설계
- › Redis 인메모리 세션 관리 및 0.0016s 실시간 판별
- › SAP HANA CDS 기반 HW-SW 의존성 검증 쿼리 설계
- › HANA → Redis → ECU 실시간 피드백 루프 구현
ANTI-BRICKING 구현
- › ISO 24089 기반 에러 감지 및 자동 롤백 메커니즘계
- › SHA-256 Hash 기반 펌웨어 무결성 검증 (Code Signing)
- › Fail-Safe Dual Bank 복구 시뮬레이션
- › Autosar DLT 바이너리 포맷 파서 구현
표준 검증 및 테스트
- › ISO 3779 VIN 17자리 고유 식별 체계 적용
- › ISO 21434 보안 요구사항 아키텍처 반영
- › 장애 시나리오 기반 Zero Data Loss 검증
- › 1,000 에이전트 동시 부하 테스트 및 TPS 분석
03 프로젝트 내용 – Architecture Evolution
LEVEL 1
무결성 및 보안
Security · ISO 21434- • Code Signing (AIE) — 펌웨어 패키지 서명 검증, SHA-256 Hash를 HANA DB에 저장·관리
- • Verification (클라이언트/ECU) — ota-agent가 패키지 수신 즉시 서버 제공 Hash 대조
- • Fail-Safe — 검증 실패 시 자동 복구(Dual Bank), 블랙 시뮬레이터 적용
LEVEL 2
클라우드 네이티브 전환
Scalability · 1,000 ECU- • Containerization — Docker 이미지화, K8s HPA로 CPU/Memory 부하 탄력 대응
- • GitOps CI/CD — ArgoCD·GitHub Actions 기반 자동화 배포 및 롤백 파이프라인
- • K3s 위 1,000개 독립 Pod 분산 배치 — 실제 플릿과 동등한 부하 환경 재현
LEVEL 3
배포기 처리 및 실시간 모니터링
Efficiency · Sandwich- • Kafka Message Queue — DLT 패킷 완충, Consumer Group 병렬 처리로 병목 방지
- • Redis/SAP HANA 하이브리드 — 인메모리 0.0016s 판별 + DB 의존성 검증 이중화
- • Real-time Monitoring Dashboard — Throughput(TPS) 시각화, Latency 실시간 추적
ARCHITECTURE
K3s 클러스터 - 1,000대 차량 에이전트
Kafka-Redis-HANA 파이프라인 실시간 처리
ISO 24089 기반 안티 브리킹 시스템 수현
SYSTEM ARCHITECTURE · VM1~VM5
AGENT LAYER
VM1 (K3s) : agent
master node
K3s Control Plane
VM2 (K3s)
worker node1
~333 Pods
VM3 (K3s)
worker node2
~333 Pods
VM4 (K3s)
worker node3
~333 Pods
1,000대 에이전트 Pod화 - 각각 MQTT로 연결 Autosar DLT 바이너리 패킷 발행
SERVER LAYER – VNS (DTA SERVER)
Kafka 3-Node Cluster Hybrid Storage
Kafka
Broker1
Kafka
Broker2
Kafka
Broker3
HANA DB
CDS · Rule
Redis
0.0016s Cache
업데이트 가능 여부 피드백 (DB 판단 후 전송)
분산 인프라
K3s · Go- › K3s 마스터-워커 아키텍처로 4개 VM에 1,000개 독립 차량 에이전트(Pod)를 동시 실행 커넥티드 카 양산 환경과 유사한 부하 재현
- › Go 1,000 고루틴에서 Lock-Free Atomic 연산으로 동시성 데이터 정합성 100% 달성
데이터 파이프 라인
Kafka · Redis · HANA- › Kafka 3-Node 클러스터로 초당 수천 건의 DLT 바이너리 패킷 무손실 수집 — 단일 노드 장애 시에도 Zero Data Loss 보장
- › Redis 인메모리 캐시 기반 0.001초 단위 실시간 업데이트 판별
- › HANA DB CDS 레이어의 HW-SW 의존성 검증을 결합한 하이브리드 의사결정 구조 설계
안티 브리킹/ 표준
ISO 24089 · DLT- › ISO 24089(OTA) 기반 에러 감지 및 자동 롤백 메커니즘 구현으로 펌웨어 업데이트 실패 시 차량 벽돌화(Bricking) 원천 차단
- › ISO 3779 규격의 17자리 VIN 식별 체계 및 Autosar DLT 바이너리 포맷 적용으로 실무 차량 통신 표준 완전 준수
1,000
독립 차량 에이전트(Pod)
0.0016s
Redis 실시간 판별 레이턴시
3-Node
Kafka 클러스터 Zero Data Loss
ISOx3
24089 · 3779 · 21434 표준 준수
End-to-End Pipeline
K3s Pod
×1,000 Agent
DLT Packet
Autosar 바이너리
Kafka
3-Node / Zero Loss
Redis
0.0016s 판별
HANA DB
CDS 의존성 검증
Feedback
Auto Rollback
05 주요 기술 스택
06 핵심 성과 – Problem · Action · Result
Problem
기술적 도전
- › ECU 간 버전 의존성 미검증으로 인한 OTA 업데이트 실패(Brick) 현상 – 리콜·인명사고로 직결
- › 1,000대 에이전트 동시 보고 시 발생하는 트래픽 폭주(Mass Request) 및 DB 병목 현상
Action
해결 방법
- DB-Level Validation – 의존성 체크를 앱이 아닌 HANA CDS View에서 처리, 정합성·고속 검증 확보
- Kafka 샌드위치 아키텍처 – MQTT와 DB 사이에 Kafka 배치, 초당 수천 건 요청 버퍼링 및 비동기 처리
- 바이너리 직렬화 – JSON 대신 Autosar DLT 표준 고밀도 바이너리 규격 도입
Result
정량적 성과
30%↓
데이터 전송 효율 개선
DLT 바이너리 패킹으로 페이로드 크기 절감
99.9%
시스템 가동률 달성
비동기 파이프라인으로 대규모 부하에서도 안정적 가용성 확보
Tech Stack & Highlights · 핵심 코드 로직
// binary.BigEndian — 버전 정보를 3바이트 정수로 압축 // 텍스트(JSON) 대비 페이로드 30% 절감 buf[offset+4] = byte(major) buf[offset+5] = byte(minor) buf[offset+6] = byte(patch) // Autosar DLT 표준 패킷 생성 binaryData, _ := protocol.CreateDltPacket( "ICU ", "INV ", buf, ) // 고루틴 비동기 전송 — 블로킹 없이 처리량 극대화 go transport.SendToBroker( v.Client, v.VIN, binaryData, )
TECHNICAL INTENT
Autosar DLT 바이너리 직렬화
버전 정보를 바이트 단위로 압축하여 텍스트 JSON 대비 페이로드를 30% 절감. go 키워드로 비동기 전송하여 에이전트 루프 블로킹을 방지한다.
- ▸ BigEndian 3바이트 압축 — 메모리·전송 효율 최적화
- ▸ Goroutine 비동기 전송 — 1,000 에이전트 동시 처리
- ▸ 전송 효율 30% 개선 달성
// io.Copy 스트리밍 해시 — 대용량 파일도 메모리 효율적 처리 hash := sha256.New() if _, err := io.Copy(hash, file); err != nil { return false, err } // 실제 해시 계산값 → 16진수 문자열 변환 actualHash := hex.EncodeToString( hash.Sum(nil), ) // 서버 제공 Hash와 대조 → 위변조 감지 return actualHash == expectedHash, nil
TECHNICAL INTENT
ISO 21434 준수 무결성 검증
io.Copy 스트리밍 방식으로 파일 전체를 메모리에 올리지 않고 해시를 계산하여 대용량 펌웨어도 리소스 낭비 없이 처리한다.
- ▸ 스트리밍 해시 — 파일 크기에 무관한 O(1) 메모리 사용
- ▸ SHA-256 — 위변조 감지, ISO 21434 보안 요구사항 충족
- ▸ 서버 Hash 대조 → 불일치 시 즉시 배포 차단
// DB에서 조회한 이전 안정 버전 경로 사용 cmdPayload := map[string]string{ "file_path": rollbackFilePath, "expected_hash": rollbackHash, } // JSON 직렬화 → MQTT 발행 data, _ := json.Marshal(cmdPayload) // QoS 1 — 최소 1회 전달 보장 (Anti-Bricking 신뢰성) s.MQTTClient.Publish( topic, 1, // QoS Level 1 false, // retain data, )
TECHNICAL INTENT
트랜잭션 기반 자동 복구
검증 실패 시 HANA DB에서 조회한 이전 안정 버전 경로를 즉시 ECU로 전송한다. MQTT QoS 1로 롤백 명령 전달을 보장하여 브리킹 상태를 원천 차단한다.
- ▸ HANA DB 조회 롤백 경로 — 검증된 이전 버전 즉시 복구
- ▸ MQTT QoS 1 — 최소 1회 전달 보장, 명령 유실 방지
- ▸ ISO 24089 롤백 트리거와 연동 — 3등급 Fault 자동 대응
Project
Dol-AI
실시간 AI 스마트 회의 어시스턴스
Java · Spring Boot · Node.js(Mediasoup SFU) · Python(Whisper AI) · Nginx · Docker
KEY RESULTS
기간
2025.03 – 05
3개월 · 캡스톤
팀 구성
총 4인
프론트 2 · 백엔드 2
본인 기여도
35%
백엔드 담당
유형
캡스톤 디자인
실서비스 배포
01 프로젝트 목적
▲ PROBLEM – 해결해야 할 문제
하루 평균 회의 3시간 이상이지만 실제 회의 활용률은 30% 미만. 회의록 수동 작성, 핵심 내용 누락, 언어 장벽으로 인한 글로벌 협업 제한이 핵심 문제다.
✓ SOLUTION – 구현 방향
각 회의마다 독립적인 Graph RAG를 실시간으로 동적 생성하여, 회의 시작 → 발화 인식 → 그래프 구축 → 맥락 보존 → 자동 산출물 파이프라인을 완전 자동화한다.
Whisper 실시간 자막 + Azure 번역 + ArangoDB GraphDB + Gemini LLM 기반 RAG를 결합하여, 회의의 기록·이해·실행을 모두 자동화하는 AI 스마트 회의 어시스턴트. 한·중·영 다국어를 동시 지원하며 회의 종료 즉시 DOCX·PNG 회의록을 자동 생성한다.
02 문제 정의 — AS-IS → TO-BE
AS-IS → TO-BE
회의 중 핵심 내용 기록 어려움
실시간 자막 및 자동 요약
음성 → 텍스트 실시간 변환하여 핵심 내용 빠짐없이 기록
AS-IS → TO-BE
회의록 수동 작성 — 시간 낭비 & 누락
다국어 회의록 자동 생성 및 저장
한·중·영 회의록 DOCX·PNG 자동 생성
AS-IS → TO-BE
회의 흐름 파악 어려움
발언 기반 그래프 시각화
실시간 GraphDB 연동 — LLM 기반 Graph·RAG로 동적 질의응답
AS-IS → TO-BE
언어 장벽으로 글로벌 협업 제한
실시간 다국어 자막 & 협업 확대
Whisper + Azure Translator 실시간 번역으로 글로벌 협업 지원
03 인력 구성 및 기여도
| 구성원 | 포지션 | 담당 영역 | 기여도 |
|---|---|---|---|
| 본인 [본인] | Backend | Spring Boot API 서버, GraphRAG 파이프라인, ArangoDB 실시간 그래프 설계, 회의록 자동 생성 | 35% |
| 팀원 (백엔드) | Backend | FastAPI LLM 연동, Whisper STT 서버, MySQL 스키마 설계 | 15% |
| 팀원 2인 (프론트) | Frontend | React/Vite UI, tldraw 화이트보드, Electron 앱, 실시간 그래프 시각화 | 50% |
04 주요 업무 및 상세 역할
SPRING BOOT API 서버
- › 회의 세션 생성·관리 REST API 설계
- › Redis 기반 실시간 세션 상태 관리
- › MySQL 회의 데이터 영속성 처리
- › Nginx 리버스 프록시 + AWS EC2 배포
GRAPHRAG 파이프라인
- › ArangoDB 실시간 노드·엣지 동적 구성
- › 발화 데이터 → 그래프 변환 로직 설계
- › Gemini LLM 기반 그래프 질의응답(RAG)
- › 회의별 독립 그래프 생성·격리
회의록 자동 생성
- › STT 로그 → DOCX·PNG 자동 변환 파이프라인
- › 한·중·영 다국어 회의록 동시 생성
- › AWS S3 파일 저장 및 다운로드 API
- › 투두 리스트 자동 추출 및 저장
인프라 & 통합
- › Docker Compose 멀티 서버 오케스트레이션
- › Mediasoup SFU ↔ Spring Boot 연동
- › Whisper STT 서버 비동기 연동
- › AWS EC2 + S3 + Redis 클라우드 구성
ARCHITECTURE
Dol-Ai — 시스템 아키텍처
WebRTC SFU · STT Pipeline · GraphRAG 실시간 처리
Mediasoup SFU · OpenAI Whisper · ArangoDB · Spring Boot · FastAPI · AWS
SYSTEM ARCHITECTURE · DolAi
FRONTEND
UI Layer
React · Vite · TypeScript · Recharts · tldraw · Electron
Interaction
Axios · react-rnd
BACKEND (CLOUD · AWS EC2)
STT & Translate
OpenAI Whisper · Azure Translator
SFU Server
Mediasoup · TURN Server
API Server
Spring Boot · FastAPI (LLM)
Infra Layer
Docker · Nginx · Redis · MySQL · S3
GraphRAG – 관계 기반 Retrieval + LLM 응답
ArangoDB (GraphDB) ↔ Gemini LLM · 실시간 노드/엣지 동적 구성
REAL-TIME DATA PIPELINE
Audio
Mediasoup SFU
Whisper
STT 변환
Azure
다국어 번역
ArangoDB
그래프 구축
Gemini
RAG 질의응답
회의록
DOCX·PNG 생성
WebRTC SFU 서버
Mediasoup- › Mediasoup SFU — 다자간 화상회의 오디오·비디오 중계
- › TURN Server로 NAT 환경 P2P 연결 보장
- › 실시간 오디오 스트림을 Whisper STT 서버로 전달
STT & 번역 파이프라인
Whisper · Azure- › OpenAI Whisper — 실시간 음성 → 텍스트 변환
- › Azure Translator — 한·중·영 실시간 다국어 번역
- › STT 로그를 MySQL에 저장하여 회의록 생성에 활용
GraphRAG 엔진
ArangoDB · Gemini- › ArangoDB — 발화 데이터를 실시간 노드·엣지로 구성
- › 회의마다 독립적인 그래프 생성, 맥락 격리
- › Gemini LLM + 그래프 Retrieval로 동적 질의응답
3-Lang
한·중·영
동시 번역·자막
Real-time
Graph RAG
동적 생성
DOCX+PNG
회의록
자동 생성
5-Server
Spring Boot · FastAPI
Mediasoup · WhisperRc · Nginx
06 주요 기술 스택
07 핵심 성과 – Problem · Action · Result
Problem
기술적 도전
- › 하루 3시간+ 회의에서 실제 활용률 30% 미만 – 회의 가치 손실
- › 실시간 다자간 오디오 스트림에서 STT·번역·그래프 구축을 동시 처리하는 레이턴시 문제
- › 회의마다 맥락이 달라 범용 RAG 적용 불가 – 회의별 독립 지식 그래프 필요
Action
해결 방법
- › 비동기 파이프라인 – Mediasoup 오디오 스트림을 Whisper 서버로 분기, STT·번역·그래프 구축 병렬 처리
- › 회의별 독립 GraphRAG – 회의 시작 시 ArangoDB에 신규 그래프 생성, 종료 시 Gemini로 요약·질의응답
- › DOCX·PNG 자동 생성 – STT 로그 기반 다국어 회의록 자동 렌더링 및 S3 저장
Result
정량적 성과
3-Lang
한·중·영 실시간 자막
다국어 동시 번역 지원
40분+
무중단 서비스 안정화
동시 접속 5인 기준, Reconnect Storm 해결
80%↑
초기 로딩 체감 속도 개선
그래프 비동기 분리 + Lazy 렌더링
Tech Stack & Highlights · 핵심 코드 로직
// 발화 텍스트 → ArangoDB 그래프 노드 실시간 저장 public void addSpeechNode(String meetingId, SpeechDto speech) { // 발화자·키워드를 노드로 생성 Map<String, Object> node = Map.of( "_key", speech.getId(), "speaker", speech.getSpeaker(), "text", speech.getText(), "ts", Instant.now().toEpochMilli() ); arangoDb.collection(meetingId + "_nodes") .insertDocument(node); // 이전 발화와 엣지(관계) 연결 if (prevNodeKey != null) { Map<String, Object> edge = Map.of( "_from", meetingId + "_nodes/" + prevNodeKey, "_to", meetingId + "_nodes/" + speech.getId(), "rel", "FOLLOWS" ); arangoDb.collection(meetingId + "_edges") .insertDocument(edge); } }
TECHNICAL INTENT
회의별 독립 GraphRAG
발화가 들어올 때마다 ArangoDB에 실시간으로 노드와 엣지를 추가하여 회의 맥락을 그래프로 누적한다. meetingId를 컬렉션 키로 사용해 회의별 그래프를 완전히 격리한다.
- ▸ 발화 순서 엣지 — 대화 흐름 맥락 보존
- ▸ 회의 ID별 컬렉션 격리 — 데이터 충돌 방지
- ▸ Gemini RAG에 그래프 컨텍스트 전달
// Whisper STT 결과 수신 후 비동기 처리 @Async public CompletableFuture<Void> processSttResult( SttResult stt ) { return CompletableFuture // 1. Azure 다국어 번역 .supplyAsync(() → translationService.translateAll( stt.getText(), "ko", "en", "zh" ) ) // 2. 번역 결과 → 그래프 노드 추가 .thenAcceptAsync(translations → { graphService.addSpeechNode( stt.getMeetingId(), new SpeechDto(stt, translations) ); }) // 3. MySQL STT 로그 저장 .thenRunAsync(() → sttLogRepo.save(new SttLog(stt)) ); }
TECHNICAL INTENT
Non-blocking 파이프라인
@Async + CompletableFuture로 STT → 번역 → 그래프 → DB 저장을 논블로킹 체이닝. 각 단계가 완료되는 순서대로 처리되어 메인 스레드 블로킹 없이 실시간 처리를 보장한다.
- ▸ CompletableFuture 체이닝 — 순차 처리를 비동기로
- ▸ 번역·그래프·DB 저장 3단계 병렬 처리
- ▸ 실시간 자막 레이턴시 최소화
// 회의 종료 시 다국어 회의록 자동 생성 public ReportResult generateReport(String meetingId) { // 1. STT 로그 전체 조회 List<SttLog> logs = sttLogRepo .findByMeetingIdOrderByCreatedAt(meetingId); // 2. Gemini로 요약 및 투두 추출 String summary = geminiService.summarize(logs); List<String> todos = geminiService.extractTodos(logs); // 3. 한·중·영 DOCX 생성 for (String lang : List.of("ko", "en", "zh")) { byte[] docx = docxRenderer.render(logs, summary, lang); String url = s3Service.upload( "reports/" + meetingId + "_" + lang + ".docx", docx ); reportRepo.saveUrl(meetingId, lang, url); } return new ReportResult(summary, todos); }
Project
Watt-Up
CQRS 아키텍처와 Kubernetes 기반의 전기차(EV) 충전 예약 플랫폼
공공데이터 API 기반 충전소 조회 및 예약 서비스
KEY RESULTS
기간
2026.02 – 03
2주 스프린트
팀 구성
총 6인
BE 2 · FE 2 · Infra 2
본인 담당
DB · CDC · Infra
CQRS · Kafka · Jenkins
유형
팀 프로젝트
온프레미스
01 프로젝트 목적
▲ 배경 – 해결해야 할 문제
전기차 보급 급증에 따라 충전소 정보가 파편화되어 사용자의 정보 접근성과 신뢰도가 저하되는 문제 발생. 단일 서비스에서 실시간 현황 확인과 예약이 불가능한 상황.
✓ 목적 – 구현 방향
공공데이터 API를 활용하여 실시간 충전소 현황을 확인하고, 즉시 예약 가능한 신뢰성 높은 통합 서비스를 구축한다. CQRS 패턴과 CDC 파이프라인으로 읽기·쓰기 성능을 분리 최적화한다.
공공데이터 기반 전기차 충전소 정보를 PostgreSQL(PostGIS)에 적재하고, Debezium CDC → Kafka 3-Node → MongoDB로 이어지는 실시간 동기화 파이프라인을 구축한다. CQRS 패턴으로 쓰기(PostgreSQL)와 읽기(MongoDB)를 분리하여 대용량 조회 성능을 최적화하며, Kubernetes 4-Node 클러스터와 Jenkins DooD CI로 온프레미스 인프라를 완성한다.
02 주요 기능
01 · 지역 기반 탐색
지역구 선택 → 지도 자동 이동
드롭다운으로 지역구를 선택하면 지도가 자동 이동하며 해당 구역 내 충전소 위치를 클러스터 마커로 즉시 표시, 직관적인 탐색 지원
02 · 스마트 클러스터링
줌 레벨 기반 동적 그룹화
지도 줌 레벨 변화에 따라 충전소 그룹을 동적으로 병합·분리하며 그룹 내 충전소 수 및 개별 충전기 수를 시각화
03 · 실시간 정보 모달
마커 클릭 → 상세 슬라이드 오픈
충전기 상세 스펙, 현장 이미지, 현재 예약 가능 시간표를 실시간으로 제공
04 · 간편 예약 시스템
전화번호 입력만으로 예약 완료
복잡한 회원가입 없이, 예약자 전화번호 입력만으로 빈 시간대 충전기를 즉시 점유하고 예약을 확정하는 간편 시스템
03 인력 구성 및 기여도
| 구성원 | 포지션 | 담당 영역 | 기여도 |
|---|---|---|---|
| 본인 포함 (DB 2인) [본인] | DB·CDC·Infra | CQRS 패턴 설계, PostgreSQL·MongoDB 구축, Debezium CDC 파이프라인, Kafka KRaft 클러스터, 온프레미스 인프라, Jenkins DooD CI | 30% |
| 팀원 (BE 2인) | Backend | FastAPI 비즈니스 로직, 예약 API, 공공데이터 Importer | 35% |
| 팀원 (FE 2인) | Frontend | React UI, Naver Maps API 연동, 클러스터링·예약 화면 | 25% |
04 주요 업무 및 상세 역할
CQRS 패턴 & 데이터베이스 설계
- › PostgreSQL(PostGIS) — 쓰기 전용 Primary DB 설계
- › MongoDB — 읽기 전용 Read DB 설계 및 구축
- › 지리 좌표 기반 PostGIS 쿼리 최적화
- › 충전소·예약 테이블 스키마 설계
CDC 파이프라인 구축
- › Debezium Custom 이미지 빌드 (MongoDB 라이브러리 포함)
- › Kafka KRaft 3-Node 클러스터 구축
- › PostgreSQL WAL → Kafka Topic → MongoDB Sync
- › 컬렉션별 Sink 커넥터 분리 생성
온프레미스 인프라 구축
- › VirtualBox 5-VM 환경 구성 (K8s 4-Node + DB VM)
- › Kubernetes Cluster — Master + Worker 3대
- › Nginx Gateway 단일 진입점 설계 (NodePort 30007)
- › Tailscale VPN 네트워크 보안 통제
CI/CD – JENKINS DOOD
- › DooD 방식 Jenkins 컨테이너 구성 (호스트 소켓 공유)
- › GitHub → Docker Hub 이미지 빌드·푸시 자동화
- › ArgoCD GitOps CD 파이프라인 연동
- › 메모리 리미트 설정으로 인프라 서비스 안정성 확보
ARCHITECTURE
WattUp — 시스템 아키텍처
K8s 클러스터 · CDC 파이프라인 · CQRS 패턴
Kubernetes 4-Node · Debezium CDC · Kafka Kraft 3-Node · PostgreSQL(PostGIS) · MongoDB
SYSTEM ARCHITECTURE · WattUp (5-VM On-Premise)
K8S 클러스터 (VIRTUALBOX 4-NODE)
Service – Nginx NodePort (30007)
단일 진입점 · Host:30007 → VIP포트포워딩 → NodePort
FE Service
React / Maps ClusterIP
BE Service
FastAPI ClusterIP
외부 DB VM (STATEFUL 분리)
Importer
공공데이터 초기 적재
PostgreSQL (PostGIS)
Write DB · WAL 기반 CDC
MongoDB
Read DB · 읽기 최적화
Debezium
CDC Engine · Custom Image
CDC PIPELINE – DEBEZIUM · KAFKA KRAFT 3-NODE
Importer
data init
PostgreSQL
WAL Ingest
Debezium
db-source
Kafka
Broker 0~2
K8S 4-NODE 구성
Master
Control Plane · API Server
Worker 1
Nginx Gateway
Worker 2
FastAPI ClusterIP
Worker 3
React FE ClusterIP
CQRS + CDC 패턴
Debezium · Kafka- › 쓰기 — FastAPI → PostgreSQL(PostGIS) 단방향
- › 읽기 — MongoDB 전용 최적화 컬렉션
- › PostgreSQL WAL 변경사항을 Debezium이 실시간 캡처 → Kafka → MongoDB 동기화
- › 컬렉션별 Sink 커넥터 분리로 데이터 격리
K8s 인프라 구성
4-Node · NodePort- › 총 5-VM — K8s 4대(Master+Worker 3) + DB 전용 VM 분리
- › Nginx NodePort(30007) 단일 진입점 — 프론트/백엔드 내부 ClusterIP만 허용
- › DB·Kafka 등 Stateful 리소스는 K8s 외부 VM에 배치하여 안정성 확보
- › Tailscale VPN 네트워크 보안 통제
Jenkins DooD CI/CD
DooD · ArgoCD- › DooD — 호스트 Docker 소켓 공유로 DinD 오버헤드 제거
- › GitHub Push → Jenkins 빌드 → Docker Hub 이미지 Push
- › ArgoCD GitOps — manifest 변경 감지 → K8s Pod 자동 교체
- › 메모리 리미트 2g로 DB 서비스 안정성 보장
5-VM
온프레미스
VirtualBox 구성
CQRS
읽기/쓰기
완전 분리
3-Node
Kafka Kraft
클러스터
CDC
Debezium
실시간 동기화
06 주요 기술 스택
07 핵심 성과 – Problem · Action · Result
Problem
기술적 도전
- › 읽기·쓰기 DB 미분리로 인한 조회 성능 병목 – 충전소 실시간 현황 조회 시 쓰기 부하 영향
- › 온프레미스 단일 서버에서 K8s·Kafka·DB를 동시 운영 시 메모리 고갈 및 OOM Kill 반복
- › Debezium 기본 이미지에 MongoDB 라이브러리 부재 – mongo-sink 커넥터 생성 불가
Action
해결 방법
- › CQRS + CDC – PostgreSQL 쓰기, MongoDB 읽기 분리. Debezium WAL 캡처 → Kafka → MongoDB 실시간 동기화처리
- › Stateful 리소스 VM 분리 – DB·Kafka를 K8s 외부 전용 VM에 배치. JVM Heap 제한(-Xmx512M)으로 OOM 방지
- › Custom Debezium 이미지 빌드 – Dockerfile로 MongoDB 커넥터 라이브러리 직접 포함
Result
정량적 성과
CQRS
읽기/쓰기 완전 분리
조회 부하가 Primary DB에 영향 주지 않는 구조 달성
무중단
CI/CD 파이프라인
DooD Jenkins + ArgoCD GitOps로 단일 노드 무중단 배포 완성
Tech Stack & Highlights · 트러블슈팅
01 Kafka KRaft — meta.properties 생성 실패로 브로커 무한 재시작
문제 상황
- › KAFKA_METADATA_LOG_DIR 와 KAFKA_LOG_DIRS 가 각각 /metadata, /data 로 분리 설정
- › 자동 포맷 스크립트가 metadata만 포맷 → /data 에 meta.properties 미생성
- › 브로커 Fatal Exception으로 컨테이너 무한 재시작
해결 방법
- › KAFKA_METADATA_LOG_DIR 설정 제거, KAFKA_LOG_DIRS 만 단일 경로로 통합
- › docker compose down -v 로 오염된 볼륨 삭제 후 Clean Start
- › KRaft 모드는 경로 분리 시 레이스 컨디션 발생 가능 — 단일 경로 관리 권장
결과 & 학습
- › 볼륨 초기화 후 Kafka 클러스터 정상 기동
- › 단순함의 가치 — 경로 분리는 성능 최적화 시에만, 그 외엔 단일화
- › KRaft는 실행 전 Storage 포맷이 필수임을 확인
02 Debezium JVM OOM Killer — 아무런 로그 없이 컨테이너 조용히 종료
문제 상황
- › 서버 잔여 메모리 5.8GB 여유에도 Debezium 컨테이너가 에러 없이 즉시 종료
- › 단일 DB 서버에 DB 2대·Kafka 3대 밀집 — JVM 기본 힙 과점유로 Linux OOM Killer 동작
해결 방법
- › Docker 메모리 하드 리미트 --memory="1g" 설정
- › JVM 환경변수 주입: JAVA_OPTS="-Xms512M -Xmx512M"
- › 불필요한 힙 확장 차단으로 예측 가능한 메모리 사용량 확보
결과 & 학습
- › 플러그인 스캐닝·초기화 안정 완료, 8083 포트 정상 서비스
- › OOM Killer는 에러 로그를 남기지 않음 — 조용한 종료 = 메모리 의심
03 Debezium Custom 이미지 빌드 — MongoDB 커넥터 라이브러리 부재
문제 상황
- › Debezium 기본 이미지에 MongoDB 관련 라이브러리 없음 → mongo-sink 커넥터 생성 불가
- › 단일 mongo-sink 커넥터로 다중 컬렉션 처리 시 데이터 격리 불가
- › bitnami Kafka 이미지 pull 실패 — 이미지 저장소 업데이트 중단
해결 방법
- › MongoDB 라이브러리를 포함하는 Custom Dockerfile 직접 작성·빌드
- › 컬렉션별 독립 Sink 커넥터 생성 (station·reservation 분리)
- › bitnami → apache/kafka:3.8.0 으로 이미지 교체
결과 & 학습
- › mongo-sink 커넥터 정상 등록, 컬렉션 분리 완료
- › 이미지 커스텀은 어렵지 않음 — Dockerfile로 라이브러리 추가
- › AI가 버전 수정을 제안해도 직접 Docker Hub에서 이미지 존재 여부 확인 필요
04 Jenkins DooD CI — 호스트 리소스 독식 방지 및 Docker 권한 문제
문제 상황
- › Jenkins가 빌드 중 호스트 리소스를 독식 → DB 서비스 다운 위험
- › Jenkins 컨테이너 내부에서 docker build 권한 없음
해결 방법
- › DooD(Docker out of Docker) — 호스트 소켓 공유 방식 채택
- › -v /var/run/docker.sock:/var/run/docker.sock 마운트
- › Jenkins 컨테이너 --memory="2g" 하드 리미트 설정
결과 & 학습
- › GitHub → Docker Hub 이미지 빌드·푸시 자동화 완성
- › DB·Kafka 서비스 무중단 유지
- › DinD vs DooD — 단일 서버에선 DooD가 오버헤드 없이 유리
# 공식 Debezium Connect 이미지를 베이스로 FROM debezium/connect:2.5 # MongoDB 커넥터 플러그인 다운로드 및 설치 USER root RUN curl -fsSL \ https://repo1.maven.org/maven2/io/debezium/debezium-connector-mongodb/2.5.0.Final/debezium-connector-mongodb-2.5.0.Final-plugin.tar... \ | tar -xzf - -C /kafka/connect/ # kafka-connect-mongodb (MongoDB Sink) 추가 RUN curl -fsSL \ https://packages.confluent.io/maven/io/confluent/kafka-connect-mongodb/1.11.2/kafka-connect-mongodb-1.11.2.jar \ -o /kafka/connect/mongodb/kafka-connect-mongodb.jar USER 1001 # 컬렉션별 Sink 커넥터 REST API 등록 예시 # POST /connectors → station용 커넥터 / reservation용 커넥터 각각 생성 # "topics": "ev_server.public.ev_station" → ev_station 컬렉션 # "topics": "ev_server.public.ev_reservation" → ev_reservation 컬렉션
Project
스쿨버스 앱 서버 유지보수
9,000+ 실사용자 대상 교내 스쿨버스 GPS 위치 추적 서버
교내 셔틀버스 및 마을버스의 실시간 GPS 위치를 2초 주기로 수집하여 REST API로 모바일 앱에 제공
KEY RESULTS
기간
2024.06 – 12
6개월
팀 구성
IT보조 6인
서버 유지보수 2인
본인 기여도
50%
서버 유지보수 담당
실사용자
9,000+
교내 학생·교직원
핵심 성과 – Problem · Action · Result
Problem
공공데이터 API의 1.5초 polling으로 일일 호출 제한 초과 → 하굣길 약 6시간 동안 버스 위치 미표시
Action
polling 주기 1.5초 → 2초로 조정. 기사님과 협의하여 주요 우회 구간 파악 → 해당 좌표를 노선 데이터에 추가 반영
Result
일일 API 호출량 약 30% 감소, 위치 매칭 실패율 약 87% 감소
Problem
2초 주기 GPS 수집 × 3개 노선 × 운행 시간 → 일일 약 5만 건 이상 누적 → SELECT 쿼리 응답 시간 증가
Action
Timer 기반 스케줄러로 매일 자정 GPS 테이블 자동 초기화 (TRUNCATE bus_gps)
Result
DB 용량 관리 자동화, API 응답 속도 200ms 이하 유지
Problem
버스 운행 종료 후에도 마지막 GPS 좌표가 DB에 남아 있어 앱에서 운행 중으로 오인 표시
Action
운행 종료 상태를 stationId = 999로 정의 → API에서 999인 경우 위치 정보 null 반환 처리
Result
사용자 혼란 방지 및 운행 종료 오표시 98% 해소
팀에 기여할 준비가 되어 있습니다
분산 시스템과 데이터 파이프라인 설계 경험을 바탕으로,
팀과 함께 성장하는 엔지니어가 되겠습니다.
(+82)10-8225-7963