SUMMARY

경력과 프로젝트의 핵심만 한 페이지에 모았습니다. 각 항목의 READ MORE에서 상세 내용을 볼 수 있습니다.

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

온습도 센서화재 센서도어 센서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)
큐는 운영 유입량의 약 0.5초분만 대기시키고 큐와 최대 스레드가 모두 차면 호출 스레드가 직접 처리
결과
400 req/s 부하에서 CPU 사용률 95% → 60%로 감소

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

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

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

인스턴스 A스케줄러 실행 중인스턴스 B스케줄러 실행 중인스턴스 C스케줄러 실행 중인스턴스 D스케줄러 실행 중Redis 분산 락단일 실행락 획득 인스턴스종료 로직 수행
문제
운영 중 국면 전환이 자동 종료되지 않고 종료 알림에 Y와 N이 동시에 도착
서버 4대가 10초마다 종료 스케줄러를 동시에 실행하면서 발생한 Race Condition
해결
이미 운영 중인 Redis로 분산 락을 걸어 한 대만 종료 로직을 수행하고 락은 TTL 10초로 자동 만료
커스텀 어노테이션과 AOP로 락 획득과 해제를 모듈화해 신규 스케줄러에도 같은 정책 적용
결과
스케줄러 4회 실행에서 종료 로직 진입 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건만 성공하고 나머지는 차단

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

LIVE SITE ↗
systemd timer60초마다 GHCR image 확인새 버전 컨테이너 기동Readiness 확인통과해야 전환Nginx upstream 변경기존 SSE기존 버전에서 처리310초 뒤 종료신규 요청새 버전에서 처리2초마다 상태 확인연속 3회 실패안전 장치기존 버전으로 롤백
문제
코드를 변경할 때마다 테스트와 빌드, 이미지 생성을 직접 확인
GitHub Actions에서 EC2로 SSH 배포하려 했지만 러너 IP가 매번 달라 실패, 22번 포트를 전체 공개하면 공격에 노출
Watchtower 도입 후에도 컨테이너가 즉시 교체되면서 시세를 전달하던 SSE 연결이 끊김
해결
GitHub Actions로 테스트와 빌드, GHCR 이미지 저장까지 자동화
배포 방향을 push에서 pull로 바꿔 EC2의 Watchtower가 새 이미지를 받아 교체
새 버전을 다른 포트에 먼저 띄워 Readiness 통과 후 전환하고 기존 SSE 연결은 310초 뒤 종료
결과
22번 포트를 열지 않고 배포하면서 기존 시세 연결도 유지

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

정상 갱신 - Token RotationToken R0ACTIVEAuth ServiceToken 갱신갱신Token R0ROTATEDToken R1ACTIVE이전 Token 재사용 - Family RevokeToken R0ROTATEDAuth Service재사용 감지다시 제출Token R0REVOKEDToken R1REVOKED
문제
로그아웃할 때 쿠키만 지우면 미리 복사된 Refresh Token은 서버에서 계속 유효
공격자가 로그아웃 이후에도 탈취한 Token으로 Access Token을 재발급
해결
갱신할 때마다 이전 Token을 ROTATED로 바꾸는 Refresh Token Rotation 적용
같은 로그인에서 이어진 Token을 family_id로 묶고 ROTATED Token이 들어오면 재사용으로 보고 Family 전체 폐기
결과
로그아웃 이후 탈취된 Token의 재사용 차단