Skip to main content

One post tagged with "concurrency"

View All Tags

Database Concurrency(데이터베이스 동시 배정 처리)

· 5 min read
Alex Han
Software Engineer

Untitled

배경

현업에서 업무를 하다 보면 배정 관련해서 데이터베이스 쿼리를 통해 가장 적게 배정 받은 순서로 플래너를 배정하고 안심번호를 배정하는 경우가 있습니다. 이때 요청이 많을 경우 문제가 발생합니다.

예를 들어 배정이 가장 적게 된 사람을 검색하고 그 사람은 이제 배정 됐음을 데이터베이스를 통해 업데이트를 하게 된다면, 이 프로세스를 진행하는 동안 수 많은 고객들이 데이터베이스가 업데이트 되기도 전에 같은 프로세스를 돌면서 중복 업데이트, 중복 배정의 문제가 발생됩니다.

설계

솔루션을 활용한 방법(rabbitmq, kafka, redis, …)

Untitled2

순서

  1. 백엔드로 요청이 들어오면 배정을 위해 필요한 데이터를 준비하고 그 순서를 큐에 쌓아둡니다.
  2. 쌓아둔 큐를 규칙에 따라 cron이 돌면서 가져와 순차적으로 배정됩니다.
  3. 이 때 큐의 규칙은 FIFO로 설정해 먼저 쌓인 요청부터 처리하는 방식이 신뢰도 있게 동작할 수 있습니다.

결론

메시지 큐 관련 솔루션을 활용해 배정이 필요한 부분을 쌓아둔 뒤, 일정 규칙에 맞게 cron을 돌려 쌓아둔 배정을 순차적으로 처리하는 방식입니다.

MySQL user-level lock 기능을 활용하는 방법

소개

MySQL은 사용자 레벨에서 데이터베이스를 조작할 수 있는 Lock 기능을 아래와 같이 제공합니다.

NameDescription
GET_LOCK()Get a named lock
IS_FREE_LOCK()Whether the named lock is free
IS_USED_LOCK()Whether the named lock is in use; return connection identifier if true
RELEASE_ALL_LOCKS()Release all current named locks
RELEASE_LOCK()Release the named lock

GET_LOCK(str, timeout): Lock의 이름을 설정하고 해당 락 프로세스 수행이 오래 걸릴 시를 대비해 timeout도 설정합니다.

IS_FREE_LOCK(str): GET_LOCK에서 설정된 이름을 조회해 현재 이 Lock이 사용중이라면 0, Lock이 풀렸다면 1, 만약 오류가 있다면 null 을 반환합니다.

IS_USED_LOCK(str): 이름에서 보는 것과 같이 IS_FREE_LOCK과 반대로 동작합니다.

RELEASE_ALL_LOCKS(): 해당 세션에서 설정한 모든 락을 풀어줍니다.

RELEASE_LOCK(str): Lock의 이름을 찾아 Lock을 풀어줍니다.

순서

Untitled1

동시성에 대해 문제가 발생하는 위의 그림과 같이 lock을 걸고 insert, update 를 처리한 후에 lock을 release 해주어 이를 해결하는 방법입니다.

  1. 배정이 가장 적게 된 사람을 검색하고 배정 됐음을 업데이트 하는 프로세스를 코드 실행 상 가장 근접하게 구성합니다.
  2. 1번에서 구성된 프로세스 앞 단에 GET_LOCK 쿼리를 하고 로직 수행 후 RELEASE_LOCK을 수행합니다.

결론

솔루션을 활용하는 방법 보다 서버 구성의 복잡도를 줄일 수 있고 백엔드 서버 내에서 코드적으로 처리할 수 있는 이점이 있습니다.