동시성 이슈 해결 고민...

Han Gyul Kang·2022년 10월 16일

동시성 문제

목록 보기
1/7

우선 도커 명령어부터 좀 작성해두고...

docker 설치

  • brew install docker
  • brew link docker
  • docker version

mysql 설치 및 실행

  • docker pull mysql
  • docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=__ --name mysql mysql
  • docker ps

mysql bash

  • docker exec -it mysql bash

문제 발단

  1. 특정 값을 100개 이상 허용하지 않기로 함
  2. 다수의 사용자가 비슷한 또는 같은 시간에 단일 테이블의 데이터를 바꾸려고 함
  3. 100개 이상 허용하지 않는 값이 100개를 초과해서 저장 됨(=update)
  • 예 : 선착순 100명 판매 상품
  • 레이스 컨디션
    두 개 이상의 스레스가 공유 데이터에 병렬적으로 접근할 때 발생하는 문제


문제 해결 공부 : 인프런 '동시성이슈-재고시스템'

Application Level

1. Synchronized

메서드에 선언, 한 개의 스레드만 접근 가능하도록 함

문제점
실제 서비스에서는 서버를 두 대 이상 사용함
해당 기능은 한 개의 프로세스 또는 서버에만 유효한 기능으로 사실 거의 사용하지 않음

Transactional annotation
우리가 만든 클래스를 Wrapping 한 클래스를 새로 만듦
트랜잭션이 정상적으로 종료될 때 데이터베이스에 데이터를 저장함
실제 데이터베이스에 데이터를 저장하기 전에 다른 Thread가 접근 가능해지기 때문에 여전히 레이스 컨디션 문제가 발생함.



Database 정합성

1. Database

DB를 활용한 데이터 정합성 맞추기

  1. Pessimistic Lock (비관적 락)
    실제로 데이터(row 또는 table 단위)에 Lock을 걸어서 정합성을 맞추는 방법
    Lock이 걸려있는 동안 다른 트랜잭션에서는 Lock걸린 데이터에 대한 권한이 없음
    데드락이 걸릴 수 있기 때문에 주의하여 사용해야 함

  2. Optimistic Lock (낙관적 락)
    실제로 Lock을 이용하지 않고 버전을 활용하여 버전으로 조회한 데이터를 Update 시 버전도 함께 변경하여 다른 트랜잭션에서 Update에 실패하도록 유도 함
    다만 이럴 경우 Update 실패 시 다시 버전을 읽어 실패한 프로세스를 다시 실행하도록 해줘야 함

  3. Name Lock (네임 락)
    이름을 가진 Metadata Locking으로 Lock이 획득한 후 해재할 때까지 다른 세션은 이 lock을 획득할 수 없음.
    Transaction이 종료될 때 Lock이 자동으로 해제되는 것이 아니기 때문에(=수동 해제) 별도의 명령어로 Lock을 풀어줘야 함
    Pessimistic Lock과 다르게 Metadata 기준으로 Lock을 걺



Redis Distributed Lock

  1. Redis 셋팅
    -docker pull redis
    -docker run --name myredis -d -p 6379:6379 redis
    -docker ps로 확인

  2. Lettuce
    setnx 명령어를 활용하여 분산락 구현
    spin lock 방식으로 개발자가 Lock 획득 재시도 로직을 구현해야 함
    재시도가 필요하지 않은 Lock 구현에 활용

  • setnx : SET if Not eXist, key와 value를 set할 때 기존의 값이 없어야 set
  • spin lock : Lock을 획득하려는 Thread가 Lock을 획득할 수 있는지 반복적으로 확인
  1. Redisson
    pub-sub 기반으로 Lock 구현 제공
    Lock을 획득한 Thread가 Lock 해제가 되면 대기하는 Thread에 Lock 획득 가능 사실을 전달함
    별도 Lock 획득 재시도 로직을 구현하지 않아도 됨
    재시도가 필요한 Lock 구현에 활용

MySQL, Redis 장단점

  1. MySQL
    • 이미 MySQL을 사용중이라면 별도 비용이 들지 않는다
    • 어느정도 트래픽까지는 문제 없이 활용 가능
    • Redis보다는 성능이 떨어짐
  2. Redis
    • 활용중인 Redis가 없다면 별도 비용과 관리비용이 발생한다
    • MySQL보다는 성능이 우수하다

이번 실무에서 동시성 이슈를 해결한 방안...

  • Redis는 별도로 구축되어있는게 없었고 새로운 미들웨어를 도입하기엔 시간이 촉박했음
  • 동시성 문제 해결을 위해 Pessimistic Lock을 선택
BEGIN
	...
    
    MAIN_LABEL : BEGIN
	...
        START TRANSACTION;
			SELECT ... FROM _T FOR UPDATE;
			
            UPDATE _T
			SET _DATA = V_DATA
			WHERE _PK = V_PK;
            
			<logic>
            ...
        
        # LOCK 해제를 위한 COMMIT
        COMMIT;
        
        ...
	END;
END
profile
피아노 치는 개발자

0개의 댓글