SUMMARY

경력과 프로젝트의 핵심만 한 페이지에 모았습니다.

선박에서 수집되는 센서 데이터를 외부 서버로 실시간 전송하는 데이터 연동 시스템

온습도 센서화재 센서도어 센서API Server센서 데이터 수신 핸들러MQTT 전송 스레드풀MQTT PublisherMQTT Broker외부 서버
문제
애플리케이션 네 개와 MySQL, Redis가 8코어 단일 서버를 공유하는 폐쇄망 환경
MQTT 전송에 @Async만 붙여 사내 공통 스레드풀(pool-size="100", queue-capacity 미설정)을 그대로 사용
400 req/s 부하가 이어지자 스레드가 100개까지 늘면서 CPU 사용률 95%까지 상승
해결
공통 풀은 그대로 두고 MQTT 전송 전용 스레드풀만 분리 (Core 8, Max 16, Queue 200)
평상시 8개로 처리하고 순간적인 부하나 전송 지연이 겹칠 때만 16개까지 확장
결과
Locust로 재현한 400 req/s 부하에서 CPU 사용률 95% → 60%로 감소

선박의 위치와 방향 정보, 화재 센서 데이터를 실시간으로 수신하고 처리하는 시스템

선박 위치선박 방향화재 센서Ethernet ConverterSerial -> TCPNetty비동기 I/O 처리센서 메시지 분리BufferBatch InsertMySQL
문제
피크 시 운항 데이터와 화재 센서 데이터 초당 약 600건을 기존 트래픽과 함께 처리
IOPS가 낮은 HDD 환경에서 단건 Insert로 인해 서버 평균 I/O wait 18%까지 상승
해결
실시간 전달 경로는 그대로 두고 로그 저장 경로만 ConcurrentLinkedQueue로 분리
600건이 모이거나 1초가 지나면 Batch Insert로 묶어 저장
결과
TCP 시뮬레이터로 재현한 600 messages/s 부하에서 I/O wait 18% → 약 3%로 감소

종료 조건을 확인해 국면 전환을 자동 종료하는 스케줄러

인스턴스 A스케줄러 실행 중인스턴스 B스케줄러 실행 중인스턴스 C스케줄러 실행 중인스턴스 D스케줄러 실행 중Redis 분산 락단일 실행락 획득 인스턴스종료 로직 수행
문제
운영 중 국면 전환이 자동 종료되지 않고, WebSocket 종료 상태 알림에 Y와 N이 동시에 도착
서버 4대가 10초마다 종료 스케줄러를 동시에 실행하면서 발생한 Race Condition
해결
Redis 분산 락으로 스케줄러 중복 실행을 막고, 서버 4대 중 한 대만 종료 로직 수행
커스텀 어노테이션과 AOP로 락 획득과 해제를 모듈화해 신규 스케줄러에도 같은 정책 적용
결과
운영 환경에서 종료 로직 진입 1회, 종료 알림 1건 확인

승인권자가 모바일 앱에서 승인하거나 반려하는 전자 결재 시스템

Before - Lost Update 상황Approver AMySQLApprover BSELECT 상태 조회status: 대기SELECT 상태 조회status: 대기UPDATE 반려UPDATE 승인Lost Update마지막 요청이 덮어씀After - 조건부 UPDATE 적용Approver AMySQLApprover BUPDATE WHERE 상태=대기record lockaffected rows: 1UPDATE WHERE 상태=대기affected rows: 0충돌 예외 처리중복 처리 차단Lost Update 방지
문제
여러 승인권자가 같은 결재를 동시에 처리하면 SELECT와 UPDATE 사이에 상태가 바뀜
두 요청이 모두 승인 대기를 읽으면서 승인이 반려를 덮어쓰는 Lost Update 발생
해결
비관적 락과 낙관적 락 대신 상태 조건을 넣은 단일 UPDATE 사용
조건에 맞는 인덱스 레코드에 record lock이 걸려 동시 요청이 직렬화되고, affected rows가 0이면 이미 처리된 결재로 판단
결과
동시에 들어온 승인과 반려 중 1건만 성공하고 나머지는 차단

