📖
Kyu9's Repo
  • Library of mameil
  • 이슈 경험
    • 20230220_트랜잭션
    • 20230306_캐싱이슈
    • 20230722_테스트코드에서 @Transactional
    • 20230807_deadlock
  • 인턴 스터디
    • Gradle
    • Stream, Optional, 람다식
    • JVM의 메모리 구조, Garbage Collector
    • RESTful API
    • Microservice Architecture
    • HTTP
    • 웹서버란 무엇인가
    • Git Branch
    • TDD
    • Redis을 이용한 캐시
    • Thymeleaf
    • 정리가 필요한 자료들
    • SpringBoot Management
    • 테스크 코드 분할
  • 동아리 스터디
    • 기본 SQL 공부
      • SQL의 기본 개념
      • SELECT 문장을 이용하여 원하는 데이터 출력하기
        • 집합 연산자 사용하기
        • where절에 비교 연산자를 사용해보기
        • SELECT_EX
        • 산술 연산자 사용해보기
      • 단일 행 함수 사용
        • lower/upper 함수 사용하기
        • length함수 사용하기
        • concat함수 사용
        • substr/mid/substring 함수 사용
        • instr함수 사용하기
        • lpad/rpad 함수 사용하기
        • trim/ltrim/rtrim 함수 사용하기
        • replace 함수 사용하기
        • round 함수 사용하기
        • truncate 함수 사용하기
        • mod함수 사용하기
        • ceil함수 사용하기
        • floor함수 사용하기
        • power 함수 사용하기
        • Date fn(날짜 함수)
        • 형 변환 함수
        • 일반함수란
    • a-ha 실습
    • 혼자서 만들어본 게시판
    • AWS 강의
  • 학교 나머지 공부 자료
    • 웹프레임워크(Spring)
      • Spring이란?
      • Webframework1-1
      • Webframework1-2
      • SpringBoot의 특징
      • SpringBoot 생성 방법
      • Spring Data JPA
      • SpringBoot Security
      • SpringBoot HATEOAS
  • 공부 자료들
  • WS 온라인 자바 스터디
    • Week1(JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.)
    • Week2(자바 데이터 타입, 변수 그리고 배열)
    • Week3(연산자)
    • Week4(제어문)
    • Week5(클래스)
    • Week6(상속)
    • Week7(패키지)
    • Week8(인터페이스)
    • Week9(예외처리)
    • Week10(멀티쓰레드 프로그래밍)
    • Week11(Enum)
    • Week12(Annotation)
    • Week13(I/O)
    • Week14(Generic)
    • Week15(람다식)
  • 백준문제
    • 입출력과 사칙연산
      • We love kriii(10718)
      • 고양이(10171)
      • 개(10172)
      • A+B(1000)
      • A-B(1001)
      • AxB(10998)
      • A/B(1008)
      • 사칙연산(10869)
      • 나머지(10430)
      • 곱셈(2588)
    • for문
      • 구구단(2739)
      • A+B - 3(10950)
      • 합(8393)
      • 빠른 A+B(15552)
      • N 찍기(2741)
      • 기찍 N(2742)
      • A+B - 7(11021)
      • A+B - 8(11022)
      • 별 찍기 - 1(2438)
      • 별 찍기 - 2(2439)
      • X보다 작은 수(10871)
    • if문
      • 두 수 비교하기(1330)
      • 시험 성적(9498)
      • 윤년(2753)
      • 사분면 고르기(14681)
      • 알람 시계(2884)
      • 오븐 시계(2525)
      • 주사위 세개(2480)
      • 영수증(25304)
    • While문
      • A+B - 5(10952)
      • A+B - 4(10951)
      • 더하기 사이클(1110)
    • 1차원 배열
      • 최소, 최대(10818)
      • 최댓값(2562)
      • 숫자의 개수(2577)
      • 나머지(3052)
      • 평균(1546)
      • OX퀴즈(8958)
      • 평균은 넘겠지(4344)
    • 함수
      • 정수N개의 합(15596)
      • 셀프 넘버(4673)
      • 한수(1065)
    • 문자열
      • 아스키코드(11654)
      • 숫자의 합(11720)
      • 알파벳 찾기(10809)
      • 문자열 반복(2675)
      • 단어 공부(1157)
      • 단어의 개수(1152)
      • 상수(2908)
      • 다이얼(5622)
      • 크로아티아 알파벳(2941)
      • 그룹 단어 체커(1316)
    • 기본수학-1
      • 손익분기점(1712)
      • 벌집(2292)
      • 분수찾기(1193)
      • 달팽이는 올라가고 싶다(2869)
      • ACM 호텔(10250)
      • 부녀회장이 될테야(2775)
      • 설탕 배달(2839)
      • 큰 수 A+B(10757)
      • Fly me to the Alpha Centauri(1011)
    • 기본수학-2
      • 소수 찾기(1978)
      • 소수(2581)
      • 소인수분해(11653)
      • 소수 구하기(1929)
      • 베르트와 공존(4948)
    • 재귀
      • 하노이 탑 이동 순서(11729)
      • 피보나치 수 5(10870)
      • 별 찍기(2447)
    • 브루트 포스
      • 블랙잭(2798)
      • 분해합(2231)
      • 덩치(7568)
      • 체스판 다시 칠하기(1018)
      • 영화감독 슘(1436)
    • 집합과 맵
      • 숫자 카드(10815)
      • 문자열 집합(14425)
      • 숫자 카드2(10816)
      • 듣보잡(1764)
      • 대칭 차집합(1269)
      • 서로 다른 부분 문자열 갯수(11478)
    • 정렬
      • 수 정렬하기(2750)
      • 수 정렬하기 2(2751)
      • 수 정렬하기 3(10989)
      • 통계학(2108)
      • 소트인사이드(1427)
      • 좌표 정렬하기(11650)
      • 좌표 정렬하기2(11651)
      • 단어 정렬(1181)
      • 나이순 정렬(10814)
      • 커트라인(25305)
      • 좌표압축(18870)
    • 백트래킹
      • N과 M - 1(15649)
      • N과 M - 2(15650)
      • N과 M - 3(15651)
      • N과 M - 4(15652)
      • N-Queen(9663)
      • 스도쿠(2580)
      • 연산자 끼워넣기(14888)
      • 스타트와 링크(14889)
    • 이분 탐색
      • 수 찾기(1920)
    • 동적계획법
      • 피보나치 함수(1003)
      • 신나는 함수 실행(9184)
      • 01타일(1904)
      • 파도반 수열(9461)
      • RGB거리(1149)
      • 정수 삼각형(1932)
      • 계단 오르기(2579)
      • 1로 만들기(1463)
      • 쉬운 계단 수(10844)
      • 포도주 시식(2156)
      • 가장 긴 증가하는 부분 수열(11053)
      • 가장 긴 바이토닉 부분 수열(11504)
      • 전깃줄(2565)
      • LCS(9251)
      • 연속합(1912)
      • 평범한 배낭(12865)
      • 더하기(9095)
    • DFS와 BFS
      • 미로탐색(2178)
      • 바이러스(2606)
      • DFS와 BFS(1260)
      • 단지번호붙이기(2667)
      • 전쟁 - 전투(1303)
      • 숨바꼭질(1697)
      • 데스 나이트(16948)
      • 나이트의 이동(7562)
      • 녹색 옷 입은 애가 젤다지?(4485)
      • 음식물 피하기(1743)
      • A->B (16953)
      • 숨바꼭질 3(13549)
      • 숨바꼭질 2(12851)
    • 구현
      • 치즈(2636)
  • 프로그래머스 문제
    • SQL
      • Animal Table - Oracle
      • Animal Table - MySQL
      • Animal Table2 - Oracle
      • Animal Table 3,4 - Oracle
    • Lv1
      • 두 개 뽑아서 더하기
      • 제일 작은 수 제거하기
      • 문자열 내 p와 y의 개수
      • 예산
      • 자릿수 더하기
      • 두 정수 사이의 합
      • 같은 숫자는 싫어
      • 가운데 글자 가져오기
      • 수박수박수박수박수박수?
      • 나누어 떨어지는 숫자 배열
      • 2016년
      • 폰캣몬
      • 서울에서 김서방 찾기
      • 문자열을 정수로 바꾸기
      • 소수 만들기
      • 문자열 다루기 기본
      • 소수 찾기(에라토스테네스의 체)
      • 숫자 문자열과 영단어
      • 이상한 문자 만들기
      • 없는 숫자 더하기
      • 문자열 내림차순으로 배치하기
      • 문자열 내 마음대로 정렬하기
      • 약수의 개수와 덧셈
      • 콜라츠 추측
      • 자연수 뒤집어 배열로 만들기
      • 신규 아이디 추천
      • 비밀지도
      • 크레인 인형뽑기 게임
      • 실패율
      • 로또의 최고 순위와 최저 순위
      • 키패드 누르기
      • 정수 내림차순으로 배치하기
    • Lv2
      • 행렬의 곱셈
      • 영어 끝말잇기
      • 영어 끝말잇기
      • N개의 최소 공배수
      • 피보나치 수
      • 124 나라의 숫자
      • 짝지어 제거하기
      • 프린터
      • 다음 큰 숫자
      • 최댓값과 최솟값
      • 최소값 만들기
      • 숫자의 표현
      • JadenCase 문자열 만들기
      • 오픈채팅방
      • 영어 끝말잇기
      • 멀쩡한 사각형
      • 올바른 괄호
      • 위장
      • 기능개발
      • 더 맵게
      • 스킬트리
    • 완전탐색
      • 모의고사(Lv1)
      • 카펫(Lv2)
      • 소수 찾기(Lv2)
    • 정렬(Sorting)
      • K번째 수(Lv1)
      • 가장 큰 수(Lv2)
      • H-Index(Lv2)
    • 해시(Hash)
      • 완주하지 못한 선수(Lv1)
      • 전화번호 목록(Lv2)
    • 탐욕법(Greedy)
      • 체육복(Lv1)
      • 큰 수 만들기(Lv2)
      • 구명보트(Lv2)
    • 동적계획법(DP)
      • 정수 삼각형(Lv3)
    • 깊이/너비 우선 탐색(DFS/BFS)
      • 타겟 넘버(Lv2)
      • 네트워크(Lv3)
      • 단어 변환(Lv3)
  • 스프링부트 책
    • Day 1
    • Day 2
    • Day 3
    • Day 4
    • Day 5
    • Day 6
    • Day 7
    • Day 8
    • Day 9
    • Day 10
    • Day 11
    • Day 12
    • Day 13
    • Day 14
    • Day 15
    • Day 16
    • Day 17
  • JPA 책
    • 프로젝트 세팅 및 기본설정
    • 영속성 관리 개념
    • 엔티티 매핑
      • 실습 예제
    • 연관관계 매핑 기초
      • 실습 예제
    • 다양한 연관관계 매핑
      • 다대일, 일대다 관계
      • 일대일, 다대다 관계
      • 실습 예제
    • 고급 매핑
      • 상속 관계 매핑
      • @MappedSuperclass
      • 복합 키와 식별 관계 매핑
      • 조인 테이블
    • 프록시와 연관관계 관리
      • 프록시
      • 즉시 로딩과 지연 로딩
      • 영속성 전이, 고아 객체
    • 값 타입
      • 임베디드 타입
      • 값 타입과 불변 객체
      • 값 타입의 비교, 컬렉션
    • 객체지향 쿼리 언어
      • JPQL part1
      • JPQL part2
      • JPQL part3
      • QueryDSL
      • NativeSQL
      • 객체지향 쿼리 심화
    • 응용 애플리케이션
      • 엔티티 설정
    • 스프링 데이터 JPA
      • 공통 인터페이스
  • Kotlin In Action
    • 코틀린의 특징
    • 코틀린의 기초
    • 함수 정의와 호출
    • 클래스, 객체, 인터페이스
    • 람다 방식
    • 코틀린 타입 시스템
    • 연산자 오버로딩과 기타 관례
    • 고차함수
    • 제네릭스
    • 애노테이션과 리플렉션
    • 코루틴
  • Oracle
    • Oracle 기본
    • Oracle 심화
  • SQL_연습
    • Revising the Select Query
    • Basic Select
    • Advanced Select
    • Basic Select 2
  • SQL 첫걸음(책)
    • Day 1
    • Day 2
    • Day 3
    • Day 4
    • Day 5
    • Day 6
    • Day 7
    • Day 8
    • Day 9
    • Day 10
    • Day 11
    • Day 12
    • Day 13
    • Day 14
    • Day 15
    • Day 16
    • Day 17
    • Day 18
    • Day 19
    • Day 20
    • Day 21
    • Day 22
    • Day 23
    • Day 24
    • Day 25
    • Day 26
    • Day 27
    • Day 28
    • Day 29
    • Day 30
  • 더 자바 코드를 조작하는 다양한 방법
    • JVM 이해하기
    • 바이트코드 조작
    • 리플렉션
    • 다이나믹 프록시
    • 애노테이션 프로세서
  • 더 자바, 애플리케이션을 테스트하는 다양한 방법
    • JUnit5
    • Mockito
    • 도커와 테스트
    • 성능, 운영이슈, 아키텍처 테스트
  • 이펙티브 자바
    • item1 - 생성자 대신 정적 팩토리 메소드를 고려하라
    • item2 - 생성자에 매개변수가 많다면 빌더를 고려하라
    • item3 - 생성자나 열거타입으로 싱글턴임을 보증하라
    • item4 - 인스턴스화를 막기 위해선 private 생성자를 사용하라
    • item5 - 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라
    • item6 - 불필요한 객체 생성을 피하라
    • item7 - 다 쓴 객체 참조를 해제하라
    • item8 - finalizer와 cleaner 사용을 피하라
    • item9 - try-finally 보다 try-with-resources을 사용하라
    • item10 - equals는 일반 규약을 지켜 재정의하라
    • item11 - equals을 재정의하려면 hashCode도 재정의하라
    • item12 - toString을 항상 재정의하라
    • item13 - clone 재정의는 주의해서 진행하라
    • item14 - Comparable을 구현할지 고민하라
  • Elastic Search
    • 강의 Summary
    • Elastic Summary 개념 정리
    • Elastic Summary 적용 정리
  • 토비의 스프링 강의
    • 스프링부트 살펴보기
    • 독립 실행형 서블릿 애플리케이션
  • k8s
    • minikube 설치
    • jenkins 추가
  • Article
    • Choosing the Right MessageBroker
