항해99 플러스 백엔드 1주차 WIL - TDD 와 동시성

2024. 9. 28. 15:48· 교육 | 외부활동/항해99 플러스 백엔드
목차
  1. 1주차 WIL
  2. DB없는 단일 인스턴스 환경에서의 동시성 대응 방안
  3. 내가 구현한 동시성 대응 방안
  4. 동시성을 테스트하는 여러 가지 방법
  5. 회고
  6. 항해99 회고
반응형

1주차이니 플러스백엔드 코스에 대해 간단하게 설명부터 하자면,

항해 99 플러스 백엔드는 현재 재직중인 주니어 개발자들을 대상으로 10주간 기본기를 탄탄하게 다지고, 실무 중심으로 과제를 하나하나 해결해 나가는 코스이다.

https://hanghae99.spartacodingclub.kr/plus/be

[항해 플러스, 도전을 넘어 개발자 커리어 도약으로

백엔드 주니어 개발자로서 성장의 한계를 느끼고 있다면, 시니어 코치진과 함께 10주 몰입을 통해 도약하세요.

hanghae99.spartacodingclub.kr](https://hanghae99.spartacodingclub.kr/plus/be)

첫주차 발제 내용은 TDD(근데 이제 동시성을 곁들인..)였고, 주말동안 계속 밤을 새서 코드를 구현했다..

화요일에는 헬스 PT가 있었는데 월요일 저녁까지 밤을 새버려서 PT쌤한테 몸상태가 좋지 못해서 못갈것 같다고도 했었다.. (밤새느라 몸상태가 안좋은건 맞으니까..)

1주차 WIL

동시성에 대해서 공부가 많이 필요했다.

그래서 김영한 강사님의 실전 자바 프로그래밍을 참조를 많이 했다.

https://www.inflearn.com/course/%EA%B9%80%EC%98%81%ED%95%9C%EC%9D%98-%EC%8B%A4%EC%A0%84-%EC%9E%90%EB%B0%94-%EA%B3%A0%EA%B8%89-1

[김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성 강의 | 김영한 - 인프런

김영한 | 멀티스레드와 동시성을 기초부터 실무 레벨까지 깊이있게 학습합니다., 국내 개발 분야 누적 수강생 1위, 제대로 만든 김영한의 실전 자바[사진][임베딩 영상]단순히 자바 문법을 안다?

www.inflearn.com](https://www.inflearn.com/course/%EA%B9%80%EC%98%81%ED%95%9C%EC%9D%98-%EC%8B%A4%EC%A0%84-%EC%9E%90%EB%B0%94-%EA%B3%A0%EA%B8%89-1)

대표적으로 멀티쓰레드 환경(특히 스프링) 에서는 여러 스레드가 변경 가능한 공유 데이터를 동시에 수정하려 할 때 경쟁조건(Race Condition)이 발생한다. 자바에서는 이러한 경쟁조건을 회피할 수 있도록 여러가지 동기화 대응 방안이 있다.

DB없는 단일 인스턴스 환경에서의 동시성 대응 방안

동시성 제어에는 Syncronized, LockSupport, ReentrantLock에 대해 먼저 공부했다.

Syncronized 키워드

자바에서 가장 기본적인 동기화 방법이다. 특정 코드 블록이나 메서드에 대해 한 번에 하나의 스레드만 접근할 수 있도록 보장한다.

장점으로는, 프로그래밍 언어에 문법으로 제공한다는 것과, 편리하게 사용할 수 있다는 점, 그리고 자동 잠금해제가 된다는 것이다.

자동 잠금 해제는 syncronized 메서드나 블록이 완성되면 자동으로 락을 대기중인 다른 스레드의 잠금이 해제된다. 개발자가 직접 특정 스레드를 깨우도록 관리해야 된다면 매우 어렵고 번거로울 것이다.

하지만 큰 단점들이 존재하는데, 바로 무한 대기와 데드락 문제와 공정성 문제이다.

  1. 무한 대기 상태 : 한 스레드가 syncronized 블록을 장기간 점유하게 되면 다른 스레드들이 영원히 대기할 수 있다. BLOCKED 상태의 쓰레드는 락이 풀릴때까지 무한 대기하는 특징 때문
  2. 공정성 문제 : 락이 돌아왔을 때 BLOCKED 상태의 여러 쓰레드 중에 어떤 쓰레드가 락을 획득할 지 알 수가 없다. 최악의 경우에는 특정 스레드가 너무 오랜기간 락을 획득하지 못할 수도 있다고 한다.

syncronized의 가장 치명적인 단점은 락을 얻기 위해 BLOCKED 상태가 되면 락을 얻을 때까지 무한 대기한다는 점이다. 예를 들어 고객이 어떤 요청을 했는데, 화면이 계속 요청 중만 뜨고, 응답을 못 받는 것이다.

결국 더 유연하고, 더 세밀한 제어가 가능한 방법들이 필요하게 되었다., 이런 문제를 해결하기 위해 자바 5부터 java.util.concurrent라는 동시성 문제 해결을 위한 패키지가 추가된다.

단순하고 편리하게 사용하기는 참 좋다. 목적에 맞게 쓰도록 하는 것이 좋을 것 같다.

LockSupport

syncronized의 단점을 보완하기 위해 자바 5에 나타난 녀석.

쓰레드를 WAITING 상태로 변경한다. WAITING 상태는 누가 깨워주기 전까지는 계속 대기한다. 그리고 CPU 실행 스케줄링에 들어가지 않는단다.

저수준의 락 관리 기능을 제공한다. 특히 쓰레드를 직접 차단하고 깨우는 기능이 있어서 무한 대기 문제를 해결할 수 있다고 한다.

LockSupport의 존재 자체도 몰랐는데, 팀원분께서 이런 것도 있다고 하셔서 좋은 공부가 되어가고 있다. (그 분은 1주차가 끝나고 하차하셨다.. ㅠㅠ)

장점으로는 인터럽트를 사용할 수 있다는 것이다. WAITING 상태의 쓰레드에 인터럽트가 발생하면 RUNNABLE 상태로 변하면서 꺠어난다.

이것도 단점이 있다. 바로 저수준의 기능만 존재한다는 것이다.

저수준의 기능 : 매!우! 저수준의 락 관리 매커니즘을 제공해서 코드가 복잡해질 수 있다고 한다.

무슨 기능이 있는지 알아보자.

park : 쓰레드를 WAITING(대기) 상태로 변경한다.

parkNanos(나노초) : 쓰레드를 나노초동안만 TIMED_WAITING 상태로 변경한다.

unPark(쓰레드) : WAITING 상태의 대상 쓰레드를 RUNNABLE 상태로 변경한다.

ReentrantLock

자바5부터 도입된 고급 락 매커니즘으로 syncronized의 단점을 보완하기 위해 나타난 녀석. BLOCKED 상태를 통한 임계 영역 관리의 한계를 극복하기 위해 만들어졌다고 한다.

특징으로는 무한대기 방지, 공정성, 다양한 기능이 있다.

  1. 무한 대기 방지 : tryLock 메서드를 사용해서 일정 시간 동안만 락을 시도하고, 실패할 경우 대기하지 않도록 할 수 있다. (무한대기 회피 전략이라고 한다)
  2. 공정성 : 공정성을 보장할지의 여부를 설정 가능하다. 공정성이 설정되면 락을 먼저 요청한 쓰레드가 우선적으로 락을 획득할 수 있도록 한다.
  3. 다양한 기능 : syncronized보다 훨씬 많은 기능이 내장되어 있다. 락을 명시적으로 획득, 해제 가능하다. 재진입도 가능하고 대기 중인 쓰레드를 인터럽트하거나 위에 말했듯 시간을 설정하여 락을 시도하는것도 가능하다.

자바5에서 등장한 Lock 인터페이스와 ReentrantLock 덕분에 synchronized의 단점인 무한 대기와 공정성 문제를 극복하고, 또 더욱 유연하고 세밀한 쓰레드 제어가 가능하게 되었다.

내가 구현한 동시성 대응 방안

과제 목표 중 유저별로 락을 관리할 수 있게 구현해야 한다고 써있엇다. 여러 조사를 해본 결과, ReentrantLock과 ConcurrentHashMap을 사용해서 유저별로 락을 걸 수 있도록 하였다.

각 USER_ID에 대해 별도의 락을 관리하는 것으로 단일 인스턴스에서 여러 스레드가 동일한 유저아이디에 대해 순차적으로 작업을 수행하도록 보장 가능하다.

ConcurrentHashMap은 HashMap과 같지만, 각 요소에 대한 get/set 연산이 key별로 syncronized로 제어된다. 고로 Thread-safe하다고 한다. (-허재 코치님 멘토링 중-)

이렇게 ConcurrentHashMap을 사용한 락 관리 기능을 스프링 컴포넌트로 분리하고, 서비스 계층에서 이를 주입받아 사용하도록 구현했다.

@Component
public class LockManager {

    private final Map<Long, Lock> locks = new ConcurrentHashMap<>();

    public Lock getLock(Long id) {

    //이 코드는 id가 맵에 존재하지 않으면, 새로운 ReentrantLock을 생성하고 맵에 저장한다. id가 이미 존재하면 해당 키에 매핑된 기존의 ReentrantLock을 반환한다.
        return locks.computeIfAbsent(id, key -> new ReentrantLock()); 
    }

}

동시성을 테스트하는 여러 가지 방법

1. CompletableFuture를 사용하는 방법

CompletableFuture는 자바 8부터 도입된 비동기 프로그래밍을 지원하는 클래스이다.

비동기 작업을 수행하고 그 결과를 처리할 수 있게 해주는 도구로, 여러 스레드를 사용하여 병렬 작업을 쉽게 구현할 수 있다. 그리고 콜백을 통해 작업 완료 후 후속 작업을 정의할 수 있는 기능을 제공한다.

CompletableFuture의 join() 메서드는, 이러한 비동기 작업이 모두 마칠때까지 기다리는 메서드로, 동시성 테스트하기 위해 적합한 메서드이다.

        for (int i = 0; i < 5; i++) {
            tasks.add(CompletableFuture.runAsync(() -> pointService.charge(USER_ID_2, 500L)));
        }
        CompletableFuture<Void> allTasks = CompletableFuture.allOf(
            tasks.toArray(new CompletableFuture[0]));
        allTasks.join();

2. CountdownLatch를 사용하는 방법

CountDownLatch는 자바의 concurrent패키지에 속한 클래스 중 하나로, 여러 쓰레드가 특정 작업을 완료할 때까지 대기하게 하는 동기화 도구이다.

이를 통해 특정 조건이 만족될 때까지 한 쓰레드 또는 여럿 쓰레드가 기다리도록 설정할 수 있다.

ExecutorService를 활용해서 쓰레드 풀을 선언하고, 카운트다운으로 하나씩 줄여주면서 테스트를 하면 된다.

execute는 반환값 없을때, submit은 반환값 있을때 사용

CountDownLatch latch = new CountDownLatch(taskCount);
    ExecutorService executorService = Executors.newFixedThreadPool(taskCount);
    // 비동기 작업 수행
    executorService.execute(() -> {
        try {
            pointService.charge(USER_ID_1, 2000);
        } finally {
            latch.countDown(); // 작업 완료 후 latch 카운트 감소
        }
    });
    executorService.execute(() -> {
        try {
            pointService.use(USER_ID_1, 1000);
        } finally {
            latch.countDown(); // 작업 완료 후 latch 카운트 감소
        }
    });
    // 모든 작업이 완료될 때까지 대기
    latch.await();

    // ExecutorService 종료
    executorService.shutdown();

회고

발제는 STEP1과 STEP2로 나누어져 있었다.

STEP1은 제공해준 스켈레톤 프로젝트(DBx 단일 인스턴스 환경)에 유저 포인트 어플리케이션을 동시성을 고려해서 구축해보고, 단위테스트와 통합테스트를 구현해보는 것이었고, STEP2는 그에 대한 공부내용 정리 및 보고서를 작성하는 것이었다.

정말 운이 좋게도 허재 코치님께서 STEP2에 우수과제로 선정해주셨다!!

2주차 발제 내용은 클린 아키텍처이다. 발제 내용과 녹화본을 보면서 이번에도 패스 받도록 열심히 해봐야겠다..

항해99 회고

1. 문제 (과제, 프로젝트를 진행하면서 부딪혔던 기술적인 문제)

이번 주차를 지나며 겪었던 문제가 무엇이었나요?
동시성에 대해 아무것도 몰랐다.

2. 시도

문제를 해결하기 위해 어떤 시도를 하셨나요?
발제 영상과, 김영한의 실전자바 인프런 인강에 나온 동시성 부분을 계속 시청했다.

3. 해결

문제를 어떻게 해결하셨나요?
블로그 레퍼런스와 멘토링에서 꿀팁을 많이 주웠다.

4. 알게된 것

문제를 해결하기 위해 시도하며 새롭게 알게된 것은 무엇인가요?
동시성 테스트


Keep : 현재 만족하고 계속 유지할 부분

이번 주를 마무리 하며 나에게 만족했던 부분은 무엇인가요?
TDD에 대해 익숙해진 것

Problem : 개선이 필요하다고 생각하는 문제점

이번 주를 마무리 하며 개선이 필요하다고 생각했던 문제점은 무엇인가요?
P1. TDD 더 공부하자

Try : 문제점을 해결하기 위해 시도해야 할 것

이 문제점을 해결하기 위해 다음 한 주간 시도 할 것은 무엇인가요?

P1.TDD 공부

반응형

'교육 | 외부활동 > 항해99 플러스 백엔드' 카테고리의 다른 글

Index를 통한 쿼리 성능개선 - 8주차  (1) 2024.11.12
캐시 및 Redis 대기열 이관 - 7주차 WIL  (0) 2024.11.10
콘서트 예약 서비스에서의 동시성 이슈 해결 방안 분석 및 성능 테스트 - 6주차 WIL  (0) 2024.10.30
항해99 플러스 백엔드 Chapter2(3,4,5주차) 회고 및 WIL  (8) 2024.10.25
항해99 플러스 백엔드 2주차 WIL - 클린아키텍처와 동시성  (0) 2024.10.04
  1. 1주차 WIL
  2. DB없는 단일 인스턴스 환경에서의 동시성 대응 방안
  3. 내가 구현한 동시성 대응 방안
  4. 동시성을 테스트하는 여러 가지 방법
  5. 회고
  6. 항해99 회고
'교육 | 외부활동/항해99 플러스 백엔드' 카테고리의 다른 글
  • 캐시 및 Redis 대기열 이관 - 7주차 WIL
  • 콘서트 예약 서비스에서의 동시성 이슈 해결 방안 분석 및 성능 테스트 - 6주차 WIL
  • 항해99 플러스 백엔드 Chapter2(3,4,5주차) 회고 및 WIL
  • 항해99 플러스 백엔드 2주차 WIL - 클린아키텍처와 동시성
wn1331
wn1331
반응형
wn1331
JONGHUN
wn1331
전체
오늘
어제
  • 분류 전체보기 (268)
    • Spring (16)
      • Spring Data JPA (0)
      • Spring Security (11)
      • Spring Batch (5)
    • DEV (40)
      • FrontEnd (2)
      • JAVA (5)
      • Git (1)
      • 기타 (6)
      • Network (1)
      • MSA (12)
      • 개발일기 || 트러블슈팅 (5)
      • 행사 || 후기 (3)
      • GraphQL (3)
      • Kotlin (0)
      • Database (2)
    • 코딩테스트 (164)
      • Programmers_LV0 (100)
      • Programmers_LV1 (54)
      • 백준 (8)
      • Algorithm (1)
    • 교육 | 외부활동 (44)
      • 이론_JAVA (13)
      • ORACLE (12)
      • PUBLISHING (6)
      • JAVASCRIPT (5)
      • JQuery (0)
      • 항해99 플러스 백엔드 (8)
    • 기본지식 (0)
    • 끄적끄적 (3)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

  • 학부생(용인대학교 컴퓨터과학과 1~4학년) 네이버 블로그는⋯

인기 글

태그

  • SESSION
  • 항해99
  • 항플 백엔드
  • 압축
  • spring security
  • JPA
  • 세션
  • java
  • MySQL
  • 항해플러스
  • Step
  • 스프링 부트
  • MSA
  • Spring Batch
  • 스프링 시큐리티
  • 항플
  • Spring Boot
  • 스프링
  • Spring
  • transaction

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.2
wn1331
항해99 플러스 백엔드 1주차 WIL - TDD 와 동시성
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.