[Spring Batch] Spring Batch 아키텍쳐와 전체 흐름 이해하기
·
Spring
Spring Batch는 무엇을 해결하려는 기술일까?애플리케이션을 운영하다보면 사용자의 요청에 즉시 응답하는 API 처리와는 조금 다른 종류의 작업이 필요해진다. 매일 새벽 주문 데이터를 정산하거나, 대량의 회원 데이터를 읽어서 상태를 갱신하거나, 외부 시스템에서 받은 파일을 검증한 뒤 데이터베이스에 적재하는 작업들을 예시로 들 수 있다. 이러한 작업들은 보통 대량의 데이터를 처리해야 하고, 일정한 주기로 반복 실행되며, 실패했을 때 어디까지 처리했는지 추적할 수 있어야 한다. Spring Batch는 이런 배치 작업을 안정적으로 만들기 위한 프레임워크다. 공식 문서에서도 Spring Batch를 대량 데이터 처리를 위한 경량이면서 포괄적인 배치 프레임워크로 설명하고 있다. 다만, Spring Batc..
[EduKit] 사용자 경험을 개선해보자 (feat. Tomcat NIO)
·
Spring
문제점1차 MVP를 마친 이후, Edukit는 사용자의 피드백을 바탕으로 지속적으로 개선을 이어가고 있다. 성능 및 부하 테스트 과정에서, 서비스의 핵심 기능인 생기부 응답 AI 생성 로직에서 부하 테스트 도중 톰캣 쓰레드 풀이 고갈되는 문제가 발견되었다.현재 구조를 살펴보면, 사용자가 프롬프트를 입력하면 이를 기반으로 OpenAI 서버에 AI 응답 생성을 요청하는 전 과정이 동기식 처리로 이루어져 있다. 이로 인해 각 요청이 톰캣의 스레드를 점유하게 되고, 스레드 풀이 모두 소진되면서 다른 요청들이 대기 상태에 놓였다. 결과적으로 전체 API 응답 속도가 지연되는 병목 현상이 발생한 것이다.톰캣 스레드 고갈도 문제지만, 사용자 체감 속도가 느리다는 점이 더 큰 문제였다. 현재 서비스는 사용자의 한 번의..
이벤트 기반 처리로 구현하는 회원가입 및 이메일 전송 (feat. Thread pool)
·
Spring
요구사항이전 포스팅에서도 언급했듯, EduKit 서비스에는 이메일 인증 프로세스가 존재한다. 사용자가 회원가입 버튼을 클릭하면 인증을 위한 인증 코드가 생성되고, 해당 코드가 포함된 인증 링크가 담긴 이메일이 발송되는 흐름이다. 해당 로직을 구현하면서 고려했던 사항들은 아래와 같다. 1. 회원가입이 성공적으로 완료된 후, 이메일이 발송되어야 한다.즉, 회원가입을 수행하던 도중 어떠한 이유로 오류가 발생하여 롤백되는 경우, 인증 이메일이 발송되는 일은 없어야 한다. 가입 정보는 DB에 존재하지 않는데, 이메일은 발송되었다면 혼란을 줄 수 있기 때문이다. 따라서, 이메일 전송은 회원가입이 성공한 이후에만 실행되어야 한다. 2. 외부 메일 서비스의 장애가 회원가입 로직의 실패로 이어져서는 안된다.현재 우리 서..
재시도 폭풍에서 서버를 지키는 방법 (feat. 동시성 문제)
·
Spring
들어가며..2025 네이버 신입 공채 1차 면접 때 있었던 일이다. 이제 막 1달 된 따끈따끈한 일이다. 당시의 면접관의 질문과 내 답변을 복기해보면 아래와 같다.👤이력서 써놓은 신 것을 봤는데, 지금 동시성 제어를 낙관적 락으로 해결하셨다고 되어 있네요. 그러면 지금 100명이 동시에 좋아요를 눌렀을 때 발생할 수 있는 문제점이 뭐가 있을까요?️🗣️ 일단 지금 저의 로직으로는, 낙관적 락을 걸었기 때문에 만약 동시에 수정을 하면 버전 충돌로 인해서 자동으로 다시 시도하는 로직이 구현되어 있습니다. 근데 이제 100명이 동시에 시도를 하면 성공한 1명 빼고 나머지 99명은 똑같이 재시도 로직을 돌게 될 텐데 그 재시도를 도는 과정에서 부하가 일어날 수 있을 것 같습니다.👤 네 그 부하라는 거는 어떤..
로그인 코드 리팩토링 대장정
·
Spring
미뤄두고 미뤄두던 로그인 로직 리팩토링.. 더이상 미룰 수 없다고 생각해서 이번에 코드를 새롭게 갈아엎어보았다. 그 과정을 살펴보자!기존 코드의 문제점 🤔SOLID 원칙 위반기존 코드의 가장 큰 문제점은 객체지향스럽지 못하다는 것이다.위의 코드는 AuthService의 코드 중 일부로 외부 네트워크와 통신하여 사용자의 정보를 받아오고 또 탈퇴하는 코드이다. 인자인 platform은 사용자가 가입을 할 때, 클라이언트에서 어느 플랫폼으로 가입을 시도했는지 서버에게 보내준 enum 값이다. 이 코드의 문제점은 무엇일까? DIP와 OCP에 위배된다는 점이다. 만약, 기획의 요구사항의 변경으로 구글 로그인이 추가되었다면 어떨까? 구글 서버와 통신하기 위한 로직과 클래스를 생성해야하는 것은 물론이고, 이 Aut..
스프링 트랜잭션과 전파
·
Spring
문제점을 찾아보자!위 코드는 '한끼족보'에서 로그인을 담당하는 코드이다. 무엇이 문제일까?트랜잭션 범위RealMySQL에서는 트랜잭션의 범위를 최소화 하라는 조언이 있다. 특히, 외부 서버와 통신을 하는 과정은 트랜잭션 내에서 제거하는 것이 좋다고 한다. 프로그램이 실행되는 동안, 외부 서버와 통신할 수 없는 상황이 발생한다면 웹 서버 뿐만 아니라 DBMS 서버까지 위험해지는 상황이 발생할 수 있기 때문이다.다시 돌아와서, 코드를 살펴보자. 무엇이 문제일까?위 로직은, DB에 유저를 조회하거나 저장하는 로직과 함께 애플과 카카오 서버를 통해 사용자의 정보를 가져오는 getSocialInfo메서드 즉, 외부 서버와 통신하는 로직이 하나의 트랜잭션 단위로 묶여져있다. 만약, 카카오 서버에 문제가 생긴다면 어..
[Spring] 스프링 DB 2편 - 섹션 10~11
·
Spring
외부 트랜잭션과 내부 트랜잭션트랜잭션 전파란, 이미 진행 중인 트랜잭션이 존재할 때 추가로 트랜잭션을 수행하려는 상황에서 어떻게 동작할 지 결정하는 것을 트랜잭션 전파(propagation)이라고 한다. 트랜잭션 전파에는 여러가지 옵션이 존재하지만, 기본 옵션이 REQUIRED를 기준으로 설명하겠다.외부 트랜잭션이란 쉽게 말해서 가장 먼저 시작된 트랜잭션이다. 그리고 내부 트랜잭션은 그 이후에 호출된 트랜잭션으로 외부에 트랜잭션이 수행되고 있는 도중에 호출되기 때문에 마치 내부에 있는 것처럼 보여서 내부 트랜잭션이라 한다.흐름내부 트랜잭션을 시작하는 시점에는 이미 외부 트랜잭션이 진행중인 상태이다. 이 경우 내부 트랜잭션은 외부 트랜잭션에 참여한다. 즉, 내부 트랜잭션은 외부 트랜잭션을 기대로 이어 받아..
[Spring] 스프링 DB 2편 - 섹션 9
·
Spring
선언적 트랜잭션과 AOP@Transactional이라는 애노테이션을 사용하여 매우 편리하게 트랜잭션을 적용하는 것을 선언적 트랜잭션 관리라고 한다. 이 방식은 기본적으로 프록시 방식의 AOP가 적용된다.AOP의 핵심은, 실제 객체 대신 트랜잭션을 처리해주는 프록시 객체가 스프링 빈에 등록된다는 것이다. 또한 주입을 받을 때도 실제 객체 대신에 프록시 객체가 주입된다. 즉, 선언적 트랜잭션을 사용하면 항상 프록시를 통해서 대상 객체를 호출한다는 것이다.프록시 내부 호출만약, 프록시를 거치지 않고 대상 객체를 직접 호출하게 되면 어떻게 될까? 2가지 상황에 대해 알아보자.상황 1트랜잭션이 적용된 Internal() 메서드가 내부 호출로 External() 메서드를 호출하는 상황이다. Internal() 메서..
동시성 문제를 해결해보자
·
Spring
한끼족보에서 발생하는 동시성 문제'한끼족보'에도 동시성 문제(=Race Condition)가 존재한다. 예를 들어 2명의 유저가 동시에 하나의 가게에 좋아요를 누른다면, 해당 가게의 전체 좋아요 수가 2가 아니라 1로 집계되는 문제가 발생했다. 왜 이런 문제가 발생하는 것일까?문제 발생 원인위는 현재 '한끼족보'의 테이블 구조이다. '좋아요 수'를 비정규화 하여 가게 테이블에 위치해 있는 상태이다.@Transactionalpublic HeartCreateResponse createHeart(final HeartPostCommand heartPostCommand) { User user = userFinder.getUserReference(heartPostCommand.userId()); ..
[Spring] 스프링 DB 1편 - 섹션 3~4
·
Spring
트랜잭션트랜잭션은 작업의 완전성을 보장해 준다. 즉, 논리적인 작업 셋을 모두 완벽하게 처리하거나, 처리하지 못할 경우에는 원 상태로 복구하여 작업의 일부만 적용되는 현상(Partial update)이 발생하지 않도록 해준다.ACID원자성(Atomicity)트랜잭션 내에서 실행한 작업들은 모두 성공하거나 모두 실패해야 한다.일관성(Consistency)모든 트랜잭션은 일관성 있는 데이터베이스 상태를 유지해야 한다. 예를 들어 데이터베이스에서 정한 무결성 제약 조건을 항상 만족해야 한다.격리성(Isolation)동시에 실행되는 트랜잭션들이 서로에게 영향을 미치지 않도록 격리한다. 예를 들어 동시에 같은 데이터를 수정하지 못하도록 해야 한다. → 격리성은 동시성과 관련된 성능 이슈로 인해, 트랜잭션 격리 수..