본문 바로가기
가치관 쌓기/개발 돌아보기

(수정)DB 에서 하는 동시성제어와 애플리케이션에서 하는 동시성 제어는 어떤게 다른걸까?

by simplify-len 2024. 10. 8.

 

데이터베이스에서 하는 동시성 제어애플리케이션에서 하는 동시성 제어는 모두 동시성 문제를 해결하는 방법이지만,

적용되는 레벨과 사용되는 기술에서 차이가 있다.
이 둘은 각각 다른 목적으로, 다른 상황에서 사용되며, 서로 보완적인 역할을 할 수 있다.

1. 데이터베이스에서의 동시성 제어 

데이터베이스에서의 동시성 제어는 트랜잭션 관리를 통해 여러 클라이언트가 동시에 동일한 데이터에 접근할 때 발생하는 데이터 무결성일관성을 보장하는 것을 목표로 한다. 그래서 자주 사용하는 것은 잠금(Locking), 격리 수준(Isolation Level) 등의 기술을 사용한다.

트랜잭션 기반이라는 말은, 데이터베이스는 트랜잭션 단위로 동시성을 제어한다. 트랜잭션은 하나 이상의 쿼리가 실행되며, 트랜잭션이 완료될 때까지 데이터의 무결성을 보장한다.

격리수준이란?  데이터베이스가 트랜잭션 간의 격리 수준을 설정하여 동시성 문제(더티리드, 팬텀리드, 반복 불가능한 읽기) 등의 문제를 해결해준다.

  • READ UNCOMMITTED - 트랜잭션이 커밋되지 않은 데이터를 다른 트랜잭션이 읽을 수 있다. 가장 낮은 격리 수준.
  • READ COMMITTED - 트랜잭션이 커밋된 데이터만 읽을 수 있다.
  • REPEATABLE READ - 트랜잭션 내에서 동일한 데이터를 여러 번 읽어도 동일한 결과를 보장한다.
  • SERIALIZABLE - 가장 높은 수준의 격리로, 트랜잭션 간 완전한 순차적 실행을 보장해 동시성 문제가 발생하지 않는다.

잠금(Locking)이란? 데이터베이스는 낙관적 잠금(Optimistic Locking)과 비관적 잠금(Pessimistic Locking)을 사용해 데이터에 접근하는 트랜잭션을 동기화한다.

  • 비관적 잠금 - 한 트랜잭션이 데이터를 수정할 때 다른 트랜잭션이 그 데이터를 읽거나 수정하지 못하도록 잠금을 거는 방식이다.
  • 낙관적 잠금 - 데이터 수정이 발생할 가능성이 낮다고 가정하고, 수정 시점에 충돌이 발생하면 충돌 방지 후 롤백한다.

여기서 동시성 제어의 목적데이터 일관성과 무결성을 보장하는 것은 주된 목적이다. 데이터베이스는 트랜잭션과 잠금을 통해 충돌을 방지하고, 충돌이 발생할 때 이를 해결한다.

예시를 들어보면 은행 시스템에서 계좌 이체: 두 명의 사용자가 동시에 같은 계좌에 접근해 돈을 인출하거나 입금할 경우, 데이터베이스는 트랜잭션을 사용해 동시성 제어를 한다. 하나의 트랜잭션이 완료되기 전에는 다른 트랜잭션이 해당 데이터에 접근할 수 없다. 이를 통해 데이터 무결성을 보장한다.

2. 애플리케이션에서의 동시성 제어

애플리케이션에서의 동시성 제어는 다중 스레드 환경에서 여러 스레드가 동시에 자원(메모리, 데이터 구조, 파일 등)에 접근할 때 발생하는 문제를 방지하는 것을 목표로 한다. 이를 위해 애플리케이션에서는 락(Lock), 동기화(Synchronization), CAS(Compare and Set) 과 같은 알고리즘을 사용한다.

애플리케이션에서 동시성은 스레드 기반의 제어를 한다.

스레드 기반 제어: 애플리케이션은 주로 스레드 간의 경쟁 조건(Race Condition)을 제어하기 위해 동시성 제어를 사용한다. 여러 스레드가 동일한 자원에 동시에 접근하여 충돌을 일으키는 문제를 방지하는 것이 목표다.

  • 락(Locking)과 동기화(Synchronization):
    • 락: 한 스레드가 자원에 접근할 때 다른 스레드가 그 자원에 접근하지 못하도록 락을 설정한다.
    • 동기화: 자원에 대한 동시 접근을 방지하여 한 번에 하나의 스레드만 접근하도록 제한한다. 자바의 synchronized 키워드가 대표적이다.

낙관적/비관적 동시성:

  • 낙관적: 여러 스레드가 동시에 작업을 처리할 수 있도록 하고, 충돌이 발생하면 롤백하거나 재시도하는 방식이다.
  • 비관적: 충돌 가능성이 높다고 가정하고, 미리 자원을 잠그고 다른 스레드의 접근을 차단한다.

데이터 공유: 애플리케이션에서 여러 스레드가 공유 자원(예: 메모리의 변수, 리스트)에 동시에 접근하는 경우, 동시성 제어를 통해 데이터가 불일치 상태에 빠지지 않도록 보호한다.

동시성 제어의 목적: 애플리케이션 레벨에서는 주로 스레드 안전성데이터 일관성을 확보하는 것이 목적이다. 자원 접근 시 충돌을 방지하거나, 충돌 시 처리 방식을 관리하는 것이 중요하다.

 

-- 내용추가

그럼 이 두개를 분리해서 생각해야되는 이유는 뭘까?

이 질문에 대해서 핵심을 관통하는 트러블슈팅을 해주신분이 계셨다. 운이 좋았다.

https://hyeon9mak.github.io/why-occurs-deadlock-from-select-query/

 

왜 조회 쿼리에서 데드락이 발생했을까?

“아니, 도대체 왜 조회 쿼리 메서드에서 데드락이 생기는거야?”

hyeon9mak.github.io

위 포스팅을 보면 흥미로운 이야기가 나온다. 조회는 애플리케이션에서 하는데, DB에서 데드락이 걸린다고?

Spring boot 와 JPA 을 활용하는 애플리케이션에서 JPA 는 ORM 으로서 개발자가 작성해야될 코드를 대신 해결해준다. 

중간에 이런 말이 나온다

트랜잭션끼리의 경쟁은 하나의 요청 내에서만 발생하는게 아니라 여러 요청 사이에서도 발생할 수 있다. 결국 ‘DB 에 동시 접근중인 트랜잭션이 몇 개냐’ 관점으로 바라봐야하는 것 같다.



즉, DB 와 애플리케이션에서 발생하는 트랜잭션을 분리해서 생각해야만 한다. 서로다른 context 를 가지고 있기 때문이다. 그리고 동시성을 해결할 수 있는 방안으로 무조건 애플리케이션 락/DB락 만이 있는것이 아님을 인지할 필요도 있을 것 같다.

댓글