미리보기
기본 정보
빠른 시도로 문제를 해결하는 것과 불필요한 부분을 개선하는 것을 좋아합니다. 커피와 함께 개발하는 것을 즐거워합니다.
자기소개
안정적으로 데이터를 처리할 수 있는 백엔드 엔지니어입니다.
MQ를 통해 비동기로 데이터를 처리하며 데드레터와 재시도 전략을 수립했습니다.
동시성 이슈를 마주해 Lock 전략을 비교하며 해결한 경험이 있습니다.
설계와 이슈 해결의 개선점을 꾸준히 고민합니다.
실시간 양방향 위치 공유 시스템 설계를 위해 기술들을 비교 분석하며 선정했습니다.
문제에 적합한 자료구조를 선택해 성능을 개선합니다.
Full Text 인덱스의 쿼리를 분석했으며 Sorted Set으로 랭킹 시스템을 개선했습니다.
기술 스택
Java, Spring, JPA, MySQL, Docker, Redis, aws-ec2
프로젝트
이길저길 - 길치들을 위한 경로 제공 및 만남 관리 서비스
팀 프로젝트 [백엔드(70%), 인프라(100%)]
2023.07. ~ 2024.03.
Github 저장소: https://github.com/HongDam-org/TWTW
#STOMP #OpenAPI #FCM
주요 기여 기술: Java Spring
JPA
MySQL
RabbitMQ
Redis
Docker
Github Actions
[위치 공유, 알림, 친구, 약속장소, 이미지, 데드레터] 도메인 / Jib 및 cicd 기반 aws ec2 배포
* 항목별 파란 글꼴은 블로그 포스트로 연결됩니다.
1. 실시간 양방향 위치 공유 시스템 설계 및 지속적으로 갱신되는 위치 좌표 저장 고민
Websocket, API 폴링, SSE 비교 분석과 STOMP 선택
[실시간성 / 양방향 지원 / 업데이트 빈도 적합성(각 다른 시점, 3초 주기)] 로 요구사항 기반 기준 비교
위 비교와 부하 테스트 수행 결과를 함께 고려해 STOMP 선택
Message Broker 고민과 RabbitMQ 선택
사용자 그룹당 평균 1.3/s 의 요청이 오기에 여러 개의 queue로 분산하는 것이 좋을 것이라 판단
그룹별로만 데이터를 공유하면 되기에 그룹별로 Binding 하여 queue 사용하는 방법 고려
동적으로 queue 생성/삭제 가능하며 그룹별 라우팅을 쉽게 구성 가능한 RabbitMQ 선택
지속적으로 갱신되는 위치 좌표 저장 고민과 Redis Geo 선택
메모리에서 O(log(n)) 의 거리 연산을 수행하는 Redis Geo를 DB에 비해 성능적 개선을 기대하며 선택
Redis, RabbitMQ aws 아키텍처 선택
Topic당 2만, queue당 2천 이상의 tps로 설계 요구사항을 상회하는 처리량을 제공하는 Amazon MQ, 장애 대응을 위한 스냅샷 등을 제공하는 AWS Elasticache를 선택하며 결합도 낮은 아키텍처 구성
2. FCM 알림 발송 비동기 처리를 위한 MQ 활용과 데드레터 전략 수립
비동기 처리 고려
FCM의 응답은 사용하지 않으며 성능을 고려해 아키텍처의 RabbitMQ로 비동기 처리하기로 결정
데드레터와 재시도 전략 수립
DB에 진행 상태를 저장하였으며 에러를 파악하기 위해 데드레터 발생 시 Slack 알림 발송
관리자 권한 API를 통해 데드레터 DB PK를 받아 DB 조회 후 큐로 재전송 가능하도록 구성
일시적인 에러의 경우에는 재시도로 처리하고자 3초 간격으로 최대 2번 재시도
3. OpenAPI RateLimit 이슈 대응과 호출 비용 절감을 위한 캐싱 및 만료 전략 수립
부하테스트 기준 Latency 평균 91.88ms -> 22.26ms 4.12배 개선
불필요한 OpenAPI 호출 고민과 캐싱 도입
데이터가 자주 변경되지 않는 OpenAPI를 지속적으로 호출, 간헐적으로 RateLimit 이슈 발생
기존 평균 91.88ms 소요되었던 OpenAPI 활용 부분 캐싱으로 이슈 해결 기대
Cache Aside 패턴 기반 캐싱 도입과 만료 전략
동일 로직의 @Cacheable를 사용하는 API와 @CachePut을 사용하는 API로 분리
평균 22.26ms로 개선 및 다음과 같은 갱신/만료 전략 수립
새로고침 요청 시 @CachePut 사용 API 호출하여 OpenAPI 직접 호출 이후 캐시 갱신
일정 시간이 지나 새 데이터 확인이 필요한 경우를 고려해 TTL 설정으로 캐시 만료
4. 무분별한 Mock 사용 제거를 위한 Strategy 패턴을 적용한 테스트 더블
단위 테스트 중 Mock 문제와 코드 구조 고민
Service Layer 테스트 시 Mock을 사용이 많았으며, 늘어나는 Mock으로 동적인 테스트 불가
Fake객체와 Strategy 패턴으로 구조 개선
JpaRepository를 상속받는 인터페이스와 Fake객체의 공통 인터페이스를 만들어 상속받도록 수정
@TestConfiguration 클래스에 @Primary와 함께 공통 인터페이스 타입으로 Fake 구현체 빈 등록
운영 시와 테스트 시 서로 다른 구현체가 주입되었으며 무분별한 Mock 사용 제거
5. OpenAPI 서버 장애 이슈 대응을 위한 서킷 브레이커와 모니터링
OpenAPI 서버 장애에 따른 대응 고민
Kakao, Naver, Tmap 의 OpenAPI 서버의 점검이나 장애 상황에도 계속해서 호출하며 에러 발생
OpenAPI 서버가 정상적인 응답을 하지 않음을 감지해 동적으로 처리하고자 Resilience4J 서킷브레이커 도입하여 호출 중 실패율이 30% 도달 시 Open 되어 fallback 메서드로 기본 응답 반환
모니터링의 도입과 알림 시스템
OpenAPI, FCM를 사용하며 RabbitMQ와 같은 기술과 상호작용하는 등 시스템에 변수가 많은 점 또한 고려해 모니터링 도입 및 Spring Actuator 중 Prometheus와 Resilience4J 사용
Grafana로 개선 작업 시 API Latency, 운영 시 API Status Code 분포 등 확인
장애 상황을 빠르게 파악하고 대응하고자 AlertManager로 관리자 Slack으로 알림 발송하도록 구성
6. Like 쿼리 개선을 위한 Full Text 인덱스 도입과 n-gram parser 분석
500만 row 기준 쿼리 평균 2.63s -> 0.53s 4.96배 개선
구현 초반 사용한 Like 쿼리와 문제점
닉네임의 Like 기반 검색 쿼리가 500만 row의 데이터 기준으로 평균 2.63s 소요
문자열 검색을 지원하는 MySQL의 Full Text 인덱스로 Like 기반 쿼리를 대체하고자 함
match against 쿼리 에러 발생
n-gram parser와 함께 boolean mode로 match 연산 시 쿼리 캐시 공간 부족 에러 발생
첫 번째 시도: 닉네임 길이 제한
쿼리시 고려할 경우의 수를 줄이고자 닉네임 최대 길이 8로 제한하니 29s 이상 걸리는 롱 쿼리 발생
query profiling 확인하여 FULLTEXT initialization 과정에서 29s 소요됨을 확인
두 번째 시도: n-gram parser 특징을 고려한 쿼리 수정
[ngram_token_size = 2] 임을 확인하며 검색어의 길이가 2보다 긴 것이 원인이라 추측
검색어 string을 길이 2씩 분할하여 쿼리하도록 수정해 평균 0.53s로 개선
GitRank - 블록체인 기반 깃허브 활용도를 통한 랭킹 서비스
팀 프로젝트 [백엔드(100%), 인프라(100%)]
2023.01. ~ 2023.09.
Github 저장소: https://github.com/tukcom2023CD/DragonGuard-JinJin
#크롤링 #블록체인 연동 #OpenAPI #이메일
주요 기여 기술: Java Spring
JPA
MySQL
Redis
Python
프로젝트 리더로서 홀로 서버 개발을 맡은 한이음 ICT 멘토링 공모전 입선작
* 항목별 파란 글꼴은 블로그 포스트로 연결됩니다.
1. Github API의 느린 응답 이슈 개선을 위한 스케줄링을 통한 DB 업데이트
부하테스트 기준 평균 Latency 7.72s -> 49.26ms 15.6배 개선
기존 구현과 OpenAPI의 응답 속도 이슈
5s ~ 10s를 기다려야 응답을 받는 OpenAPI를 매번 호출하며 평균 Latency 7.72s로 응답
첫 번째 시도: DB 우선 조회
결과 데이터를 DB에 저장하여 DB 데이터 반환하며 Latency 평균 49.26ms로 개선
두 번째 시도: 스케줄링으로 업데이트
Github 서버와의 데이터 Sync를 위해 스케줄링으로 2시간마다 전체 데이터 업데이트
히트율을 고려한 개선할 사항
Star 수가 많은 Repository만 스케줄링으로 업데이트 및 개인 Repository는 로그인 시 일괄 업데이트
2. DB 동시성 이슈 개선을 위한 Lock 전략 수립과 Lock 해제 시점 고민
요구사항과 동시성 이슈
한 번의 요청에 각각 다른 4종류의 데이터를 가져와 하나의 테이블에 update, 한 테이블에는 insert
동시 여러 번 호출 시 랭킹이 잘못 산정되는 문제 발생
첫 번째 시도: 낙관적 락
성능을 생각해 낙관적 락을 우선 적용하였지만, 충돌로 인한 롤백 자주 발생
두 번째 시도: 공유락
읽기 작업에는 락이 필요 없어 공유락 선택하여 해결
Redis 락 적용과 Lock 해제 시점
이후 아키텍처에 Redis가 추가되어 성능을 고려해 Redis 분산락으로 수정
독립된 처리를 위한 전파 레벨 설정, 정합성을 위해 별도 생성 트랜잭션이 끝나면 Lock 해제되도록 구현
3. DB 페이징 및 정렬 기반 랭킹 시스템 Redis 자료구조를 통한 개선
부하테스트 기준 평균 Latency 120.44ms -> 26.26ms 4.58배 개선
랭킹 페이징 쿼리 성능 이슈
5만 row 더미 데이터 삽입 후 테스트 시 페이징 및 정렬 기반 랭킹 조회 API Latency 120.44ms 소요
Redis의 Sorted Set 고민과 도입
Member의 DB PK와 포인트를 Redis Sorted Set에 저장하여 랭킹을 산정하도록 재구현
부하 테스트 기준 랭킹 API Latency 평균 26.26ms로 개선
포트폴리오
교육
한국공학대학교
대학교(학사) | 컴퓨터공학부 소프트웨어학과
2020.03. ~ 2024.02. | 졸업
대외활동
한이음 ICT 멘토링
한국정보산업연합회
한국공학대학교 UMC 4기 서버/Spring 운영진
한국공학대학교 UMC 4기
* 대학 IT 연합 동아리
한국공학대학교 프로그래밍 동아리 운영진
동아리 씨부엉
자격증
[수상 내역] TUKOREA SW-PowerUp
최우수상 | 한국공학대학교 컴퓨터공학부
2023.12.
[수상 내역] 한이음 ICT 멘토링 공모전
한국정보산업연합회장상(입선) | 한국정보산업연합회
2023.12.
[수상 내역] SW 캡스톤디자인 콘테스트
Pre-캡스톤 부문 동상 | 한국공학대학교 컴퓨터공학부
2022.10.