Context와 Skill 기반 AI Agent 업무 자동화

Context와 Skill로 일감 생성부터 운영 배포까지 반복 업무를 자동화

개발자요청AI AgentClaude Code, CodexContextAGENTS.md목차필요할 때docs/구조, 도메인, 운영먼저 읽음값 전달요약 결과SkillSKILL.md절차스크립트실행API 호출업무 도구RedminePostmanJenkinsS3메일
문제
AI로 구현은 빨라졌지만 세션마다 프로젝트 맥락을 다시 설명해야 함
Redmine, Postman, Jenkins, S3, 메일 등 도구 7개를 오가며 같은 정보를 반복 입력
해결
AGENTS.md는 목차로 두고 도메인 지식은 하위 문서로 나눠 필요할 때만 읽도록 구성
반복 업무를 Skill로 만들고 실행은 Python 스크립트에 맡겨 모델은 요청에 맞는 값을 넘긴 뒤 요약된 결과만 읽음
결과
일감 생성부터 운영 배포까지 7단계 업무를 Skill 4번 호출로 단축하고 사내 기술 발표에서 전사에 공유

삼성전자 vs SK하이닉스, 시가총액 1위 경쟁을 보여주는 대시보드

LIVE SITE ↗
systemd timer60초마다 GHCR image 확인새 버전 컨테이너 기동Readiness 확인통과해야 전환Nginx upstream 변경기존 SSE기존 버전에서 처리310초 뒤 종료신규 요청새 버전에서 처리2초마다 상태 확인연속 3회 실패안전 장치기존 버전으로 롤백
문제
배포 때 컨테이너를 바로 교체하면 시세를 전달하던 SSE 연결이 끊기며 시세 공백 발생
blue-green 적용 후 SSE 400개를 유지한 채 배포하자 두 JVM이 겹쳐 서버의 메모리가 바닥나고 61분간 응답하지 못함
해결
blue-green 배포로 새 버전을 다른 포트에 먼저 띄워 Readiness 통과 후 전환하고 기존 SSE 연결은 310초 동안 유지
JVM 메모리를 275MiB에서 226MiB로 줄여 두 JVM이 겹쳐도 메모리 여유 확보
가용 메모리가 64MiB 아래로 떨어지면 기존 버전을 먼저 내리는 메모리 가드로 서버 멈춤 대신 SSE 재연결 선택
결과
배포 중에도 기존 시세 연결 유지
같은 부하에서 서버가 멈추지 않고 배포 완료 (Health Check 실패 153회 → 0회)

다양한 주제로 자유롭게 의견을 나누는 커뮤니티 서비스

운영자공지 등록Push APIMySQLpush_broadcast발송 접수push_delivery발송 단위발송 단위 생성Dispatcher발송 토픽push-sendConsumer선점 UPDATE외부 푸시 업체5xx, 타임아웃재시도 토픽push-send-retry4xx, 재시도 소진실패 격리 토픽push-send-dlt
문제
운영자가 공지를 등록하면 요청 스레드가 기기 1만 대에 외부 푸시 업체 API를 순서대로 호출해 발송에 약 5분 16초 소요
게이트웨이 타임아웃 60초 뒤 운영자가 재요청하면 같은 공지를 처음부터 다시 보내 9,246건 중복 발송
일시적인 503도 다시 보내지 않아 1만 대 중 207대는 공지를 받지 못함
해결
발송 요청은 DB에 접수한 뒤 바로 응답하고 기기 단위 메시지로 나눠 Kafka Consumer 6개가 병렬 발송
Idempotency-Key로 같은 요청은 한 번만 접수하고 공지와 기기 한 쌍인 발송 단위는 조건부 UPDATE로 선점해 중복 발송 차단
5xx와 타임아웃은 재시도 토픽에서 재발송, 4xx 응답을 받았거나 재시도를 모두 쓴 메시지는 DLT에 격리
결과
발송 요청 응답은 60초 타임아웃 → 107ms, 중복 수신 9,246건 → 4건으로 감소