Powered by GitBook
On this page

Was this helpful?

  1. 이슈 경험

20230220_트랜잭션

이번에 발생했었던 이유 사항에 대해서 정리해보자 계속해서 HikariCP 에서 deadlock으로 인해서 timeout 에러가 발생하고 있었다

우선 문제는 명확했다 우리 회사는 MSA 구조로 되어있는 터에 수 많은 컴포넌트들이 하나의 디비를 바라보고 있는 상황이다 물론 디비의 상세 구조를 내가 알고 있는 것은 아니라서 확실하게는 모르겠지만 수 많은 컴포넌트들이 하나의 디비를 바라보고 Connection pool 을 잡고 있어서 Connection pool이 가득찼던 이슈 사항이 있었다. 그래서 이걸 해소하기 위해서 개발계에서 많이 사용되는 컴포넌트가 아닌 사용량이 적어도 괜찮은 컴포넌트의 커넥션 풀을 줄이자는 이야기가 나왔다 물론 해당 작업은 본인이 진행하지는 않았지만 일정 컴포넌트의 Hickri의 connection pool size을 2개로 줄였다 해당 설정과 관련해서 수정한 config은 이하와 같다

spring.datasource.hikari.maximumPoolSize=2
spring.datasource.hikari.minimum-idle=2

