400ms STW 하나가 실시간 서비스를 어떻게 멈춰세우는지
·
JAVA
글을 작성하게 된 이유실시간 트래픽이 몰리는 서비스에서 Stop-The-World(STW)가 400ms 이상 걸리면서, 모듈 사이 통신이 끊기고 라우팅이 꼬이는 상황을 겪고 나서야 깨달았다. 이 글은 그때 겪었던 장애 상황부터, GC 원인 분석, 그리고 ParallelGC에서 G1GC로 튜닝하면서 실제로 STW를 줄였던 과정을 정리해보려고 쓴다. GC가 뭐길래?Java에서는 개발자가 직접 free() 같은 걸 호출해서 메모리를 해제하지 않는다.대신 GC가 주기적으로 돌아다니면서 더 이상 참조되지 않는 객체를 찾아서 메모리에서 치워준다.이 덕분에 메모리 관리가 편해지는 대신, GC가 도는 동안 애플리케이션의 모든 쓰레드가 멈춘다. 이것을 Stop-The-World(STW) 라고 부른다. 서비스 간략 설명내..
분산 환경 JPA 영속성 관리, 그리고 RabbitMQ Pub/Sub로 푸는 캐시 동기화
·
TroubleShooting/Server
문제 상황운영 환경에서 다음과 같은 Hibernate 예외가 발생했다.javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: kr.aift.davinci.common.rdb.model.sql.chatbot.ClassMasterprod 환경에서는 상세한 스택트레이스 없이 에러 코드와 메시지만 볼 수 있었기 때문에,정확한 원인 파악이 쉽지 않았다. 왜 JPA는 detached entity에 persist를 허용하지 않을까?JPA의 persist는 "새로운 엔티티"만을 위한 메소드다. 이미 DB에 존재하는 엔티티(즉, PK가 할당된 엔티티)는 merge를 통해..
복잡한 queryDSL에 대한 최적화 고민과 회고
·
Refactoring
문제 배경사용자 질의 기록을 분석하여 분석 결과 요약 리스트를 제공하는 API를 개발하면서, 다음과 같은 기능 요구사항이 있었습니다특정 기간 내 사용자 요청을 기준으로 응답/미응답 여부를 필터링분석 결과는 3가지 알고리즘 (a 분류, b 분류, c 유사도) 별로 각각 존재분석 결과 외에도 시나리오 정보, 엔티티 탐지 정보 등 다양한 부가 정보도 함께 보여줘야 함즉, 기준 테이블(A)에서 다수의 결과 테이블(B, C, D)를 각각 조인 또는 별도로 조회해야 하는 상황이었고, 단일 쿼리로 모든 결과를 가져오면 다음과 같은 문제가 있었습니다알고리즘마다 JOIN이 추가되며 성능 저하 발생응답/미응답 여부 판단을 위해 알고리즘별 조건이 달라 별도 조건 분기를 동적으로 처리해야 함UI에는 하나의 레코드처럼 보여야 ..
이직 후 첫 회고록 - MSA 멀티모듈 API 명세서 도입기
·
카테고리 없음
AI 백엔드 팀으로 이직 후 작성하는 첫 회고록이다.새로운 환경에서 업무를 시작하면서 가장 먼저 중요하게 여긴 것은 도메인 파악이었다.이를 빠르게 진행하기 위해 설계도와 프로젝트 셋업을 우선적으로 시작했다. 이 프로젝트는 MSA 환경에서 동작하는 멀티 모듈 기반이었으며, 브랜치 전략 또한 이전 회사와 달라서 별도로 분석이 필요했다. 업무 중 자사 서비스를 이용하며 API를 살펴보던 중, 하나의 Request 객체가 여러 Controller에서 전역적으로 사용되고 있다는 점을 발견했다. 다양한 곳에서 재사용되는 구조였지만, 필드에 @Nullable 등의 명시적 제약이 없어 어떤 필드가 필수인지 파악이 어려웠다. API 명세서는 postman, request 파일, openapi 파일 등으로 따로 관리되고 ..
'Diagram_AI' 플러그인 개발
·
Plugin
평소 새로운 프로젝트에 투입되거나 여러 프로젝트를 동시에 진행할 때, 도메인 구조를 빠르게 파악할 수 있도록 도와주는 프로그램이 있으면 좋겠다고 생각했습니다. 제가 주력으로 사용하는 Spring Framework는 Bean 간의 관계를 잘 분석하면 도메인 구조를 다이어그램으로 시각화하는 것이 충분히 가능하다고 판단했고, 이를 자동화하는 도구를 개발하게 되었습니다. 우선 SpringFramework의 동작 과정에 대해서 학습이 필요했습니다.Spring Boot가 실행될 때 내부적으로 어떤 과정이 발생하는가?SpringApplication.run(...) 실행Spring Boot 애플리케이션을 시작하는 가장 기본적인 엔트리 포인트로, 내부적으로 SpringApplication 객체를 생성하고 실행함.이 과정..
네트워크 왕복을 줄여 성능 개선 (Redis / Lua Script)
·
DB
(대규모 대기열 접속 시스템에서 최소의 자원으로 최대의 효율을 내기 위한 방법을 공부하던 중 기록하게 되었습니다.) Redis의 기본 방식에서는 여러 개의 명령어 실행 시 네트워크 왕복 비용이 증가한다.LUA 스크립트는 Redis 서버 내부에서 실행되므로, 네트워크 왕복을 줄이고 성능을 향상.캐싱된 LUA 스크립트를 EVALSHA로 실행하면 추가적인 성능 최적화 가능.LUA 스크립트로 변환해야 할 주요 메서드대기열 등록 (registerWaitQueue)→ ZADD를 사용하여 사용자 추가 (이미 존재하는 경우 추가 방지)사용자 입장 허용 (allowUser)→ ZPOPMIN으로 대기열에서 사용자 추출 후 진행 목록에 추가→ TTL 설정 추가 (EXPIRE)즉, 반복되는 작업을 레디스 내에서 동작하도록 하..
만만하지 않았던 블랙프라이데이
·
카테고리 없음
블랙 프라이데이 한정 수량 판매에서 초과 결제가 발생했던 이유와 해결 과정블랙 프라이데이 기간에 한정 수량으로 진행한 전기 자전거 판매 이벤트에서 초과 결제가 발생하면서 이슈가 있었고, 이를 어떻게 해결했는지 정리해본다. 단순 트래픽 폭주 정도가 아니라, 분산 환경에서의 재고 관리 방식 자체를 다시 설계해야 했던 케이스다.문제 상황전기 자전거 180대 한정 판매블프 시간대에 재고 이상 고객 동시 접속실제 확보한 재고보다 N건 이상 초과 결제 발생초과 결제된 사용자에게 환불을 해야 했고, 불만도 상당히 발생문제 원인1) 재고 차감 위치가 결제 트랜잭션 이후에 있었다기존 로직 흐름은 다음과 같았다.사용자가 결제 페이지로 이동결제 요청 → 외부 PG 결제 승인결제 성공 후 재고 차감문제는 단계 2번에서 동시에..
MSA (2) Spring Cloud Gateway - Filter
·
Infra
FIlter Spring Cloud Gateway에서 Filter는 요청(Request) 및 응답(Response)을 처리하거나 변환하는 데 사용된다. 필터를 설정 이유공통 로직 처리:모든 요청에 대해 동일한 작업(예: 인증, 로깅)을 중앙에서 처리가 가능하다.유연한 요청 처리:서비스별로 맞춤형 필터를 적용해 요청을 동적으로 변환이 가능하다.관리와 확장성:개별 서비스에 중복 코드를 작성할 필요 없이 Gateway에서 일괄 관리 가능하다..yml 필터 작성server: port: 8000eureka: client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://localhost:8..
MSA (1) - Spring Cloud Netflix Eureka
·
Infra
Spring Cloud Netflix EurekaService DiscoveryEureka는 Spring Cloud Netflix에서 제공하는 서비스 디스커버리 도구로, MSA 환경에서 각 서비스의 위치(IP와 포트)를 동적으로 관리한다.서비스 디스커버리란?MSA에서는 각 서비스가 독립적으로 배포되고 확장되므로, 고정된 IP와 포트를 사용하는 것이 어렵다.Eureka는 서비스 레지스트리로 작동하여 각 서비스의 위치 정보를 등록하고, 다른 서비스가 이를 검색할 수 있도록 돕는다.Eureka Server와 Eureka ClientEureka Server: 모든 서비스의 위치 정보를 저장 및 관리.Eureka Client: 애플리케이션이 Eureka Server에 자신의 위치를 등록하거나, 다른 서비스의 위치..
서비스 이자율 정책
·
카테고리 없음
미납 회수를 위한 연체 이자 도입 기획구독 시스템의 미납 회수율을 개선하고, 결제 없이 서비스를 지속적으로 이용하는 연체 사용자 문제를 해결하기 위해 연체 이자 시스템을 도입하고자 합니다.주요 신용카드사의 연체 관리 방식을 참고하고, 관련 법적 요구 사항을 기반으로 구체화하였습니다.현재 로직 분석1. 미납 결제 시도 시bill_id가 존재하는지 확인가장 최근 데이터의 status 확인status = success이면 정상 결제 완료 → 결제 시도 ❌status != success이면 미납 상태 → 결제 재시도 retry_count에 따라 이자율 증가2. 문제점같은 구독자라도 연체 기간이 다르면 부담하는 이자가 다를 수 있음현재 방식은 retry_count만 고려하여 이자율을 증가시키기 때문에, 장기 연체..