티스토리 뷰

토이 프로젝트를 진행하던 중, 동시성 이슈를 해결해야 할 필요가 생겼습니다.
이 내용을 문서화 할 필요도 있어 해당 내용을 정리한 내용을 블로그에다가도 옮겨 보았습니다.

 

Objective

현재 우리 서비스에서는 하나의 책에 2개 이상의 스레드가 접근해 주문을 시도하면 데이터의 정합성이 깨지는 문제가 있음. 우리 서비스와 같은 다중 사용자 환경에서 둘 이상의 트랜잭션이 동시에 수행될 때, 데이터의 정합성을 해치지 않도록 트랜잭션의 데이터 접근을 제어할 필요가 있음. 이러한 동시성 이슈를 해결하기 위해 lock을 이용한 동시성 제어를 사용하고자 함.

 

 

Proposal

  • redisson 사용

redis의 pub-sub 기반 message broker 기능을 이용하여 락을 구현하는 방법이다. 락을 해제하는 측이 락을 대기하는 프로세스에게 락 획득을 시도해도 된다는 메시지를 전달하는 방식으로 동작하며, 이 방법을 사용하면 끊임없이 redis 서버에 락 획득이 가능한지 여부를 확인하는 spin lock을 사용하지 않아도 된다.

이 방법은 우리가 직접 구현할 필요가 없이 redisson이라는 라이브러리를 사용하면 된다. 이미 메시지 브로커 기능을 활용하여 락을 구현해 두었기 때문이다.

또한 이 라이브러리는 타임아웃을 구현하여 일정 시간동안 락을 획득하지 못하면 예외를 발생시킬 수 있다. (pessimistic lock에서도 timeout을 구현할 수는 있다고 함. 다만 락을 유지하는 동안 리소스를 계속 점유하니 db에 계속 부하를 주게 되는 문제가 있다고 함.)

이를 통해 특정 서버에 문제가 생겨도 처리할 수 있어 해당 방법을 사용하는 게 적합하다고 생각된다.

 

  • pessimistic lock 사용

실제로 데이터에 락을 걸어 정합성을 맞추는 방법이다. 락을 걸게 되면 다른 트랜잭션에서는 락이 해제되기 전까지는 데이터를 건들 수 없다.

락을 통해 데이터를 제어하기 때문에 데이터의 정합성을 보장할 수는 있으나, 데이터 자체에 락이 걸리기 때문에 성능 저하가 발생할 수 있다.

또한, 서로 다른 스레드에서 각자 락이 걸린 데이터에 접근할 때 데드락이 발생할 수 있으며 락을 걸어둔 서버에 장애가 발생하면 해당 데이터에 대한 락이 풀리지 않아 다른 서버에서 해당 데이터를 수정할 수 없는 상황이 발생할 수 있다.

 

 

checkPoints

redis를 활용하게 되면 별도의 구축비용과 관리비용이 발생한다. 락을 라이브러리 차원에서 제공하기 때문에 사용법 숙지가 필요하다.

 

 

alternatives

  • optimistic lock 

실제 lock을 이용하지는 않고 버전을 이용해 정합성을 맞추는 방법이다.

버전 컬럼을 추가해야 하고, 재시도 로직을 직접 작성해야 한다. 우리 서비스의 경우 트랜잭션에서의 충돌이 빈번할 것이기 때문에 성능이 저하될 것으로 예상되어 적합하지 않다.

 

  • named lock 

사용되는 데이터에 락을 거는 게 아니라 별도의 다른 데이터에 락을 거는 방법

락은 별도의 트랜잭션으로 분리해서 관리해야 하며 트랜잭션이 종료될 때에 락 해제를 꼭 해줘야 한다.

우리 서비스에서 실제로 사용할 시에 구현방법이 복잡해 적합하지 않다고 생각하였다.

 

  • Lettuce

스프링에서 redis를 사용하면 lettuce가 기본이기에 별도의 라이브러리를 사용하지 않아도 된다.

다만 spin lock 방식이기 때문에 동시에 많은 스레드가 lock 획득을 대기중이라면, redis에 부하가 갈 수 있어 적합하지 않다고 생각하였음.

 

  • syncronized

해당 키워드는 해당 스레드를 제외하고 나머지 스레드들의 접근을 막아 순차적으로 접근할 수 있게 해준다.

다만 하나의 프로세스 안에서만 보장이 되기 때문에 우리와 같은 환경에는 적합하지 않다.

 

 

references

locking 기법에 대해

https://mangkyu.tistory.com/30

 

[Database] 8. 트랜잭션, 동시성 제어, 회복

[ 본 사진은 쉽게 배우는 오라클로 배우는 데이터베이스 개론과 실습 ppt에서 캡처했습니다. ]이번 장에서는 트랜잭션(Transaction), 동시성 제어(Locking or Currency Control), 회복(Recovery)에 대해 알아보겠

mangkyu.tistory.com

mysql의 locking

https://dev.mysql.com/doc/refman/8.0/en/locking-functions.html

 

MySQL :: MySQL 8.0 Reference Manual :: 12.15 Locking Functions

This section describes functions used to manipulate user-level locks. Table 12.19 Locking Functions GET_LOCK(str,timeout) Tries to obtain a lock with a name given by the string str, using a timeout of timeout seconds. A negative timeout value means infin

dev.mysql.com

jpa lock(하이버네이트) https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#locking

 

Hibernate ORM 5.4.33.Final User Guide

Fetching, essentially, is the process of grabbing data from the database and making it available to the application. Tuning how an application does fetching is one of the biggest factors in determining how an application will perform. Fetching too much dat

docs.jboss.org

lock 전반에 대한 내용. 이해하기 쉬움

https://velog.io/@tco0427/동시성-제어하기

 

동시성 제어하기

모아모아 서비스 동시성 제어하기

velog.io

https://thalals.tistory.com/370

 

[Spring & Java] 🚀 재고시스템으로 알아보는 동시성이슈 해결방법

인프런 "재고시스템으로 알아보는 동시성 이슈 해결방법" 강의를 보고 정리한 글입니다. 📗 Spring & Java, Mysql, Redis 를 이용합니다 재고시스템을 활용해서, 멀티스레드 혹은 분산환경에서 가변데

thalals.tistory.com

redis lock

https://hyperconnect.github.io/2019/11/15/redis-distributed-lock-1.html 

 

레디스와 분산 락(1/2) - 레디스를 활용한 분산 락과 안전하고 빠른 락의 구현

레디스를 활용한 분산 락에 대해 알아봅니다. 그리고 성능을 높이고 일관성을 보장하는 방법에 대해 알아봅니다.

hyperconnect.github.io

https://velog.io/@hkyo96/Redis-분산락을-이용한-동시성-문제-해결

 

레디스와 분산 락(1/2) - 레디스를 활용한 분산 락과 안전하고 빠른 락의 구현

레디스를 활용한 분산 락에 대해 알아봅니다. 그리고 성능을 높이고 일관성을 보장하는 방법에 대해 알아봅니다.

hyperconnect.github.io

 

댓글