순차적 일관성 (Sequential Consistency)
핵심 인사이트 (3줄 요약)
- 본질: 다중 프로세서 환경에서, 모든 코어가 내린 메모리 읽기/쓰기 명령어가 마치 "하나의 CPU가 시분할로 실행한 것처럼" 시간적으로 완벽하게 줄을 서서(인터리빙) 프로그래머가 코드에 작성한 순서(Program Order)와 100% 동일하게 모든 프로세서에게 목격되는 가장 엄격한 메모리 일관성 모델이다.
- 가치: 스레드 1의 행동과 스레드 2의 행동이 절대로 서로의 순서를 거스르며 꼬이지 않기 때문에, 개발자의 상식과 직관에 완전히 부합하여 멀티스레드 동기화 코딩과 디버깅 시 가장 안전하고 쾌적한 환경을 제공한다.
- 융합: 이 이상적인 모델을 물리적 하드웨어로 보장하려면 CPU의 꽃인 비순차 실행(Out-of-order), Store Buffer(쓰기 지연), 캐시 최적화를 철저히 금지해야 하므로, 파이프라인 성능이 깡통 수준으로 하락하는 최악의 트레이드오프 탓에 현대 범용 하드웨어에서는 버려진 이론적 이상향이다.
Ⅰ. 개요 및 필요성 (Context & Necessity)
순차적 일관성 (Sequential Consistency)은 1979년 튜링상 수상자인 레슬리 램포트(Leslie Lamport)가 멀티프로세서가 마땅히 지켜야 할 '최소한의 상식'으로 정의한 모델이다.
프로그래머가 코드를 짤 때 가장 당연하게 믿는 명제가 있다. "코드는 위에서 아래로 순서대로 실행된다."
멀티스레드에서도 마찬가지다. A 스레드가 x=1을 쓰고 y=2를 썼다면, B 스레드가 지켜볼 때 무조건 x=1이 먼저 보이고 그다음에 y=2가 보여야 인간의 뇌가 로직을 짤 수 있다.
[순차적 일관성의 2가지 절대 룰 (Lamport의 정의)]
1. 각 프로세서의 작업은 프로그래머가 명시한 순서(Program Order)대로 실행되어야 한다.
2. 모든 프로세서의 작업들은 전역 메모리를 향해 '단 하나의 시간적 순서'로 엮여서(Interleaving) 들어가야 한다.
* 작동 예시 (이상적인 교차로 진입)
[코어 1]: A=1 ──┐
[코어 1]: B=1 ──┤
├──> [ 메모리 진입 큐 ]: (A=1) -> (X=9) -> (B=1) -> (Y=9)
[코어 2]: X=9 ──┤ => 섞여서 들어가긴 하지만, 코어 1의 A와 B 순서, 코어 2의 X와 Y 순서는 절대 뒤집히지 않음!
[코어 2]: Y=9 ──┘
이 규칙이 지켜지면, 세상의 어떤 데드락 알고리즘(데커 알고리즘, 피터슨 알고리즘)도 메모리 배리어(Barrier) 같은 하드웨어 꼼수 없이 순수 소프트웨어 논리만으로 완벽하게 동작한다. 개발자에겐 그야말로 천국이다.
📢 섹션 요약 비유: 순차적 일관성은 은행 창구(메모리)가 딱 1개뿐인 세상입니다. 손님 1번과 2번이 각자 번호표를 2장씩 뽑았다면, 은행원이 손님을 번갈아 처리할 순 있어도 손님 1번의 앞 번호표 업무를 뒤 번호표 업무보다 늦게 처리하는 하극상은 절대 벌어지지 않는 완벽한 질서입니다.
Ⅱ. 아키텍처 및 핵심 원리 (Deep Dive)
이 아름다운 소프트웨어의 천국이 현실 하드웨어에서 구현되려면 반도체 설계자들은 지옥을 맛봐야 한다. 하드웨어 성능을 올리기 위한 모든 최신 기술을 원천 봉쇄당하기 때문이다.
| 하드웨어 가속 기술 | 순차적 일관성 보장을 위해 당하는 처벌 | 아키텍처적 비극 |
|---|---|---|
| Write Buffer (Store Buffer) | 금지. 캐시에 데이터를 쓰러 가는 동안 100클럭이 걸려도, 완료될 때까지 CPU는 다음 명령을 절대 실행하지 못하고 무조건 멈춰서 기다려야 함 | 파이프라인 정지 (가장 심각한 속도 저하) |
| 비순차 실행 (Out-of-Order) | 금지. 뒤에 있는 연산이 먼저 끝날 수 있어도, 무조건 앞 연산이 끝날 때까지 파이프라인 방치 | 수퍼스칼라 칩 면적 투자 의미 상실 |
| Non-blocking Cache | 금지. 1번 데이터 캐시 미스 나면 2번 데이터 읽기 요청도 대기 | 메모리 지연 은닉(Latency Hiding) 불가능 |
이 때문에 순차적 일관성을 하드웨어 스펙으로 100% 보장하는 CPU를 만들면, 수십억 개의 트랜지스터를 박아 넣은 최신 멀티코어 칩이 20년 전 펜티엄 3 시절의 싱글 코어 수준의 속도로 퇴화해 버린다.
📢 섹션 요약 비유: 우체부가 편지를 주소 순서대로만 배달해야 한다는 규칙(순차적 일관성)을 지키려면, 강남 가는 편지가 가방 맨 밑에 깔려 있다고 해서 눈앞에 있는 강북 편지를 먼저 배달하면 안 됩니다. 무조건 강남을 다녀온 뒤 강북 편지를 꺼내야 하므로 동선 낭비(성능 저하)가 끔찍하게 발생합니다.
Ⅲ. 실무 적용 및 기술사적 판단 (Strategy & Decision)
현대의 인텔, AMD, ARM CPU는 아무도 이 '순차적 일관성'을 하드웨어 기본값으로 쓰지 않는다(완화된 일관성 채택). 하지만 실무 C++/Java/Rust 개발자들은 락프리(Lock-free) 프로그래밍을 할 때 논리적 붕괴를 막기 위해, 특정 코드 구간에서만큼은 강제로 하드웨어의 멱살을 잡고 '순차적 일관성'을 흉내 내도록 억지를 부려야 한다.
실무 하드웨어 통제 및 메모리 오더링 시나리오
- C++11
std::memory_order_seq_cst의 적용과 페널티- 상황: 복잡한 멀티스레드 락프리 큐를 구현 중. 데이터가 꼬이는 걸 막기 위해 원자적 연산(
std::atomic)에 메모리 오더(Memory Order) 옵션을 넣어야 함. - 의사결정: 가장 안전하게 가기 위해 디폴트 옵션인
memory_order_seq_cst(Sequential Consistency, 순차적 일관성)를 변수 조작에 때려 박는다. - 이유: 이 코드를 본 컴파일러와 CPU는 즉각 모든 잔재주(Reordering, Store Buffer 사용)를 중지하고, 해당 줄을 실행할 때 강력한 **풀 메모리 배리어 (Full Memory Barrier)**를 사방에 쳐서 앞뒤 코드의 순서를 우직하게 지켜낸다. 개발자는 버그의 공포에서 해방되지만, 그 대가로 해당 틱(Tick)의 연산 속도는 무거운 락(Mutex)을 건 것과 비슷하게 느려지는 막대한 성능 세금(Performance Penalty)을 물게 된다. (최고수들은 이걸 안 쓰기 위해 Relaxed 모드로 설계함)
- 상황: 복잡한 멀티스레드 락프리 큐를 구현 중. 데이터가 꼬이는 걸 막기 위해 원자적 연산(
📢 섹션 요약 비유: 순차적 일관성은 개발자에게 "자전거 보조 바퀴"와 같습니다. 절대 넘어지지 않고 안전하게 코딩할 수 있게 해주지만, 카레이싱(최고 성능 튜닝)을 해야 하는 실무 서버 환경에서는 보조 바퀴를 달고 달리면 남들에게 속도로 처참하게 박살 나게 됩니다.