Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[refactor] : global에서의 의존성을 제거하고, 닉네임 중복 확인 시 분산 락을 활용한다 #87

Merged
merged 2 commits into from
Nov 23, 2024

Conversation

bbbang105
Copy link
Member

@bbbang105 bbbang105 commented Nov 23, 2024

✅ PR 유형

어떤 변경 사항이 있었나요?

  • 새로운 기능 추가
  • 버그 수정
  • 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경)
  • 코드 리팩토링
  • 주석 추가 및 수정
  • 문서 수정
  • 빌드 부분 혹은 패키지 매니저 수정
  • 파일 혹은 폴더명 수정
  • 파일 혹은 폴더 삭제

📝 작업 내용

이번 PR에서 작업한 내용을 간략히 설명해주세요(이미지 첨부 가능)

  • 아래의 코드 리뷰 코멘트를 해결하고자 하였습니다.
  1. [A팀] 백엔드 파트 코드리뷰용 PR #44 (comment)
의존성이 global <-> auth 처럼 되어있는것 같은데요.
global이라는 네이밍과 내부 클래스들을 봤을때, 모든 도메인에서 참조하는 공통 로직을 넣어주신거 global -> auth로 의존성이 생기면 어떤 단점이 있을까요?

global 패키지 하위에 있는 RedisManagerCookieUtilAuthErrorStatus를 사용하면서 global -> auth로의 의존성이 발생했습니다. 이는 추후 순환 참조 문제 등이 발생할 수 있기에, ErrorStatus로 코드를 이동시키면서 해결하고자 하였습니다.

  1. [A팀] 백엔드 파트 코드리뷰용 PR #44 (comment)
2명의 유저가 동시에 A라는 이름으로 중복확인을 하고 한명이 먼저 가입해버린다면 어떻게 될까요?
두명의 유저 모두 사용가능한 닉네임 이라는 응답을 받겠지만 늦게 가입을 누른 한명은 가입 중간에 에러를 보게될겁니다.

그냥 에러를 보게 하고 재입력하게 해도 되지만, 닉네임 체크를 할때 정책에 따라 분산락을 획득한다든지 하는 재밌는 방식으로 풀어낼수도 있을거 같아요.

코드 리뷰에서 언급해 주신 문제 상황 (동시성 문제)를 처리하기 위해서, Redis를 활용한 분산 락을 구현했습니다.

DistributedLockManager

@Component
@RequiredArgsConstructor
public class DistributedLockManager {
    private final StringRedisTemplate redisTemplate;

    /**
     * 분산락 획득 시도.
     *
     * @param lockKey   락 키
     * @param timeoutMs 락 만료 시간 (밀리초)
     * @return 락 획득 여부
     */
    public boolean acquireLock(String lockKey, long timeoutMs) {
        Boolean isLocked = redisTemplate.opsForValue().setIfAbsent(lockKey, "LOCKED", timeoutMs, TimeUnit.MILLISECONDS);
        return Boolean.TRUE.equals(isLocked);
    }

    /**
     * 분산락 해제.
     *
     * @param lockKey 락 키
     */
    public void releaseLock(String lockKey) {
        redisTemplate.delete(lockKey);
    }
}

분산 락과 관련된 로직을 하는 클래스입니다.

  1. 락 키 (닉네임)를 가지고 Redis에 set을 시도하며, 이미 존재할 시 (누군가 5초 이내로 동일한 닉네임 중복 확인을 한 경우)에는 false를 반환합니다.
  2. 분산락 해제 메서드의 경우에는 해당 닉네임이 최종적으로 허용된 경우에만 호출됩니다.

UserService

...

private static final long LOCK_TIMEOUT = 5000; // 5초

...

    /**
     * 닉네임 중복 확인.
     *
     * @param request 닉네임 중복 확인 요청 정보
     */
    @Transactional
    public void checkNickname(CheckNicknameRequestDto request) {
        String nickname = request.nickname();
        String lockKey = "lock:nickname:" + nickname;

        // 1. 락 획득 시도
        if (!distributedLockManager.acquireLock(lockKey, LOCK_TIMEOUT)) {
            throw new CustomException(UserErrorStatus._DUPLICATED_NICKNAME);
        }

        try {
            // 2. 닉네임 중복 확인
            User user = userRepository.findByNickname(nickname);
            if (user != null) {
                throw new CustomException(UserErrorStatus._DUPLICATED_NICKNAME);
            }

            log.info("닉네임 사용 가능: {}", nickname);
        } finally {
            // 3. 락 해제
            distributedLockManager.releaseLock(lockKey);
        }
    }
  1. 락 획득 시도에서, false가 반환된 경우에는 중복된 닉네임이라는 에러를 반환합니다.
  2. 해당 닉네임이 DB에 존재하는지 확인합니다.
  3. 최종적으로 사용 가능한 닉네임이라면, 락을 해제하며 로직을 종료합니다.
  4. 5초로 유효 기간을 지정했기에, 5초가 지나면 자동으로 Redis에서 제거됩니다

✏️ 관련 이슈

본인이 작업한 내용이 어떤 Issue Number와 관련이 있는지만 작성해주세요

#78


🎸 기타 사항 or 추가 코멘트

지금과 같은 분산락 방법에는 여러 허점들이 존재해서, Redis에서 제공하는 Redlock 이라는 알고리즘을 사용한다고 합니다.
이를 구현하고자 했지만 아직 이해도가 낮은 것 같아 추후 학습 후 도입해보려고 합니다!

Redlock 참고 블로그1
Redlock 참고 블로그2

@bbbang105 bbbang105 added 🚀 feat 새로운 기능 추가 / 일부 코드 추가 / 일부 코드 수정 (리팩토링과 구분) / 디자인 요소 수정 🔄 refactor 코드 리팩토링 🤯 SANGHO 상호 Issue or PR labels Nov 23, 2024
@bbbang105 bbbang105 requested a review from juuuunny November 23, 2024 19:00
@bbbang105 bbbang105 self-assigned this Nov 23, 2024
Copy link
Contributor

@juuuunny juuuunny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 수고하셨어요!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

분산락 개념은 처음 들어보는데 신기한 개념이네요.
락과 관련하여 이후에 공부해봐야할 것 같네요.
수고하셨습니다!!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

같이 공부해봅시다!!

@bbbang105 bbbang105 merged commit d8583db into refactor-v1 Nov 23, 2024
@bbbang105 bbbang105 deleted the feature/#78/refactor-cookieutil branch November 23, 2024 21:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🚀 feat 새로운 기능 추가 / 일부 코드 추가 / 일부 코드 수정 (리팩토링과 구분) / 디자인 요소 수정 🔄 refactor 코드 리팩토링 🤯 SANGHO 상호 Issue or PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants