LostCatBox

hanghae-6week

Word count: 790Reading time: 4 min
2025/04/26 1 Share

6주차 발표 요약

  • 코드 리뷰
    • 코드 리뷰 -> 공동 목표 필요, 일관된 방향, 분리된 토픽으로 커밋단위로 리뷰
  • countdownlatch
    • 동시성 테스트툴
    • 사용법(excute and finally-> countDown() 필요)

6주차 발제

  • 6주차부터 대용량 트래픽부터는 커리어에 매우 도움이 많이 될것이다.
  • 5주차까지는 DB락 제어-> 낙관적락과 비관적락을 사용하는가.
    • 낙관적락은 충돌이 많이 발생하지않는경우, 빠른 피드백이 필요한 경우, 실패해도 되는경우
      • retry 관련 로직은 application에서 비즈니스 로직에 존재
    • 비관적락은 충돌이 많이 발생하는경우, 반드시 성공해야하는 경우
      • DB 에서 대기 및 실행, 성능적으로는 확실히 비관적락이 빠름.
  • 만약 DB가 여러개

이번주 목표

  • DB 트랜잭션 이상의 범위, 분산 환경에서 Lock을 적용할수있는 방법 학습
    (DB가 여러개라던지 MSA구조라던지)
  • 분산락 : DB에 의존하지않는 원자성 보장, 논리적 트랜잭션 구현