일단 2개로 넣어둔 상황에서 지속해서 Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection 요 에러가 수우우우우우우도 없이 발생하고 있었다 그래서 자세한 로그를 확인해본 결과, 해당 에러는 HikariCP 에서 connection timeout이 발생했다고 말해주고 있었고, 해당 connection timeout은 hikari에서 connection pool을 찾는 도중에 deadlock이 발생하면서 나온 에러로 확인되었다

그럼 해당 에러를 재현해보자 해당 에러를 재현하기는 쉬웠다 하나의 api가 있는데 요것은 req부터 res까지 필요한 시간은 0.7초? 정도면 수행되는 api 였다 그런데 요 0.7초 내에 해당 api를 또 다시 호출하게되면 (같은 row에 접근하는 케이스가 아니더라도 괜찮았다) connection pool을 기다리다가 hikari에서 connection pool을 기다리는 기본 타임아웃 시간 초인 30초를 넘어가면서 타임아웃이 발생하게 되는 그런 상황이였다

해당 메소드의 내부 로직을 봐보면 이러하다 메인 메소드에서 데이터를 저장 >> @Async에서 데이터를 저장 >> @Transactional(propagation=REQUIRES_NEW) 에서 findById.ifPresent{it.카운트++} (근데 이게 저장까지 되는게 신기하네) >> 추가로 전에 작성한 findById에는 @Lock(LockModeType.PESSIMISTIC_WRITE)이 달려있었다 그래서 이 메소드들의 의심점을 가지고 무엇이 문제인지 확인해보았다

