👋
안녕하세요~ 평비입니다!
오늘은 많이 혼동하시는 동시성과 병렬성 개념에 대해서 나름(?) 자세하게 준비한 포스팅을 준비해봤습니다!
이 주제에 대해서, 설명을 하기 위해 지난 포스팅에 다뤘던 그림을 가져왔습니다.
백엔드 서버에 동시에 100개의 요청이 들어왔을 때, 이걸 어떻게 처리할까요?
이 시스템은 동시성이 보장된 시스템일까요?
또, 병렬성이 보장된 시스템일까요?
1. 개념
우선, 동시성과 병렬성의 개념부터 짚고 넘어가봅시다. 간단해요!
🟨 동시성 (Concurrency)
동시에 여러 작업을 “처리 중”인 상태 (꼭 동시에 “수행”되지 않아도 됨)
- 시간 분할 (싱글코어에서도 가능)
- 주로 I/O 바운드 문제에 대응
예시 : 하나의 CPU가 요청 A, B, C를 빠르게 번갈아가며 처리
🟦 병렬성 (Parallelism)
여러 작업을 실제로 동시에 수행하는 것
- 멀티코어, 멀티스레드 필요
- 주로 CPU 바운드 문제에 대응
예시: 4코어 CPU가 동시에 4개의 요청을 각각 다른 코어에서 처리
2. 비교
항목 | 동시성 | 병렬성 |
목적 | 응답성 향상 | 처리량 향상 |
필수 조건 | 단일/멀티코어 가능 | 멀티 코어/스레드 필요 |
주 대상 | I/O 바운드 | CPU 바운드 |
예시 | async/await, coroutine | 멀티 스레드, 분산 처리 |
3. 정리
그럼, 다시 아래 그림으로 돌아가봅시다.
이 그림은 동시에 요청 A, B, C, D, ...을 모두 처리하고 있으니 동시성이 있는 시스템이라고 할 수 있습니다.
다만, 단일 큐에 할 일을 쌓아놓고, 한 번에 하나의 일만 할 수 있기 때문에 병렬성이 없는 시스템이라고 할 수 있습니다.
4. 동시성 이슈 (Concurrency Issues)
공유 자원 접근 충돌이 대표적인 동시성 이슈입니다. 앞선 포스트에서 계속 다뤘던 갱신 손실도 동시성 이슈에 속합니다.
하나의 데이터에 여러 스레드나 요청이 동시에 접근할 때 발생하는 이슈이죠.
4-1. 동시성 이슈 사례
이슈 종류 | 설명 |
Lost Update (갱신 손실) ✅ | 두 트랜잭션이 같은 데이터를 읽고, 서로 다른 값을 계산해 덮어씀. → 한쪽 변경 내용 소실 |
예약 충돌 | 락을 걸었는데, 같은 리소스를 여러 사용자가 동시에 예약해서 실패 |
Dirty Read ✅ | 트랜잭션 A가 아직 커밋하지 않은 데이터를 B가 읽어버림 |
Non-repeatable Read ✅ | 같은 트랜잭션 내에서 두 번 읽었는데 값이 달라짐 |
Phantom Read | 조건에 맞는 row 개수가 두 번 읽었을 때 달라짐 (새로운 row 생김) |
Write Skew | 동시에 두 트랜잭션이 서로 독립적인 업데이트를 해서 전체 정합성이 깨짐 |
- 송금 잔고 동시 차감 ✅ | 이체가 겹쳐서 잔고가 음수로 떨어지는 현상 |
갱신 손실, Dirty Read, Non-repeatable Read, 송금 잔고 동시 차감에 대해서는 앞선 포스트에서 참고 부탁드립니다!
4-1-1. 예약 충돌
동시성 이슈 사례 중, 송금과 자동이체가 동시에 일어나는 경우는 Repeatable read + Optimistic Lock으로 막을 수 있었습니다. 실패가 나더라도, 재처리 시도를 하면 어느 정도 보완이 됩니다.
그렇다면, 한 자리에 대해서 대규모 트래픽이 몰리는 SKT T1 롤드컵 티켓 예약을 예로 들면 어떨까요?
맨 처음 트래픽에 대해서는 성공했는데, 다른 모든 사람에 대해서 예약이 정상적으로 진행되다가 제일 마지막에 예약 버튼을 딱! 누르는 순간 아래와 같은 서버 에러가 발생한다면??? 그 날 콜센터는 또 난리가 날 겁니다...
모든 동시성 이슈에 대해서 Repeatable read + Optimistic Lock가 정답이라고 할 수 없는 것 같습니다!
이 경우는 낙관적 락이 사용자 경험에 직접 영향을 주는 케이스인데요. 이 경우는, 성능이 떨어지더라도 공정성과 UX가 중시되는 상황이라서 비관적 락이 더 적합하다고 할 수 있습니다.
하지만, 한 번 락을 잡았다고 무한정 점유하고 있게 하는 것은 아니고 보통의 경우 SOFT HOLD 상태로 만들게 됩니다.
SOFT HOLD 상태는 임시 점유 상태입니다. [최종 예약] 버튼을 누르기 전까지 3분, 5분, 20분 이런 식으로 임시 점유 상태로 만드는 거죠.
이와 같이, 락은 상황에 따라 적합하게 사용해야 합니다.
4-1-2. Phantom Read 문제
조건에 맞는 row 개수가 두 번 읽었을 때 달라짐 (새로운 row 생김)
이 문제는 Serializable이 아닌 모든 격리 수준, Repeatable read 격리 수준도 발생할 수 있는 문제인데요.
Repeatable read는 하나의 트랜잭션에서 조회를 여러번 해도 그 결과가 동일하다는 격리수준인데, 아쉽게도 다른 트랜잭션의 update는 반영이 되지 않아도 insert는 반영이 됩니다!
트랜잭션 2 입장에서, 어떠한 insert 연산도 하지 않았는데 다시 조회했더니 건수가 늘어있는 경우입니다. 유령이 와서 집어넣은 걸까요? 트랜잭션 2 입장에서는 충분히 놀랄만한 상황입니다! 그래서 이름도 Phantom Read인 모양입니다.
4-2. 병렬성 이슈 사례
이슈 종류 | 설명 |
락 경합 (갱신 손실) | (동시성 이슈와 유사) 여러 스레드가 동시에 같은 자원 접근 → 순서에 따라 결과 달라짐 |
데드락 (Deadlock) | 병렬 처리 중인 두 스레드가 서로의 락에 걸려 서로의 자원을 기다리며 멈추거나 계속 돌기만 함 |
우선순위 역전 (Priority Inversion) | 낮은 우선순위 스레드가 자원을 점유 중 → 높은 우선순위 대기 |
Work Stealing 불균형 | 병렬 태스크 분배 시, 특정 노드만 작업이 몰려 과부하 |
캐시 불일치 | 멀티코어 CPU에서 각 코어의 캐시 불일치 |
False Sharing | 서로 다른 스레드가 같은 캐시라인에 있는 변수 접근 시 성능 저하 (CPU 캐시 간 경합 현상) ex) 두 스레드가 인접한 배열 원소를 동시에 수정 |
Memory Barrier 누락 | CPU가 명령을 재배열하는데, 동기화 없이 접근 → 예측 불가 결과 |
Atomicity Violation | 여러 연산이 원자적이지 않게 병렬로 수행되어 문제 발생 |
결국, 동시성 이슈와 병렬성 이슈 모두 자원 공유 간 동시에 접근했을 때 이슈가 발생하는 것이라서 비슷합니다. 다만, 병렬성 이슈는 좀 더 큰 맥락입니다. 동시성 이슈는 트랜잭션 단위였던 반면, 병렬성 이슈는 스레드나 프로세스를 사용할 때 리소스 관리/조율 시 이슈에 해당합니다.
- ✅ 스레드 간 캐시 일관성 문제
- ✅ 병렬 처리 간 로드 밸런싱 실패
- ✅ 락 경합(lock contention) 과다로 오히려 성능 저하
- ✅ False Sharing (CPU cache 간 경합 현상)
- ✅ 병렬 작업 간 결합도 높아 성능 비효율
👏
자, 이렇게 기술 면접에서도 자주 언급되는, 동시성과 병렬성에 대해서 다뤄봤습니다!
저도 이 포스팅을 작성하면서, 두 개념의 차이에 대해서 좀 공부를 하게 된 것 같은데요...!
평비의 이 평범한 글이 여러분에게 비범한 도움이 되었으면 좋겠습니다 👍
'기술 면접 준비' 카테고리의 다른 글
ECS vs EKS(쿠버네티스)를 왜 사용할까? - 기술 면접 준비 (2) | 2025.06.04 |
---|---|
동기/비동기와 블로킹/논블로킹 - 기술 면접 준비 (1) | 2025.05.26 |
트랜잭션 락 - 기술 면접 준비 (1) | 2025.05.18 |
트랜잭션 격리수준 - 기술 면접 준비 (0) | 2025.05.13 |
갱신 손실(lost update) 이슈는 어떻게 방지할까요? - 기술 면접 준비 (0) | 2025.05.11 |