REDIS를 사용한 분산락

  • 한번 락 획득후 실행

    • try lock -> SETNX-> key값 세팅, 기존 값 존재시 false
    • unlock -> DEL -> key값에 대한 값 지움
  • 이를 활용해,

    • simple lock

      • 락 획득 여부 = redis 에서 key 로 확인
        if (락 획득) {
            try {
              로직 실행
            } finally {
              lock 제거
            }
        } else {
          throw Lock 획득 실패 예외
        }
        
        1
        2
        3
        4
        5
        6

        - 단점: retry가 없음

        - spin lock

        -
        재시도 횟수 = 0 while (true) { 락 획득 여부 = redis 에서 key 로 확인 // SETNX key "1" if (락 획득) { try { 로직 실행 } finally { lock 제거 } break; } else { 재시도 횟수 ++ if (재시도 횟수 == 최대 횟수) throw Lock 획득 실패 예외 시간 지연 ( 대기 ) } }
        1
        2
        3
        4
        5
        6

        - 단점: while true기때문에 불필요한 io많이생김

        - pub/sub 등의 방식으로 redis를 활용

        -
        락 획득 여부 = redis 에서 lock 데이터 에 대한 subscribe 요청 및 획득 시 값 반환 // 특정 시간 동안 Lock 에 대해 구독 if (락 획득) { 로직 실행 } else { // 정해진 시간 내에 Lock 을 획득하지 못한 경우 throw Lock 획득 실패 예외 }
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25

        - redis가 Lock 획득에 대한 대기열 제공해줌

        - 레디스의 락에 대해서는 반드시 하위 양식을 따르자

        - 락획득 -> 트랜잭션 시작-> 비즈니스 로직(조회 등등) -> 트랜잭션 종료 -> 락해제



        ## redis는 구현

        - aop로 분산락을 구현해볼것이다.
        - 레디스의 락에 대해서는 반드시 하위 양식을 따르자
        - 락획득 -> 트랜잭션 시작-> 비즈니스 로직(조회 등등) -> 트랜잭션 종료 -> 락해제



        ## kafka messaging

        - 메시지 큐와 같이 순서 보장이 가능한 장치를 이용해 동시성 이슈 해결가능(순서 대로 처리됨으로 경쟁하지않으니까)
        - 반드시 토픽의 key가 같아야지만 동일한 patition로 들어가므로 순서보장됨



        ## redis에대해서 다시 생각해볼것
        Redis 등을 활용한 외부 Resource 를 통해 불필요한 DB Connection 까지 차단 가능하다. 하지만 관리주체가 DB + Redis 와 같이 늘어남에 따라 다양한 문제 파생으로 이어진다. 또한 Lock 의 관리주체가 다운되면 서비스 전체의 Down 으로 이어질 수 있는 문제가 있다.

하지만 Redis 의 높은 원자성을 활용해 프로세스 처리단위에 대한 동일한 Lock 을
여러 인스턴스에 대해 적용할 수 있으므로 매우 효과적일 수 있고, DB 의 Conection 이나
오래 걸리는 I/O 에 대한 접근 자체를 차단할 수 있으므로 DB 에 가해지는 직접적인 부하를
원천 차단할 수 있으므로 효과적이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

- 현업에서는 master-slave 2개로 클러스터 구성하는 것이 바람직함.
- 실무에서는 메모리 부족 등등으로 인해, 갑자기 redis가 꺼질 수 있음

- master-slave 클러스터 반드시 개발해보기



### redis 분산락 예시에서 문제점 찾아보기

- 문제점이 있는 분산락 예시

```java
@Transactional
public void charge(Long userId, BigDecimal point) {
RLock lock = redissonClient.getLock("userChargeLock")

try {
if(lock.tryLock() == true) {
User user = userRepository.findById(userId)
user.charge(point)
} else {
throw new LockAccruedFailedException();
}
} finally {
lock.unlock();
}
}

@Transactional
public void pay(Long userId, BigDecimal point) {
RLock lock = redissonClient.getLock("userPayLock")

try {
if(lock.tryLock() == true) {
User user = userRepository.findById(userId)
user.pay(point)
} else {
throw new LockAccruedFailedException();
}
} finally {
lock.unlock();
}
}
  • 문제점

    • 트랜잭션과 락의 순차보장이 실패해요.
    • 충전과 결제가 동시에 수행 가능해요.(getLock({lock-name})) 다름

caching

  • 적은 부하로 API 응답을 빠르게 처리하기 위해 캐싱을 사용

  • 데이터를 임시로 복사해두는 Storage 계층

  • Server Caching 전략

    • application level 메모리 캐시
    • 애플리케이션의 메모리에 데이터를 저장해두고 같은 요청에 대해 데이터를 빠르게 접근해 반환함으로서 API 성능 향상 달성

caching Strategy

  • 캐싱 전략이 중요함.
    • expiration(사용자 입장에서는 지연발생)(TTL 세팅)
      • 캐시 데이터의 유통기한을 두는 방법
      • Lifetime 이 지난 캐시 데이터의 경우, 삭제시키고 새로운 데이터를 사용가능하게 함
    • Eviction(정책에 따라 명시적으로 캐시지우고, 채움 -> 사용자 입장에서는 지연거의없음)
      • 캐시 메모리 확보를 위해 캐시 데이터를 삭제
      • 명시적으로 캐시를 삭제시키는 기능
      • 특정 데이터가 Stale 해진 경우 ( 상한 경우 ) 기존 캐시를 삭제할 때도 사용

6주차 발제 추가정보

  • 애플리케이션 메모리 캐시와 Redis 캐시, 어떤 걸 언제 선택해야 하나요?
    • 강의 다시 보기
    • testContainer를 통해 redis를 따로 띄워서 test진행하기
  • 쿠버네틱스 docker안에서 redis캐시를 두는것을 추천함.
    • aws등등을 사용하게되면 네트워크 비용이큼. 정책도 한정됨, 자유도낮음
  • 외부시스템(redis) 를 적용하고 테스트를 진행할 때, 주의해야할 것들이 혹시 있을까요?
  • 레디스 카프카 사용하는이유?
    • Valkey 벌키도

https://zoom.us/rec/play/8mDY1MGFyCCqFPTQQ1po0wvqoGhOum2p_tslBuigGzC0qtk2Uksg1twEQVPABh-UwYf8w_Rjx_0G-X7S.W12YRIV2TCP0fQun?accessLevel=meeting&canPlayFromShare=true&from=share_recording_detail&continueMode=true&componentName=rec-play&originRequestUrl=https%3A%2F%2Fzoom.us%2Frec%2Fshare%2FHWlMYOMUsM_lpk5RHuXUMDGvjATCba9NLMgLSvoSUNxR3OrFNDHk4EoqmfUAB9ES.KB9p1cY43kX8w3Xt

CATALOG
  1. 1. 6주차 발표 요약
  2. 2. 6주차 발제
  3. 3. caching
  4. 4. caching Strategy
  5. 5. 6주차 발제 추가정보