Project 34

[트러블슈팅] 분산락 걸었는데도 부하테스트 결과가 이상하다 : JPA 갱신 유실 트러블슈팅

필자는 MSA 기반 대규모 트래픽 처리 예약구매 이커머스 서비스를 개발중이었다. 깃허브 주소 프로젝트의 핵심 기능 중 하나가 예약구매였다. 한정된 재고에 대해 여러 사용자가 동시에 주문을 넣는 구조라 동시성 문제가 필연적으로 따라오는 기능이었다. 재고에 대한 동시성 문제(Race condition)는 Redis 분산락으로 테스트코드를 통해 해결됐음을 확인했다! (자세한 분산락 핸들링 기록은 아래 분산락 포스팅 참고) [프로젝트/기술적 의사결정] Redis 분산락으로 재고 감소 동시성 이슈 해결하기 (1/2)필자는 MSA 기반 이커머스 프로젝트에서 상품/재고/예약구매 도메인을 맡아 진행중이다. 지난 프로젝트에서 쿠폰 도메인을 맡아 개발했을 때 Race condition 문제를 예상치 못하게 겪고 (..) ..

[N+1 삽질] 무조건 fetch join, @BatchSize가 정답은 아니다 (feat. 집계 쿼리 최적화)

필자는 현재 스마트폰 역경매 플랫폼 bidr(비더)를 개발 중이다. (5월 런칭 목표) bidr의 견적 목록 화면에는 각 견적마다 '입찰 5개·최저 8만원' 같은 정보가 표시된다. 구매자 입장에서 내 견적에 입찰이 얼마나 몰렸는지, 가장 저렴한 입찰가가 얼마인지 한눈에 볼 수 있어야 하기 때문이다. 그런데 이걸 구현하다가 전형적인 함정(?)을 밟았다. 문제 발견 — 견적 20개를 조회했는데 쿼리가 41번?처음 구현은, 견적 목록을 불러온 뒤 각 견적마다 입찰 수량 최저가를 개별로 조회하면 된다고 생각해서 아주 단순하게 구현했다. 그런데 기능 구현을 마치고 로컬에서 테스트하다가 콘솔을 무심코 봤는데 뭔가 이상했다. 견적 목록 조회 한 번에 로그가 너무 많이 찍히는 거였다..!Hibernate: selec..

Project/phonebid 2026.05.03

계약하기 버튼, 두 번 누르면 어떻게 될까 ㅡ 비관적 락 적용기

필자는 현재 스마트폰 역경매 플랫폼 bidr(비더)를 개발 중이다. (5월 런칭 목표) bidr에서 계약이 만들어지는 흐름은 이렇다. 구매자가 견적을 올리면 여러 판매자가 입찰을 넣고, 구매자가 마음에 드는 입찰을 선택하면 계약이 체결된다. 간단한 구조다. 문제 인식 — 이 패턴, 어디서 많이 봤는데과거에 이커머스 프로젝트 개발 중 재고 차감 기능을 구현한 적이 있다. 여러 사용자가 동시에 같은 상품을 주문할 때 재고가 0 아래로 내려가는 걸 막아야 하는 상황이었다. 그때 낙관적 락과 Redis 분산락을 직접 써보면서 동시성 문제를 어떻게 다루는지 익히게 되었다. 그 경험이 있어서인지, bidr에서 계약 생성 기능을 구현하다가 코드를 보는데 뭔가 익숙하고 찝찝한(?) 느낌이 드는것이었다..! '구매자가 ..

Project/phonebid 2026.04.29

"이거 수백 개 다 손으로 바꿔야 해요?" ㅡ 그리드 마이그레이션 자동화 회고

필자는 ERP 시스템 유지보수 업무를 하면서 꽤 묵직한 작업을 맡게 되었다. dhtmlxGrid 라이브러리로 구성된 수백 개 화면을 SBGrid v3 라이브러리로 전면 전환하는 마이그레이션 프로젝트였다. 이 포스팅은 그 과정에서 반복 작업을 어떻게 자동화했는지, 그리고 폐쇄망 환경이 풀리고 나서 AI 프롬프트 배포까지 어떻게 이어졌는지에 대한 기록이다.💡이 포스팅에 나오는 라이브러리dhtmlxGrid — 해외 웹 그리드 UI 라이브러리. 행/열로 구성된 데이터 테이블을 화면에 렌더링하고 편집할 수 있게 해준다. 유료 라이선스 제품이다.SBGrid v3 — 국내 기업 소프트보울에서 만든 그리드 라이브러리. dhtmlxGrid와 동일한 역할을 하지만 라이선스 비용이 훨씬 저렴했다. 이 프로젝트에서 dhtm..

SSE 기반 실시간 알림 구현기 : 기술 선택부터 프로덕션 안정화까지

필자는 현재 스마트폰 역경매 플랫폼 bidr(비더)를 개발 중이다. (5월 런칭 목표) bidr에서는 입찰 도착, 최저가 갱신, 계약 체결 등 실시간으로 사용자에게 전달해야 하는 이벤트가 많다. 구매자 입장에서는 내 견적에 새로운 입찰이 들어왔을 때 빠르게 인지해야 하고, 판매자 입장에서는 내가 제시한 입찰이 선택됐을 때 즉각적으로 알아야 이후 계약 흐름이 자연스럽게 이어진다. 이번 포스팅에서는 이 실시간 알림을 어떤 방식으로 구현할지 선택하는 과정부터, 실제 구현 후 프로덕션 환경에서 안정적으로 동작하도록 개선한 과정까지 정리해보려 한다. 기술적 의사결정 — 폴링, WebSocket, SSE실시간 알림을 구현하는 방법은 크게 세 가지다. 폴링, 웹소켓, SSE. 1. 폴링 (Polling)클라이언트가 ..