가장 처음으로 의심을 가져보려고 했던 것은 해당 컴포넌트에게 특별하게 길게 실행되는 쿼리가 있는가 였다 그야 당연히 connection pool size를 줄인 것은 좀 되었고 해당 컴포넌트에 개발건은 몇 개월동안 없었는데 왜 이제와서..? 갑자기 커넥션 풀을 잡지 못한다고 그러는걸까? 이에 대해 생각해본 답변은 그야 갑자기 요 컴포넌트에서 배치성으로 길게 돌거나 대용량 데이터를 밀어넣는 곳이 있을까 싶어서 내부 코드를 봤지만 따로 그런건 없었다

그럼 이제는 정말 로직적으로 이슈가 있다는 것에 의심을 가지기 시작했고 처음으로 의심을 가졌던 것은 @Async 메소드 부분이였다 사실 따로 @Async였기 떄문에 처음으로 의심을 가진 것은 아니구, 메인 메소드에서 save가 일어나는 부분 다음으로 관련된 메소드였기 떄문에 의심을 해보았다 실제로 저장하는 메소드가 @Async 내부에 존재하지는 않았지만 비동기 처리가 되게 되면 별도의 스레드가 하나 더 생기게 되고 비동기 처리로 인해서 생긴 스레드에서 connection pool을 요구하게 된다 그래서 connection pool을 얻기위해서 기다릴 것이라고 생각했었다 요걸 확인해보기 위해서 해당 @Async문을 삭제하고 다시 테스트를 진행해 봤지만? 결과는 같았다 곰곰히 생각해보면 비동기 메소드에서 connection pool을 얻기 위해서 hikariCP에서의 대기열인 blocking queue에 들어갔다고 한들, 원래의 메소드가 30초가 걸리지 않고 connection pool을 뱉어낼텐데 요건 문제가 아니겠거니 싶었다 간단하게 chatGPT에게 blocking queue에 대해서 물어보니 답변은 이러했었다 A blocking queue is a queue that blocks when you try to dequeue from it and the queue is empty, or when you try to enqueue items to it and the queue is full. A blocking queue uses locking and signaling mechanisms to provide a thread-safe, synchronized way for producer and consumer threads to communicate and synchronize with each other.

