Spring

[Redis] Redisson 분산 락을 간단하게 적용해보기

2023. 11. 7. 09:24
목차
  1. 문제 상황
  2. Lock
  3. 분산락 구현을 위한 Redis 사용
  4. RLock 라이브러리
  5. 락 획득 : tryLock
  6. 락 획득과 반납 코드
  7. Redis 설정
  8. Redis 설치
  9. build.gradle implementation
  10. application.properties
  11. Configuration
  12. 실제 사용 예제

문제 상황


어떤 데이터에 대해 매우 빠르게 수정이 일어날 때 동시성 문제가 발생할 수 있다.

예를 들어 A라는 데이터를 수정하는 로직이 0.1초 소요되는데, 0.001초 간격으로 A라는 데이터를 수정하는 요청이 여러 번 들어왔을 때 값이 제대로 수정되지 않을 수 있다.

이럴 때, DB 데이터 수정의 순차적 처리를 보장하기 위한 방법으로 Lock이 있다.

Lock

트랜잭션 락과 비슷한 개념으로 어떤 데이터 수정, 접근 등에 Lock을 필요로 하게 설정하는 것이다.

데이터를 수정하려면 우선 Lock을 획득하고 수정 후에 Lock을 반납한다.

만약 Lock을 획득할 수 없는 상황에서는 Lock을 획득할 수 있을 때까지 대기하거나 수정을 취소할 수 있다. 

분산 락(Distributed Lock)

하나의 공유 자원에 대한 경쟁 상황에서 데이터에 접근할 때, 데이터의 결함이 발생하지 않도록 원자성(atomic)을 보장하는 기법이다.

동시성 이슈

하나의 스레드가 데이터를 수정 중인 상황에서 다른 스레드에서 수정 전의 데이터를 조회하여 수정함으로써 데이터의 정합성(consistency)이 깨지는 문제를 말한다.

 

락 획득 시나리오

분산락 구현을 위한 Redis 사용


스프링 부트에서 Redis는 Lettuce,  Redisson 등 여러 가지 라이브러리로 지원된다.

이 중, Redisson을 이용할 것이다.

분산락을 구현하는 데 있어서 Redisson과 Lettuce의 차이점을 알아보자.

 

Lettuce

Lettuce는 공식적으로 분산락 기능을 제공하지 않는다. 따라서 직접 구현해서 사용해야 한다.

Lettuce의 락 획득 방식은 락을 획득하지 못한 경우 락을 획득하기 위해 Redis에 계속해서 요청을  보내는 스핀락(spin lock)으로 구성되어 있다. 이 스핀 락 방식은 계속해서 요청을 보내는 방식으로 인해 redis에 부하가 생길 수 있다는 단점이 있다.

Redisson

Redisson은 락 획득 시 스핀 락 방식이 아닌 pub/sub 방식을 이용한다.

pub/sub 방식은 락이 해제될 때마다 subscribe중인 클라이언트에게 "이제 락 획득을 시도해도 된다."라는 알림을 보내기 때문에, 클라이언트에서 락 획득을 실패했을 때, redis에 지속적으로 락 획득 요청을 보내는 과정이 사라지고, 이에 따라 부하가 발생하지 않게 된다.

또한 Redisson은 RLock이라는 락을 위한 인터페이스를 제공한다. 이 인터페이스를 이용하여 비교적 손쉽게 락을 사용할 수 있다.

 

RLock 라이브러리


락 획득 : tryLock

boolean tryLock(long waitTime, long leaseTime, TimeUnit timeUnit) throws InterruptedException;
  • waitTime: 락 획득을 위해 기다리는 시간
  • leaseTime: 락을 임대하는 시간
  • timeUnit: 시간 단위

이 설정에 따라 락 획득을 요청했을 때 락을 획득할 수 없다면 waitTime만큼 기다리고,

락을 획득했다면, 최대 leaseTime만큼 락을 점유할 수 있다.

 

락 획득과 반납 코드

RLock rLock = redissonClient.getLock(lockName);

try {
  boolean available = rLock.tryLock(waitTime, leaseTime, timeUnit);
  
  if(!available){
    return false; //락 획득 실패
  }
  //락 획득 후 로직 수행
}catch (InterruptedException e){
  //락을 얻으려고 시도하다가 인터럽트를 받았을 때 발생하는 예외
}finally{
	try{
      rLock.unlock();
      log.info("unlock complete: {}", rLock.getName());
    }catch (IllegalMonitorStateException e){
      //이미 종료된 락일 때 발생하는 예외
    }
}

 


Redis 설정


Redis 설치

아래 글을 확인하자

2023.11.07 - [Database] - [Redis] 레디스 설치 및 기본 기능

 

[Redis] 레디스 설치 및 기본 기능

Redis 설치 https://redis.io/docs/install/install-redis/install-redis-on-linux/ Install Redis on Linux How to install Redis on Linux redis.io 위의 Redis 공식 사이트에서 설치할 수 있다. Window의 경우 ubuntu 리눅스 서버 설치 후에

innovation123.tistory.com

 


 

build.gradle implementation

dependencies {
	//...
    implementation 'org.redisson:redisson-spring-boot-starter:3.17.0'
}

 


application.properties

spring.redis.host=localhost
spring.redis.port=6379

 


 

Configuration

@Configuration
public class RedissonConfig {

  @Value("${spring.redis.host}")
  private String host;

  @Value("${spring.redis.port}")
  private int port;

  private static final String REDISSON_HOST_PREFIX = "redis://";

