[Spring] 동시성 문제

JY·2025년 3월 19일
0

Spring

목록 보기
2/5
post-thumbnail

💡 동시성 문제란?

"하나의 데이터에 2개 이상의 쓰레드가 작업하여 데이터의 값이 수정되거나 조회되는 현상" 혹은 "세션 및 트랜잭션 데이터를 동시에 관리하려할 때 나타나는 문제"를 의미한다.

쉽게 말해 여러 사람이 동시에 같은 데이터를 사용하거나 수정할 때, 데이터가 꼬이거나 엉뚱한 결과가 나오는 상황을 말한다.


🔥 왜 문제가 생기는 걸까?

서로 다른 사용자가 동시에 하나의 계좌에 요청을 한다고 생각해보자

요청 1 : AUser 가 계좌 잔액을 읽음 → 100,000원
요청 2 : BUser 도 동시에 잔액을 읽음 → 100,000원

👉 AUser : 50,000원 출금 → 100,000 - 50,000 = 50,000원
👉 BUser : 30,000원 출금 → 100,000 - 30,000 = 70,000원

😱 문제 발생!!!

  • 두 사용자가 같은 잔액을 기준으로 출금 처리해서 최종 잔액이 요청 순서에 따라 마지막에 저장된 70,000원이라는 값이 저장 돼버림.

  • 원래 결과 : 100,000 - 50,000 - 30,000 = 20,000원

이와같은 상황을 막고자 동시성 문제에 대한 해결방안 필요함!!


⚡동시성 문제의 대표적인 현상들

다음은 동시성 문제가 발생할 때 자주 나타나는 이슈들이다.

1️⃣ 더티 리드 (Dirty Read)
A가 데이터를 수정 중인데, B가 그 데이터를 읽어버림 → 잘못된 데이터 읽기

2️⃣ 잃어버린 업데이트 (Lost Update)
A와 B가 같은 데이터를 수정하고, 마지막에 B의 값으로 덮어씌워짐 → A의 수정 내용이 사라짐

3️⃣ 반복 불가능한 읽기 (Non-repeatable Read)
A가 데이터를 읽고 처리 중인데, B가 데이터를 바꿔버림 → A가 다시 읽으면 다른 값이 나옴

4️⃣ 팬텀 리드 (Phantom Read)
A가 데이터를 조회했을 때는 없었는데, B가 데이터를 추가해서 A가 다시 조회하면 새로운 데이터가 보임


🛠️ 그럼 해결 방법은?

이런 문제를 막으려면, 누군가 작업을 하고 있을 때 다른 사람은 잠깐 기다리게 만들거나, 순서를 조정해야 한다.

공유 데이터

✅ DB Lock

DB 자체에서 제공하는 잠금을 활용하는 방법이며, 크게 Perssimistic Lock과 Optimistic Lock으로 나뉜다.

  1. Perssimistic Lock (비관적 락)
    어느 상황이든 동시성 이슈가 발생할거라 가정하고 문제가 발생하기전에 잠금을 걸어버리는 방법
    모든 상황에 잠금을 걸기 때문에 처리 속도가 느리지만, 어떠한 방법보다 안정성이 높다.

  2. Optimistic Lock (낙관적 락)
    "뭐 이슈가 거의 안생기지 않을까?"라는 느낌으로 만약 문제 발생시 실패로 처리해버리는 방법
    상대적으로 Perssimistic Lock보다 속도는 빠르지만 문제발생시, 재시도를 해야한다.

✅ synchronized (Java의 동기화 키워드)

Java에서 synchronized 키워드를 이용해 동기화를 거는 방법이다.

간단하게 키워드를 사용함으로써 이슈를 막을 수 있으나, 쓰레드를 하나씩 처리 하는 방법이므로 성능 저하가 발생할 수 있다. 또한, 서버가 여러 대로 확장되면 동기화가 서버 간 공유되지 않기 때문에 분산 환경에서는 부적합하다.


세션 관리, 트랜잭션 데이터 등 쓰레드가 독립적으로 필요한 데이터

✅ ThreadLocal

각 쓰레드마다 독립된 값을 저장하는 방식이다.

멀티 쓰레드 환경에서 특히 유효하며, 각 쓰레드가 사용자에게 할당 되었을 때의 데이터 충돌을 방지할 수 있다.


다양한 해결방법이 존재하지만 개발자들은 프로젝트의 목표와 성능에 맞춰 적절한 방법을 채택하는 것이 필요하다.

0개의 댓글