그럼 그 다음을 문제는 @Transactional(propagation=REQUIRES_NEW) 였는데 요거겠거니 했었다 @Transactional 애노테이션에 대해서는 한번 공부를 하긴 했었는데 간단하게 다시 한 번 정리해보자 @Transactional 이라는 애노테이션에서 주의해서 봐야하는 속성은 두 가지가 있다. 그 두 속성은 이러하다 > isolation, propagation 우선 isolation은, 격리 수준이라고 해당 트랜잭션의 격리 수준을 설정하는 설정이다 해당 속성에 들어갈 수 있는 값들은 레벨 낮은 순서부터 이러하다

  • lv0 - READ_UNCOMMITTED : 커밋되지 않은 데이터에 대한 읽기 허용

    • 요것의 문제는 Dirty Read가 발생할 수 있다는 점이 위험 사항이다. 여기서 dirty read란 다른 트랜잭션에서 어떤 데이터를 수정했지만 커밋하지 않은 상태에서 해당 데이터를 읽는 것이다. 만약에 dirty read가 발생하게 되면 수정하고 있는, 해당 데이터를 건들고 있는 다른 트랜잭션의 작업을 기다리지 않고 그 값을 사용해버리는 문제가 생긴다는 것이다

  • lv1 - READ_COMMITTED : 트랜잭션에서 커밋이 확정된 데이터만을 읽도록 허용

    • 요렇게만해도 lv0에서 발생할 수 있는 dirty read을 피하는 것이 가능하다

  • lv2 - REPEATABLE_READ : 트랜잭션이 어떠한 데이터를 읽을 때, 항상 해당 데이터를 데이터베이스에서 항상 바라보고 조회하는 것이 아니라 데이터베이스에서 제공하는 스냅샷을 기준으로 조회를 해준다 따라서 커밋이 되었다고 해서 바로 커밋된 데이터가 조회되는 것이 아니라 일정 시점의 스냅샷을 조회해서 내려준다

  • lv3 - SERIALIZABLE : 트랜잭션의 가장 높은 독립성을 제공하는 속성이다

    • lv1(READ_COMMITTED), lv2(REPEATABLE_READ) 요 2가지 레벨에서 발생할 수 있는 이슈인 phantom read를 방지하는 것이 가능하다

      • phantom read : 2개의 트랜잭션에서 하나에 자원에 접근한다고 생각했을 때, 하나의 트랜잭션에서 동일한 조회 쿼리를 날렸을 때 첫 번쨰 조회쿼리와 두 번쨰 조회쿼리가 다른 경우

    • 해당 격리수준으로 설정해두면, 단순 조회하는 쿼리을 실행해두 shared lock이 걸리게 됨으로 다른 트랜잭션에서 수정하거나 삭제하는 것이 불가능하다

      • shared lock : 읽기 잠금으로 동시에 읽는 것은 가능해도 수정하는 것은 불가능한 잠금 레벨이다

      • exclusive lock : 쓰기 잠금으로 해당 자원을 수정할 때, 해당 트랜잭션의 종료 전까지 다른 트랜잭션에서 수정이나 삭제는 당연하게 제한되지만 조회마저도 제한되는 그러한 잠금 레벨이라고 볼 수 있다

