허진혁

Software Engineer

Email: gjwlsgur4866@gmail.com

Phone: 010-4140-4866

Blog: https://velog.io/@wlsgur1533

Portfolio: /portfolio/

About Me

동시 요청에서도 데이터 규칙을 지키고, 외부 호출 실패를 복구할 수 있는 구조를 고민하는 백엔드 개발자입니다. MySQL·Redis를 활용한 발급 동시성 제어와, 실시간 집계 구조 전환으로 인기순 조회를 4.6초에서 145ms로 개선한 경험이 있습니다. 또한, 효과적인 의사소통을 중시하여 좋은 질문하는 문화를 조성하는 것을 좋아하며, Notion 및 WBS 활용해 일정 공유와 기록을 통해 팀의 협업을 강화한 경험이 있습니다.

Project

개발 한 스푼

개발 2024.03 ~ 2024.06
운영 2024.01 ~ 2025.01

문답 기반으로 CS 학습을 돕는 모바일 애플리케이션

팀 프로젝트 · 백엔드 기여 30% · Kotlin, Spring Boot, MySQL

사용자별 일일 질문 중복 발급 방지

  • 문제 · 동일 사용자의 동시 요청으로 하루 1회 질문 발급 정책이 깨질 수 있었습니다.
  • 판단 · 질문 발급 여부를 판단하는 전체 과정을 사용자 단위로 보호해야 한다고 보았습니다.
  • 해결/결과 · MySQL Named Lock과 Spring AOP로 동시 발급을 제어해, 3개 동시 요청이 동일한 질문 ID를 반환함을 확인했습니다.

신고 알림의 실패 추적 및 재처리를 위해 Transactional Outbox를 도입하여 알림 누락 문제 개선

  • 문제 · 신고 저장 후 비동기 이벤트로 Slack 알림을 전송했으나, 실패 시 기록이 남지 않아 원인 추적과 재처리가 어려웠습니다. 가설을 나눠 검증한 결과 Slack의 HTTP 오류 응답(4xx·5xx)을 검사하지 않아 실패를 감지하지 못했고, 전송 작업이 메모리에만 존재해 서버 재시작 시 미완료 작업을 복구할 수 없었습니다.
  • 판단 · 단순 재시도로는 작업 유실을 막기 어렵다고 보고, 신고 데이터와 알림 작업을 같은 트랜잭션에 저장하는 Transactional Outbox를 택했습니다.
  • 해결/결과 · MockWebServer로 HTTP 500·404를 재현해 오류 감지 누락을 확인하고 응답 상태에 따라 재시도 가능 여부를 분류했습니다. AOP 실행 순서를 조정해 신고와 알림 작업을 동일 트랜잭션에 저장하고, 스케줄러 재처리(1·5·15분 간격, 최초 전송 포함 최대 4회, 429는 Retry-After 반영)를 구현했습니다. 조건부 UPDATE와 행 잠금으로 다중 인스턴스의 중복 선점을 방지하고 전송 상태·시도 횟수·HTTP 상태·실패 사유를 기록했습니다. 단위·HTTP·통합 테스트 22개와 8개 스레드 동시 처리 시 단일 발송 검증을 통과했습니다.

Givemeticon

2023.09 ~ 2024.01

사용하지 않거나 만료가 임박한 기프티콘을 사고파는 중고거래 플랫폼

Java 17, Spring Boot, MyBatis, MySQL, Redis, Redisson · 쿠폰 발급 재설계: Java 21, Spring Boot 3.3, MySQL 8.0, Redis 7, RabbitMQ 3, k6, Testcontainers

선착순 쿠폰의 초과 발급과 DB 장애 시 신청 유실을 막기 위해, RabbitMQ 접수 + MySQL 단일 판정 구조로 재설계

  • 문제 · 재고 100개에 동시 요청 1,000건이 들어오자 낡은 재고 값으로 발급을 판단해 매회 7건 초과 발급됐습니다(10회 중 10회). 비관적 락으로 정합성은 확보했으나 처리량이 약 650rps에서 정체했고, 판정을 Redis로 옮긴 뒤에도 DB 기록이 응답 경로에 남아 DB 약 48초 중단 실험에서 54초간 성공 응답이 0, 당첨 기록 200건이 유실됐습니다.
  • 판단 · 행 잠금·커넥션 풀·fsync를 하나씩 바꿔 측정해 재고 행을 4개로 나누면 800rps의 p50이 3,362ms에서 2.4ms가 되는 것을 확인하고, 단일 행 잠금을 병목으로 특정해 판정을 Redis Lua 원자 카운터로 옮겼습니다. 이어 Outbox·Redis Streams·Kafka·RabbitMQ를 비교해 브로커 저장 확인 후 응답하는 RabbitMQ를 택했고, 판정(Redis)과 기록(MySQL)이 나뉘는 불일치 위험을 없애려 Redis를 제거했습니다.
  • 해결/결과 · RabbitMQ로 접수한 뒤 MySQL 트랜잭션 하나에서 중복 확인·재고 차감·결과 기록을 처리합니다(UNIQUE 제약, 커밋 후 ACK). 초과 발급이 7건에서 0건이 됐고 정합성 테스트 40회를 모두 통과했습니다. 응답이 밀리지 않는 최대 부하는 400에서 1,600rps(Redis 판정 도입 시점)가 됐고, DB 약 48초 중단 중에도 신청 31,001건이 전부 접수돼 복구 후 유실이 0이었습니다. 커밋 후 ACK 전 강제 종료에서 재전달 620건 중 중복 저장은 0건이었습니다. 대가로 800rps에서 결과 확정까지 중앙값 42~53초가 걸리는 것을 측정했습니다.

인기순 조회 성능 개선

  • 문제 · 좋아요 100만 건을 실시간 집계하는 인기순 Top 20 조회가 4.6초까지 느려졌습니다.
  • 판단 · 인덱스 추가 후에도 남는 반복 집계 비용을 줄이려면, 집계값을 관리하는 구조를 바꿔야 한다고 보았습니다.
  • 해결/결과 · 사전 집계 메타 테이블과 MySQL 커버링 인덱스로 조회 비용을 줄여, 상품 10만 개 기준 4.6초 → 145ms로 약 96% 개선했습니다.

Certifications

SQLD

취득

정보처리기사

취득

Education

f-lab

2023.07 ~ 2024.01

깊이있게 학습하는 방법을 익혀 사수가 없어도 혼자 성장할 수 있는 개발자로 성장할 수 있도록 멘토링을 진행하여, 자바의 기본 개념들을 학습한 후 프로젝트를 통해 설계, 구현, 문서화를 포함한 전체적인 과정에 참여하여 문제 해결 능력과 소프트 스킬을 배웠습니다.

멋쟁이 사자처럼 백엔드

2022.09 ~ 2023.02

Java/Spring을 배우고 프로젝트에 적용하는 부트캠프로 회고 문화와 효울적인 스터디 진행하는 방법을 배웠습니다. 또한, 프로젝트를 진행할 떄 구현 뿐 아니라 프로젝트 일정 관리, 협업 방식, API 설계 등을 배웠습니다.