MOESI와 디렉터리 기반 캐시 일관성의 동작 원리
멀티코어 환경에서 캐시 복사본을 동기화하는 MESI·MOESI 프로토콜과 디렉터리 기반 일관성 구조를 정리한다.
2026-08-14 · 최초 발행 2026-01-19
캐시 복사본이 엇갈리는 순간
각 코어가 로컬 캐시에 같은 데이터를 보관하면 읽기 성능은 좋아진다. 문제는 어느 한 코어가 값을 바꾼 뒤에도 다른 캐시에 이전 복사본이 남는 경우다. 캐시 일관성 프로토콜은 이 복사본들의 상태를 조정해 정확성과 성능을 함께 다룬다.
공유 데이터에 여러 코어가 접근하고, 각 코어가 로컬 캐시에 복사본을 둔 상태에서 한 코어가 값을 갱신하면 문제가 시작된다. 다른 코어가 오래된 값을 읽는 읽기 불일치, 업데이트 순서가 바뀌는 쓰기 손실, 비결정적 동작으로 이어지는 데이터 경쟁이 발생할 수 있다.
MESI가 캐시 라인을 관리하는 방식
MESI는 캐시 라인의 상태와 상태 전이를 통해 복사본의 유효성을 관리한다.
- Modified (M): 수정된 유일한 복사본이며 메모리 값과 다르다.
- Exclusive (E): 한 캐시만 보유하지만 읽기만 이루어져 메모리와 일치한다.
- Shared (S): 여러 캐시에 존재하며 메모리와 일치한다.
- Invalid (I): 더 이상 사용할 수 없는 라인이다.
버스 기반 스누핑에서는 각 캐시가 버스 요청을 감시한다. 읽기 요청, 쓰기 준비를 위한 독점 읽기, 공유 상태의 업그레이드, 수정 데이터 제공이 이 흐름에서 사용된다.
- BusRd: 읽기 요청 브로드캐스트
- BusRdX: 쓰기를 준비하는 독점 읽기
- BusUpgr: Shared에서 Modified로 바꾸는 요청
- Flush: Modified 데이터를 버스에 제공하는 동작
Owned 상태가 바꾸는 데이터 전달 경로
MOESI는 MESI에 Owned 상태를 더한다. 수정된 데이터를 가진 캐시가 다른 코어의 읽기 요청에 응답할 때, 메모리로 즉시 Write Back하지 않고도 공유를 허용하는 상태다.
Owned 상태에서는 소유권을 유지한 채 다른 캐시와 데이터를 공유할 수 있다. 따라서 Modified 라인에 읽기 요청이 들어와도 메모리 쓰기가 필요하지 않고, Write Back을 뒤로 미뤄 버스 트래픽을 줄일 수 있다.
| 현재 상태 | 로컬 읽기 | 로컬 쓰기 | 원격 읽기 | 원격 쓰기 |
|---|---|---|---|---|
| M | M | M | O (데이터 제공) | I (무효화) |
| O | O | M (무효화 전송) | O (데이터 제공) | I |
| E | E | M | S (데이터 제공) | I |
| S | S | M (업그레이드) | S | I |
| I | E/S (상황 따라) | M | I | I |
AMD의 구현 예시에서는 프로브 필터가 캐시 복사본의 위치를 추적해 불필요한 스누핑을 줄인다. HyperTransport는 코어 간 고속 통신에 사용되며, Victim Cache는 퇴거된 Owned 라인을 임시로 저장한다.
브로드캐스트 대신 디렉터리를 두는 이유
버스 기반 방식은 코어 수가 늘수록 브로드캐스트 트래픽이 O(N) 코어에서 O(N²) 메시지로 커진다. 단일 공유 버스의 대역폭은 경합 지점이 되고, 모든 캐시가 스누핑해야 하므로 전력 소모도 늘어난다.
디렉터리는 메모리 블록마다 공유자와 소유자 정보를 기록하고, 필요한 코어에만 포인트-투-포인트 메시지를 보낸다. 이 구조는 수십~수백 코어까지 확장할 수 있다.
- 디렉터리 엔트리: 메모리 블록을 공유하는 코어의 정보
- 포인트-투-포인트 메시지: 대상 코어에만 보내는 메시지
- 확장성: 수십~수백 코어까지 지원
다음 흐름에서는 Core 0이 X를 읽은 뒤 Core 1이 X=200 쓰기를 요청한다. 디렉터리는 기존 공유자에게 무효화를 요청하고, 확인을 받은 뒤 쓰기를 허용한다.
- Read: 읽기 요청
- ReadX: 쓰기를 위한 독점 읽기
- Invalidate: 무효화 명령
- Data Reply: 데이터 응답
- Acknowledgement: 확인
분산 디렉터리에서는 코어, L2, 디렉터리를 타일에 배치하고 NoC를 통해 연결한다.
주소 인터리빙은 하위 비트를 기준으로 연속 블록을 다른 타일에 분산해 핫스팟을 막는다. NoC에서는 2D 그리드 메시 토폴로지, XY 라우팅과 데드락 방지, 메시지 우선순위를 위한 가상 채널이 사용된다.
저장 공간과 전달 지연을 다루는 기법
Limited Pointer Scheme은 고정 개수의 포인터만 저장하며, 예를 들어 4개를 넘기면 브로드캐스트하거나 희생자를 선택한다. Coarse Vector는 비트맵 대신 그룹 단위로 표현해 8코어를 1비트로 압축하는 대신 정확도를 낮추고 공간을 절약한다. Sparse Directory는 실제로 공유된 블록에만 엔트리를 할당하고 해시 테이블 또는 CAM을 활용한다.
캐시-투-캐시 전송은 메모리를 거치지 않고 소유 캐시에서 요청 캐시로 데이터를 전달한다.
이 방식은 메모리 우회로 지연 시간을 줄이고 메모리 컨트롤러 부하를 낮춘다. 3-hop에서 2-hop으로 줄이는 최적화도 여기에 해당한다.
프리페처가 가져온 데이터도 일관성 관리 대상이다. 잘못된 프리페치는 무효화 오버헤드를 유발할 수 있으므로, 힌트만 제공하는 비구속 프리페치나 읽기 전용 데이터를 위한 일관성 무시 프리페치가 사용된다.
하드웨어 규칙과 소프트웨어 계약
메모리 일관성 모델은 프로그래머가 관측하는 연산 순서를 정의한다. Sequential Consistency는 모든 연산을 전역 순서로 다루고, Relaxed Consistency는 쓰기 버퍼링과 재정렬을 허용한다. Release Consistency는 동기화 지점에서만 보장한다.
메모리 일관성 모델은 소프트웨어 계약이고, 캐시 일관성 프로토콜은 그 계약을 뒷받침하는 하드웨어 구현 메커니즘이다. Fence와 원자적 연산은 두 층위가 만나는 대표적인 동기화 수단이다.
// x86-64 예시
void example() {
shared_data = 42;
__asm__ __volatile__("mfence" ::: "memory"); // 메모리 배리어
flag = 1; // 플래그 설정
}
// C11 atomic
#include <stdatomic.h>
atomic_int counter = 0;
atomic_fetch_add(&counter, 1); // RMW (Read-Modify-Write)
하드웨어 차원에서는 x86의 LOCK 접두사와 MFENCE/LFENCE/SFENCE, ARM의 DMB/DSB/ISB 명령어, RISC-V의 FENCE와 AMO(Atomic Memory Operation)가 이를 지원한다.
측정에서 드러나는 일관성 비용
일관성 비용은 하드웨어 카운터로 관찰할 수 있다.
# perf를 이용한 측정 (Linux)
perf stat -e cache-misses,cache-references,L1-dcache-load-misses ./app
# Intel VTune
vtune -collect memory-access -knob analyze-mem-objects=true ./app
확인할 메트릭은 Coherence Miss Rate, Invalidation Count, Snoop Hit Rate, Average Latency다. 각각 일관성에 따른 미스 비율, 무효화 메시지 수, 스누핑 성공률, 평균 캐시 미스 지연을 나타낸다.
False Sharing은 서로 다른 스레드가 같은 캐시 라인 안의 별도 변수에 접근할 때 발생하는 핑퐁 현상이다. 패딩과 정렬로 캐시 라인을 분리할 수 있다.
// 문제 코드
struct {
int counter_a; // 캐시 라인 공유
int counter_b; // 핑퐁 현상
} shared;
// 해결 코드
struct {
int counter_a;
char padding[60]; // 64바이트 캐시 라인 분리
int counter_b;
} __attribute__((aligned(64))) optimized;
캐시 라인 크기에 맞춘 64바이트 정렬, 스레드 로컬 저장소 활용, 읽기 전용 데이터 분리는 패딩 전략으로 사용된다.
락 역시 일관성 트래픽에 영향을 준다. MCS Lock은 각 스레드가 서로 다른 캐시 라인을 폴링하는 방식이라 NUMA 환경의 로컬 메모리 접근에 유리하다. RCU(Read-Copy-Update)는 읽기 잠금을 두지 않고 그레이스 주기 이후 메모리를 반환해 일관성 프로토콜 부하를 낮춘다.
프로세서 연결 구조에서의 적용
Intel의 Haswell~ Ring Bus는 분산 L3 캐시를 사용하며, 각 슬라이스가 디렉터리 역할을 맡는다. 링 버스는 양방향 순환 구조이고 스누핑 필터는 불필요한 스누프를 줄인다.
AMD의 Infinity Fabric에서는 CCX(Core Complex)가 4코어와 L3 캐시로 구성된 클러스터다. CCX 내부에는 MOESI 프로토콜을 적용하고, CCX 간 통신에는 디렉터리 기반 방식을 사용한다. EPYC에서는 최대 64코어까지 확장성을 제공한다.
수백 코어 시스템으로 갈수록 NoC 기반 분산 디렉터리와 머신러닝 기반 적응형 일관성 프로토콜이 새로운 돌파구를 제공할 전망이다. 하드웨어의 일관성 메커니즘을 이해하면 False Sharing 회피, 동기화 프리미티브 선택, 캐시 친화적 자료구조 설계로 이어진다.