여기서 포인트는 해당 isolation lv은 디폴트가 >> 각 데이터베이스의 isolation lv에 따라서 설정이 된다 회사에서 사용하고 있는 오라클을 기준으로 보면 READ_COMMITTED 이구 MySQL은 REPEATABLE_READ이다

다음으로는 해당 트랜잭션의 전이 레벨이다. propagation 이라고도 불리운다 트랜잭션이 시작되고 해당 트랜잭션을 어떻게까지 사용할 것인가? 에 대한 속성으로 정의할 수 있으려나

  • REQUIRED(default) : 상위 메소드의 트랜잭션에 묶여서 실행되고 상위 메소드에서 트랜잭션이 종료되면 신규로 생성

  • REQUIRES_NEW : 새로운 트랜잭션에서 해당 메소드가 실행되도록 설정

  • MANDATORY : 상위 메소드에 트랜잭션이 없다면 에러를 던지고, 상위 메소드에서 트랜잭션이 있다면 조용하게 들어가서 실행 >> 종속적으로 사용해야하는 경우에 사용하는 듯

  • SUPPORTS : 상위에 트랜잭션이 있으면 들어가서 진행하지만 만약에 없다면 그냥 없는대로 실행

  • NOT_SUPPORTED : 트랜잭션을 사용하지 않도록 강제한다 > 만약에 상위에 트랜잭션이 있다면 대기시킨다

  • NEVER : 트랜잭션을 사용하지 않도록 강제한다 > 만약에 상위에 트랜잭션이 있다면 에러를 던진다