Project/phonebid 2026.04.26

[리팩토링] 알림 발송 로직을 동기에서 이벤트 기반 비동기로 개선하기 (feat. @TransactionalEventListener)

필자는 현재 스마트폰 역경매 플랫폼 bidr(비더)를 개발 중이다. (5월 런칭 목표) bidr는 구매자가 원하는 스마트폰 사양과 희망 가격 등의 견적을 올리면, 판매자들이 역으로 입찰을 넣는 구조다. 구매자 입장에선 여러 판매자의 견적을 한 번에 받아볼 수 있고, 판매자 입장에선 구매 의사가 확실한 고객에게 직접 제안할 수 있다. 이 구조에서 알림은 꽤 중요한 역할을 한다. 구매자가 견적을 등록하면 승인된 판매자 전원에게 카카오 알림톡으로 새 견적이 올라왔다는 알림이 발송되고, 구매자가 마음에 드는 입찰을 선택해 계약이 체결되면 구매자와 판매자 양쪽 모두에게 알림이 발송된다. 판매자가 빠르게 인지하고 입찰에 참여해야 서비스가 돌아가고, 계약 체결 순간에도 양쪽이 즉각적으로 인지해야 이후 결제와 배송 흐..

Project/phonebid 2026.04.23

레거시 쿼리 리팩토링으로 응답속도 99.8% 개선하기 (3.569s → 0.005s)

필자는 직전 회사에서 ERP 급여 모듈 유지보수 및 고도화를 맡고 있었다.GS 인증 취득을 위해 성능 기준 통과를 해야 하는 상황이 생겼는데, 데이터 건수가 많지 않음에도 불구하고 급여 모듈 곳곳에서 응답속도가 3~4초에 달하는 화면들이 발견됐다. (테스트 데이터 건수들은 약 100건)💡GS(Good Software) 인증이란?가전제품에 붙는 KS 마크나 식품의 HACCP 인증처럼, 쉽게 말해 "이 소프트웨어는 기능도 제대로 동작하고, 성능 기준도 충족한다"는 걸 공인 기관인 한국정보통신기술협회(TTA)이 검증해주는 것이다.공공기관이나 기업에 소프트웨어를 납품할 때 GS 인증이 있으면 신뢰도 면에서 유리하고, 일부 공공 조달 시장에서는 사실상 필수 요건으로 작용하기도 한다.인증 심사 항목 중에는 응답속..

[Spring/JPA] refresh token 통합 테스트 중 데이터 불일치 문제 삽질기 (@Modifying의 flushAutomatically 옵션)

1. 문제 상황: "분명히 지웠는데 왜 남아있지?"최근 진행 중인 사이드 프로젝트의 access, refresh token 인증 로직을 검증하기 위해 통합 테스트 코드를 작성하고 있었다. 로그인, 토큰 갱신, 로그아웃으로 이어지는 전체 플로우를 테스트하던 중, 로그아웃 시 DB에서 Refresh Token이 삭제되지 않는 문제가 생겼다.// 문제의 테스트 코드 일부@Test@DisplayName("로그아웃 -> RefreshToken 삭제 확인")void logout_ShouldDeleteRefreshToken() throws Exception { // 1. 로그인하여 토큰 생성 userService.login(loginRequest); // 2. 로그아웃 수행 (내부적으로 de..

Project/phonebid 2026.01.27

[Spring 트래픽 제한] 인증 없는 API에 안전장치 달기: Bucket4j로 Rate Limiting 구현

서비스를 운영하다 보면 보안상 가장 고민되는 지점 중 하나가 바로 '인증되지 않은 사용자의 요청' 이다. 특히 파일 업로드 API는 악의적인 사용자의 타겟이 되기 쉽다. 주변에서도 왕왕 그러 악의적인 접근 때문에 aws 요금을 폭탄맞았다는 경우도 왕왕 들었다. 오늘은 최근 프로젝트 코드 리뷰 중 발견한 보안 취약점을 해결하기 위해, Bucket4j를 도입하여 트래픽 제한(Rate Limiting)을 적용한 과정을 공유하려 한다. 1️⃣ 현재 필자의 상황 (왜 트래픽 제한이 필요한가)현재 개발 중인 프로젝트의 판매자 회원가입 로직은 다음과 같다.판매자가 회원가입 폼을 작성하며 사업자등록증 등 증빙 서류를 업로드한다.이 서류는 S3의 temp/ 경로에 임시 저장된다. (아직 가입 전이므로 비로그인 상태)회원..

Project/phonebid 2026.01.15

[프로젝트/구현] Redis Replication 마스터-슬레이브 구조를 통한 분산 처리 적용 과정

이전 글2025.05.01 - [Project/대용량 트래픽 프로젝트] - [기술적 의사결정] MSA 환경에서 배송 정보 임시 저장소로 Redis를 사용한 이유 [기술적 의사결정] MSA 환경에서 배송 정보 임시 저장소로 Redis를 사용한 이유💡문제 상황우리 프로젝트에서는 주문을 생성할 때 배송 정보도 함께 입력받는 구조를 채택하고 있다. 현재 주문 처리 흐름은주문 ➡️ 재고 확인 ➡️ 결제 ➡️ 재고 차감 ➡️ 배송 ➡️ 주developer-jinnie.tistory.com 이전 글에서는 배송 데이터 임시 저장소로 Redis를 선택해 사용하게 된 기술적 의사결정 과정을 기술해보았다. 이번 글에서는 해당 구조에서 오는 문제점을 인지하고 해결하는 과정을 공유해보려 한다. 💡문제 상황현재 개발 중인 서..