[Spring] 낙관적 락 / 비관적 락 비교하기
·
Spring Framework/Spring
한정된 수량의 쿠폰을 회원에게 발급하는 시스템에서는 동시 다발적인 요청으로 인해 동시성 문제가 발생할 수 있다. 선착순 쿠폰 발급 시나리오에서 낙관적 락과 비관적 락의 성능을 정량적으로 비교하고, 동시 접속자 수 변화에 따른 각 방식의 특성을 분석했다.실험 환경기술 스택Backend : Spring Boot, Spring Data JPA, PostgreSQL부하 테스트 : K6실행 환경 : 로컬 개발 환경 (단일 서버)시스템 설정별다른 튜닝은 적용하지 않았다.HikariCP max-pool-size: 20Tomcat max-threads: 100락 구현 방식비관적 락 (SELECT FOR UPDATE)낙관적 락 + 재시도 3회 + Exponential Backoff낙관적 락 + 재시도 10회 + Expo..
[JPA] 엔티티의 equals()와 hashCode()
·
Spring Framework/JPA
개요이전 포스팅에서 자바의 동등성(Equality)과 동일성(Identity), 그리고 equals()와 hashCode() 메서드에 대해 정리했다. 일반 자바 객체에서는 객체의 논리적 동등성을 판단하는 데 필요한 핵심 필드들을 선택하여 이 두 메서드를 오버라이딩한다.하지만 JPA 엔티티는 일반 객체와 다른 특성을 가지고 있어 주의가 필요하다:영속성 컨텍스트 관리: 같은 엔티티라도 다른 시점에 조회하면 다른 인스턴스일 수 있다프록시 객체: 지연 로딩 시 실제 엔티티가 프록시로 감싸진다ID 할당 시점: @GeneratedValue 사용 시 엔티티 생성 시점에는 ID가 null이고, persist 호출 후에야 ID가 할당된다이러한 특성으로 인해 JPA 엔티티에서는 equals()와 hashCode() 구현에..
[JPA] N+1 문제
·
Spring Framework/JPA
N+1 문제란 ORM 사용 시 발생하는 대표적인 성능 이슈부모 엔티티를 조회하는 1번의 쿼리 후, 각 부모마다 연관된 자식 엔티티를 조회하는 N번의 추가 쿼리가 실행되는 현상예시: 100개의 게시물과 댓글 있을 때게시글 전체 조회: 1번 + 각 게시글의 댓글 조회: 100번 ⇒ 총 101번의 쿼리가 실행모든 정보를 한 번의 쿼리로 가져오지 못하고 추가 쿼리로 인해 성능 이슈가 발생한다.문제 상황게시물(Post), 댓글(Comment) 엔티티가 있다.(이외의 테이블은 없다고 가정)게시물 목록 조회 시 각 게시물의 댓글 갯수를 함께 조회하고 싶다.@Entity@Table(name = "post")@NoArgsConstructor(access = AccessLevel.PROTECTED)@Getterpublic..
[Spring] tomcat 설정의 동작 원리(max-connections, accept-count, threads.max)
·
Spring Framework/Spring
Spring Boot로 웹 애플리케이션을 개발하면서 application.yml에 있는 Tomcat 설정들을 본적은 있지만 별 생각 없이 무심하게 지나쳤다. 하지만 이 설정들이 정확히 무엇을 의미하고, 어떤 역할을 하는지 궁금해 졌다.server: tomcat: max-connections: 8192 accept-count: 100 threads: max: 200본 포스팅에서는 Tomcat의 세 가지 핵심 설정인 accept-count, max-connections, threads.max가 클라이언트 요청을 처리하는 과정에서 각각 어떤 역할을 하는지 정리했다.설정들의 역할그 전에 알아야 할 것HTTP는 TCP를 기반으로 동작한다클라이언트와 서버간 연결을 위해 3-hand-sha..
[Spring] 트랜잭션과 동시성
·
Spring Framework/Spring
처음 Spring을 공부할 때 감명받은 기능 중 하나가 @Transcational이었다. 애너테이션만 붙여주면 일일히 커넥션을 열고 커서를 가져오고 작업하고 리소스를 닫는 등 번거로운 작업들이 알아서 적용되니 정말 편리했다. 그러다보니 트랜잭션이 필요한 곳에서는 관성적으로 @Transactional를 추가하고 모든 문제가 해결됐다고 생각했다. 하지만 서비스 환경에서 멀티 스레드 상황이라면 문제가 생길 수 있다.트랜잭션, 격리 수준, 락킹, 동시성 제어 등 여러 용어들은 많이 들어보고, 또 알고 있다고 생각했지만 각각의 개념이 서로 연결되지 않은 느낌이 들었다. 동시성 제어에 대해 다시 공부를 시작하면서 차근차근 정리해나가려고한다. 우선은 가장 기본적인 트랜잭션과 @Transactional에 대해 포스팅을..
[Spring Batch] 메타 데이터 테이블 정리
·
Spring Framework/Spring
Spring Batch가 배치 작업의 실행 상태와 이력을 추적하기 위해 자동으로 생성하고 관리하는 테이블사용자가 직접 조작하지 않고, Spring Batch가 내부적으로 모든 배치 실행 정보를 기록해당 테이블을 사용해서 배치 작업 모니터링도 구현해볼 수 있다.실행 이력, 성공/실패 결과 등 다양한 정보를 제공필요한 테이블의 DDL은 Spring Batch Github에서 확인할 수 있다. 여러 종류의 데이터 베이스에 대한 SQL 파일이 있어서 자신이 사용중인 데이터베이스에 맞는 쿼리를 가져와 사용하면 된다.메타 테이블 목록BATCH_JOB_INSTANCE : Job의 기본 정보(이름, hash key)BATCH_JOB_EXECUTION : Job의 실행 이력 : job id, 실행시간, 상태, 실행결과B..
[Spring Batch] skip / retry
·
Spring Framework/Spring
Spring Batch에서 일부 오류 데이터 때문에 전체 배치가 실패하는 문제를 해결하는 방법가령 10만 건 데이터 처리 중 1건의 오류로 전체 작업이 중단되거나, 일시적인 네트워크 오류로 배치가 실패하는 상황을 방지할 수 있다.알아볼 것Spring Batch skip/retry 기능을 실제 프로젝트에 적용Reader/Processor/Writer 각 단계별 오류 처리 동작 방식 이해상황별 적절한 오류 처리 전략 수립skip잘못된 데이터를 제외하고 나머지 처리를 계속해야 할 경우retry네트워크 오류, DB 연결 실패 등 재시도로 해결 가능한 문제일 경우skip / retryskip예외 발생 시 해당 아이템만 제외하고 나머지 정상 데이터는 계속 처리한다.오류 발생 → 해당 아이템 제외 → 다음 아이템 계..
[JPA] 5개 데이터가 4+1개 쿼리로 나누어지다.
·
Spring Framework/JPA
Spring Data JPA의 saveAll()로 대량 데이터를 삽입할 때 예상과 다른 SQL이 실행되는 것을 발견누가 배치 쿼리를 어떻게, 왜 분할하는지 코드를 찾아본 과정예상 vs 실제 쿼리 실행5개의 프로젝트 데이터를 saveAll()로 저장했을 때:// 5개 엔티티를 한 번에 저장List projects = generateProjects(5);projectRepository.saveAll(projects);예상한 쿼리:# 예상했던 쿼리INSERT INTO project (title,id) VALUES ($1,$2),($3,$4),($5,$6),($7,$8),($9,$10);# 실제 실행된 쿼리# - 4개 + 1개로 분할됨INSERT INTO project (title,id) VALUES ($1,$..