  @Bean
  public RedissonClient redissonClient(){
    Config config = new Config();
    config.useSingleServer().setAddress(REDISSON_HOST_PREFIX + host + ":" + port);

    return Redisson.create(config);
  }

}

 


실제 사용 예제

public void update(long id){
  Member member = memberRepository.findById(id);
  String lockName = "MEMBER" + member.getId();
  RLock rLock = redissonClient.getLock(lockName);

  long waitTime = 5L;
  long leaseTime = 3L;
  TimeUnit timeUnit = TimeUnit.SECONDS;
  try {
    boolean available = rLock.tryLock(waitTime, leaseTime, timeUnit);
    if(!available){
      throw new CustomException(ErrorCode.LOCK_NOT_AVAILABLE);
    }
    //=== 락 획득 후 로직 수행 ===
    // ...
    // === 로직 수행 완료 ===
  }catch (InterruptedException e){
    //락을 얻으려고 시도하다가 인터럽트를 받았을 때 발생하는 예외
    throw new CustomException(ErrorCode.LOCK_INTERRUPTED_ERROR);
  }finally{
    try{
      rLock.unlock();
      log.info("unlock complete: {}", rLock.getName());
    }catch (IllegalMonitorStateException e){
      //이미 종료된 락일 때 발생하는 예외
      throw new CustomException(ErrorCode.UNLOCKING_A_LOCK_WHICH_IS_NOT_LOCKED);
    }
  }
}

 

 

이 글에서는 기본적으로 분산락을 이용해 보는 예제를 다뤘다.

Spring에서는 AOP 기술을 이용하여 더 효율적으로 분산락을 다룰 수 있다.

다음 글에서는 AOP 기술을 이용하여 annotation 기반으로 사용해 볼 예정이다.

2023.11.10 - [전체 글 보기] - [Redis] Redisson 분산락(DistributedLock) AOP 적용

 

[Redis] Redisson 분산락(DistributedLock) AOP 적용

이전 글 2023.11.07 - [Database] - [Redis] Redisson 분산 락을 간단하게 적용해 보기 분산 락 AOP 이용하기 build.gradle 아래 implementation을 추가한다. dependencies { //... implementation 'org.springframework.boot:spring-boot-star

innovation123.tistory.com

 

저작자표시 (새창열림)

'Spring' 카테고리의 다른 글

[Spring security] JWT 토큰이란?  (0) 2023.11.26
[Redis] Redisson 분산락(DistributedLock) AOP 적용  (0) 2023.11.10
[Spring Security] 스프링 시큐리티 SecurityContext에 직접 Authentication(PrincipalDetails) 넣기  (0) 2023.10.16
[Spring] 카카오 로그인 API 사용 방법  (17) 2023.10.15
[JUnit] 테스트 코드 작성과 단위테스트 Unit Test  (3) 2023.10.05
  1. 문제 상황
  2. Lock
  3. 분산락 구현을 위한 Redis 사용
  4. RLock 라이브러리
  5. 락 획득 : tryLock
  6. 락 획득과 반납 코드
  7. Redis 설정
  8. Redis 설치
  9. build.gradle implementation
  10. application.properties
  11. Configuration
  12. 실제 사용 예제
'Spring' 카테고리의 다른 글
  • [Spring security] JWT 토큰이란?
  • [Redis] Redisson 분산락(DistributedLock) AOP 적용
  • [Spring Security] 스프링 시큐리티 SecurityContext에 직접 Authentication(PrincipalDetails) 넣기
  • [Spring] 카카오 로그인 API 사용 방법
HSRyuuu
HSRyuuu
Web Backend Developer happyhsryu
HS_dev_logWeb Backend Developer happyhsryu
HSRyuuu
HS_dev_log
HSRyuuu
전체
오늘
어제
  • 전체 글 보기 (235)
    • Java (25)
    • Spring (29)
    • JPA & QueryDSL (13)
    • Database (17)
    • 자료구조 & 알고리즘 (30)
    • DevOps (10)
    • [ Computer Science ] (47)
      • Web & Network (14)
      • 프로그래밍 이론 (11)
      • 운영체제 (3)
      • 데이터베이스 이론 (5)
      • Linux 리눅스 (7)
    • [ Frontend ] (17)
      • Vue.js & Nuxt.js (9)
      • JSP_Thymeleaf (7)
    • [ 기타 ] (47)
      • 오픈소스 라이브러리 (5)
      • 코딩테스트 (13)
      • Trouble Shooting (7)
      • Tech Interview (6)
      • Book Review (9)
      • 끄적끄적... (5)
      • 개인 프로젝트 (2)

블로그 메뉴

  • 홈
  • 태그
  • github

공지사항

  • GitHub
  • 공부한 내용을 정리하고 기록하는 블로그 입니다.

인기 글

태그

  • 백엔드공부
  • 백엔드기술면접
  • HTTP
  • 제로베이스
  • JPA
  • Nuxt3
  • mybatis
  • web
  • 백엔드스쿨
  • Linux
  • cleancode
  • SQL
  • 백엔드
  • springsecurity
  • SpringBoot
  • 리눅스
  • 트랜잭션
  • Spring
  • 개발자
  • vue3
  • 클린코드
  • 기술면접
  • Database
  • Redisson
  • 백준
  • TechInterview
  • Redis
  • 자료구조
  • MySQL
  • Java

최근 댓글

최근 글

hELLO · Designed By 정상우.
HSRyuuu
[Redis] Redisson 분산 락을 간단하게 적용해보기
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

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

블로그 게시글

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

모든 영역

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

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