동시성(concurrency)을 공부하다 보면
비슷해 보이는 단어들이 계속 등장한다.
- 원자성(Atomicity)
- 격리성(Isolation)
- 무결성(Integrity)
- 가시성(Visibility)
- 일관성(Consistency)
- Race Condition
문제는 이 단어들이 서로 겹쳐 보인다는 점이다.
하지만 이 개념들은
서로 다른 계층에서 발생하는 문제를 설명하는 말이다.
이번 글에서는
하나의 예시를 끝까지 확장하면서
각 개념을 정확히 분리해본다.
1. 공통 예시: 은행 계좌 출금
초기 상태:
balance = 1000
def withdraw(amount):
global balance
if balance >= amount:
balance -= amount
두 스레드가 동시에 withdraw(700)을 실행한다고 가정하자.
이 하나의 코드에서
여러 종류의 동시성 문제가 발생할 수 있다.
2. 원자성(Atomicity)
정의
하나의 연산이 “쪼개지지 않는 것”
실제 CPU에서 일어나는 일
balance -= 700
이 한 줄은 실제로는:
load balance
subtract 700
store balance
3단계다.
두 스레드가 동시에 실행하면:
A: load 1000
B: load 1000
A: store 300
B: store 300
결과는 300.
이건 무엇인가?
👉 원자성 깨짐
연산이 쪼개졌기 때문이다.
해결 방법
- atomic 연산
- mutex
- compare-and-swap(CAS)
핵심
다른 스레드가 “중간 단계”에 끼어들지 못하게 하는 것
원자성은 연산 단위의 보호다.
3. 무결성(Integrity)
정의
데이터가 논리적으로 올바른 상태를 유지하는 것
예:
balance ≥ 0
이게 비즈니스 규칙이다.
두 번 동시에 출금하면
잔액이 음수가 될 수 있다.
이건 무엇인가?
👉 무결성 위반
중요한 점
- 원자성은 “기술적 보호”
- 무결성은 “비즈니스 규칙 보호”
원자적이어도 무결성이 깨질 수 있다.
예:
atomic_decrement(balance, 2000)
원자적이지만
잔액은 -1000이 된다.
4. 격리성(Isolation)
이제 데이터베이스 상황을 생각해보자.
트랜잭션 A:
balance -= 700
(아직 commit 안함)
트랜잭션 B:
balance 조회
B가 300을 보면 안 된다.
왜냐하면 A가 롤백할 수도 있기 때문이다.
이건 무엇인가?
👉 격리성 문제
정의
동시에 실행되지만, 서로의 “중간 상태”를 보지 못하게 하는 것
핵심 차이
- 원자성 → 하나의 연산 단위
- 격리성 → 여러 연산 묶음(트랜잭션)
격리성은 더 큰 단위의 보호다.
5. 가시성(Visibility)
이번엔 CPU 두 개 상황.
코어 1:
balance = 300
코어 2:
print(balance)
코어 2가 여전히 1000을 볼 수 있다.
왜?
- 각 코어는 자기 캐시를 가진다.
- 메모리 동기화가 즉시 되지 않는다.
이건 무엇인가?
👉 가시성 문제
정의
한 코어가 변경한 값이 다른 코어에 언제 보이느냐
원자성과는 별개다.
원자적으로 써도
다른 코어에 안 보이면 의미 없다.
6. 일관성(Consistency)
이번엔 명령어 순서 문제.
코어 1:
balance = 0
flag = true
코어 2:
if flag:
print(balance)
CPU는 성능을 위해 명령어를 재정렬(reordering)할 수 있다.
결과:
- flag는 true
- balance는 아직 1000
이건 무엇인가?
👉 메모리 일관성 문제
정의
여러 코어가 동일한 순서로 값을 관측하는가
이 문제를 막기 위해:
- memory barrier
- acquire/release
- happens-before
같은 개념이 등장한다.
7. Race Condition
위 모든 문제의 공통점은 무엇인가?
실행 순서에 따라 결과가 달라진다.
이걸 Race Condition이라고 한다.
Race는 문제의 이름이고,
원자성·가시성·일관성은 그 원인이다.
8. 개념 정리표
개념무엇을 막는가계층
| 원자성 | 연산 중간 단계 노출 | CPU |
| 가시성 | 캐시로 인한 값 지연 | CPU |
| 일관성 | 명령어 재정렬 | CPU |
| 격리성 | 트랜잭션 중간 상태 노출 | DB |
| 무결성 | 논리 규칙 깨짐 | 비즈니스 |
| Race | 순서 의존 결과 | 전체 |
9. 원자성 vs 격리성 다시 정리
질문원자성격리성
| 단위 | 하나의 연산 | 여러 연산 묶음 |
| 보호 범위 | 작음 | 큼 |
| 계층 | CPU | DB |
| 막는 것 | 쪼개짐 | 섞임 |
한 줄 정리:
원자성은 “쪼개지지 않음”
격리성은 “섞이지 않음”
10. 왜 이걸 성능 엔지니어가 알아야 하는가?
동시성 버그는:
- 락 과다 → 성능 저하
- 락 부족 → 데이터 깨짐
- 잘못된 메모리 모델 이해 → 희귀 버그
성능 튜닝은 단순히 빠르게 만드는 게 아니라,
정확하면서 빠르게 만드는 것
이다.
핵심 요약
- 원자성은 연산 단위 보호
- 격리성은 트랜잭션 단위 보호
- 무결성은 논리 규칙
- 가시성은 캐시 문제
- 일관성은 순서 문제
- Race는 실행 순서 의존성
'프로그래밍공부(Programming Study)' 카테고리의 다른 글
| CPU, 메모리, 스레드 — 추상 용어를 물리적으로 이해하기 (0) | 2026.02.19 |
|---|---|
| Potpourri (자잘하지만 중요한 주제들) (2) | 2025.09.10 |
| Security and Cryptography (3) | 2025.09.09 |
| 메타프로그래밍(Metaprogramming)과 DevOps: 빌드·의존성·CI 제대로 이해하기 (0) | 2025.09.08 |
| 커맨드라인 환경 정리 – 효율적인 셸 활용법 (2) | 2025.08.30 |
댓글