나머지 속성들도 readOnly, 롤백관련, timeout 관련이 있지만 이름 그대로 인것으로 보이니 자세한게 필요할 때 보쟈

우선 propagation 속성에서 REQUIRES_NEW 이라는 속성은 기존에 진행되던 트랜잭션 이외에 새로운 트랜잭션을 생성해서 진행하겠다는 의미이다 따라서 해당 애노테이션이 달려있는 메소드 내부에서는 새로운 트랜잭션이 실행되고 소스코드에서 해당 메소드 내부에서는 findById.ifPresent{ it.카운트++ }가 되어있었는데 여기 메소드에서 새로히 connection pool을 얻고 디비를 조회하고 수정을 하고 update 쿼리를 날리는 로직이다. 그러면 결국은 여기에서 새로히 connection pool을 요청하게 되는 결과이고, 하나의 큰 메소드에서 총 2개의 connection pool을 요한 다는 것을 확신할 수 있었다

그래서 요걸 어떻게 해결할 것인가에 대해서 고민을 해보았다 우선은 REQUIRES_NEW가 들어간 부분에서 이슈가 있었기 떄문에 요걸 지우고 테스트를 해보니 잘 되었었지만 본인이 만든 코드도 아니고 해당 코드에 이유가 있어서 그렇게 애노테이션을 달아두었을 것이기 때문에 소스 코드를 수정하는 것은 불가능했다 그렇기 떄문에 적어도 4개의 conenciton pool이 필요하다고 판단했고 맨 처음에 설정해두었던 connnection pool의 사이즈를 2개에서 4개로 늘렸고 4개로 늘려둔 상황에서 REQUIRES_NEW을 통한 테스트도 정상적으로 통과하게 되었다

정말 분석하는데 트랜잭션에 대한 개념도 다시 한번 고민하게 되는 시간이였고, 맨 처음에 REQUIRES_NEW 을 유지하면서 교착상태를 해결하기 위해서 isolation level을 건드려보려고 했었지만 해당 방법을 사용하는 것은 위험한 방법이라고 들었다 그래도 이김에 isolation level에 대해서 배울 수 있는 시간이였다

원래는 dead lock을 방지하기 위해서 @Lock을 통해서 진행해보려고 까지 생각했었다. 다시 생각해보면 @Lock까지 갈 필요도 없는 문제였는데 단순히 내가 @Lock의 lockMode에 대해서 자세하게 알지 못했기 때문에 그렇게까지 생각이 진행되었던 것 같다 이 귀중한 기회를 날리지말고 공부할 수 있는 시간으로써 @Transactional, @Lock에 대해서 정리 다시 한 번 해보도록 하자

Previous이슈 경험Next20230306_캐싱이슈

Last updated 2 years ago

Was this helpful?

그래서 어디에서 dead lock이 발생해서 타임아웃이 나는가? 에 대해서 고민해보았는데 생각해보면 이렇다 처음에 언급한 api을 0.7초 내로 동시에 2개를 전송하게 되면 각각의 api가 시작되면서 메인 엔티티를 저장하기 위해서 conneciton pool 을 각각 하나씩 총 2개의 커넥션 풀을 사용하게 된다 그 상황에서 메소드가 끝나지 않은 상황에서 @Transactional(propagation=REQUIRES_NEW)을 통해서 새로운 트랜잭션을 시작하고 그 새로운 트랜잭션에서 동기적으로 conneciton pool을 얻기 위해서 hikariCP의 connection 대기 시간의 최대치인 30초를 기다리게 되는데, 애초에 처음에 메인 엔티리를 저장하기 위해서 열어두었던 connection pool 2개가 원래라면 메소드가 종료됨에 따라서 connection pool을 반납해야만 하지만 해당 메소드가 끝나지 않았기 떄문에 계속해서 connection pool을 열어둔 상황으로 기다리는 것이고 그럼 각각에서 REQUIRES_NEW로 파생된 트랜잭션에서 30초를 기다리다가 타임아웃이 발생하게 된 것이다!!!

img.png