275. 캐시 쓰기 정책 (Write Policy)

핵심 인사이트 (3줄 요약)

  1. 본질: 쓰기 정책(Write Policy)은 CPU가 데이터를 변경(Write)했을 때, 그 변경된 값을 캐시에만 업데이트할지, 아니면 저 멀리 있는 메인 메모리(DRAM)까지 동시에 업데이트할지 결정하는 하드웨어적 동기화 룰이다.
  2. 가치: 캐시의 '읽기' 성능은 적중률(Hit Ratio)이 지배하지만, '쓰기' 성능은 이 쓰기 정책(Write-Through vs Write-Back)이 완전히 지배한다. 메인 메모리로 쏟아지는 막대한 쓰기 트래픽을 어떻게 은닉(Hide)할 것인가가 핵심이다.
  3. 융합: 멀티코어 환경에서 각 코어가 캐시에 자기 맘대로 값을 쓰면 데이터 불일치가 발생하므로, 쓰기 정책은 필연적으로 **캐시 일관성 프로토콜(MESI 등)**과 융합되어 현대 CPU 버스 대역폭의 한계를 방어한다.

Ⅰ. 개요 및 필요성

  • 개념: 캐시는 메인 메모리의 '복사본'이다. CPU가 연산을 통해 이 복사본의 값을 수정했을 때, 캐시와 메인 메모리 사이에는 일시적으로 데이터가 달라지는 모순 상태가 발생한다. 쓰기 정책은 이 모순을 즉시 해결할 것인지(동시 쓰기), 아니면 나중으로 미룰 것인지(나중 쓰기)를 정하는 아키텍처적 선택이다.

  • 필요성: 프로그램 명령어 중 약 10~15%는 데이터를 쓰는 작업이다. 만약 CPU가 데이터를 수정할 때마다 100ns의 지연을 가진 메인 메모리에 매번 정직하게 쓴다면, 파이프라인은 쓰기 지연 때문에 텅텅 비어버릴 것이다. 반면, 빠르다고 캐시에만 써놓고 메모리에는 안 쓰면 정전이 나거나 다른 장치가 메모리를 읽을 때 끔찍한 구버전 데이터를 읽게 된다. 속도와 데이터 무결성 사이에서 어느 것을 우선할지 결정하는 정책이 필요했다.

  • 💡 비유: 직원이 회사 문서를 수정할 때, **한 줄 고칠 때마다 사장님 캐비닛(메모리)에 뛰어가서 복사본을 똑같이 고쳐놓는 것(Write-Through)**과, 일단 내 책상(캐시)에 있는 **문서를 맘대로 다 고친 뒤 퇴근할 때 딱 한 번 사장님께 제출하는 것(Write-Back)**의 차이입니다.

  • 등장 배경: 초기 캐시는 구현이 간단한 Write-Through를 채택했다. 하지만 CPU 클럭이 GHz를 넘어가며 메모리와의 속도 격차가 100배 이상 벌어지자, 쓰기 병목이 시스템 전체를 마비시켰다. 이를 타파하기 위해 Dirty Bit라는 1비트의 꼬리표를 도입하여 수만 번의 수정을 캐시 내부에서만 처리하는 Write-Back 기술이 현대 고성능 프로세서의 표준으로 정착했다.

┌──────────────────────────────────────────────────────────────┐
│           CPU의 쓰기 동작에 따른 캐시와 메인 메모리의 상태 변화 도식       │
├──────────────────────────────────────────────────────────────┤
...

- **📢 섹션 요약 비유**: Write-Through는 카톡을 칠 때 오타가 나면 무조건 문장 전체를 다시 써서 다시 보내는 피곤한 성격이고, Write-Back은 내 폰 메모장에서 썼다 지웠다 100번을 고치고 완벽해졌을 때 전송 버튼을 딱 한 번 누르는 효율적인 성격입니다.

---

## Ⅱ. 아키텍처 및 핵심 원리

### 쓰기 실패 (Write Miss) 시의 두 가지 분기 (Write-Allocate)

"만약 CPU가 데이터를 쓰려고 캐시를 봤는데, **그 데이터가 캐시에 없다면(Write Miss)?**" 이때도 아키텍처는 두 가지 길 중 하나를 선택해야 한다.

1. **Write-Allocate (불러와서 쓰기)**
   - 메모리에서 그 주소의 데이터를 캐시로 강제로 퍼 끌어온다.
   - 캐시에 자리가 생기면 그 위에다 새로운 데이터를 쓴다.
   - **조합**: 보통 **Write-Back**과 영혼의 짝꿍을 이룬다.

2. **No Write-Allocate (그냥 램에 쏘고 치우기)**
   - "어차피 캐시에 없네? 굳이 무겁게 캐시로 가져올 필요 없이, 바로 다이렉트로 메모리로 쏴서 거기에만 써버리자."
   - **조합**: 보통 **Write-Through**와 짝꿍을 이룬다.

### 현대 CPU의 황금 조합: Write-Back + Write-Allocate
오늘날의 프로세서들은 99.9% **[Write-Back + Write-Allocate]** 구조를 사용한다. 시간적 지역성에 따르면 변수 `i`는 루프를 돌며 수만 번 수정된다. 만약 Write-Through라면 수만 번 내내 메모리 버스가 혹사당해 시스템이 타버릴 것이다. Write-Back 구조는 처음에 캐시로 가져올 때 딱 1번, 나중에 캐시에서 쫓겨날 때 딱 1번, **총 2번의 메모리 접근만으로 수만 번의 쓰기 연산을 퉁치는 기적의 트래픽 압축기**다.

- **📢 섹션 요약 비유**: 수첩에 안 적힌 전화번호를 수정하려 할 때, 일단 내 수첩에 그 사람 이름을 적어놓고 옆에 새 번호를 고쳐 쓰는 것(Write-Allocate)이고, 내 수첩에 적기 귀찮아서 그냥 회사 중앙 명부에만 쓱 고치고 마는 것(No Write-Allocate)의 차이입니다.

---

## Ⅲ. 비교 및 연결

### Write-Through vs Write-Back 트레이드오프 매트릭스

| 특성 | Write-Through (동시 쓰기) | Write-Back (나중 쓰기) |
|:---|:---|:---|
| **메모리 업데이트 시점** | 데이터가 수정될 때 즉시 매번 | 블록이 캐시에서 쫓겨날 때 한 번 |
| **메모리 대역폭 사용**| 극도로 높음 (버스 병목의 주범) | **매우 낮음 (버스 트래픽 획기적 절약)** |
| **데이터 무결성** | 완벽함 | 취약함 (정전 시 캐시 값 증발) |
| **하드웨어 제어 복잡도** | 단순함 | 복잡함 (Dirty Bit 관리 필수) |
| **적용 계층** | 속도 덜 중요한 하위 계층 | **L1, L2, L3 등 현대 모든 메인 캐시** |

### Write Buffer (쓰기 버퍼)의 구조적 보완
Write-Through가 너무 느리니까 하드웨어 엔지니어들은 속임수를 만들었다. 캐시와 메인 메모리 사이에 작은 **'쓰기 버퍼(Write Buffer)'** 큐를 달아놓는다.
- CPU가 데이터를 쓰면 메모리까지 안 가고 이 작은 버퍼에만 쓱 던져놓고 1클럭 만에 다음 일을 하러 간다.
- 버퍼는 자기가 알아서 뒤에서 천천히 메모리에 데이터를 쓴다.
- 하지만 CPU가 쓰기를 너무 미친 듯이 연사해서 버퍼가 꽉 차버리면, 결국 CPU는 버퍼가 비워질 때까지 또 파이프라인을 멈추고 기다려야 한다.

- **📢 섹션 요약 비유**: Write-Through의 느린 속도를 가리기 위해 만든 쓰기 버퍼는 '우체통'입니다. 편지를 우체국까지 직접 안 가고 앞마당 우체통(버퍼)에 던져놓으면 되니 빠릅니다. 하지만 명절에 편지가 너무 많아 우체통이 꽉 차면 결국 집배원이 비워줄 때까지 밖에서 기다려야 합니다.

---

## Ⅳ. 실무 적용 및 기술사 판단

### 실무 시나리오

1. **DMA 장치와 캐시 불일치 사고**
   네트워크 랜카드(DMA)가 CPU를 거치지 않고 메인 메모리의 패킷 수신 버퍼에 데이터를 직접 쐈다. 그런데 CPU가 그 버퍼를 읽었더니 옛날 쓰레기 값이 나옴. 전형적인 Write-Back의 저주다. CPU의 L1 캐시에 해당 메모리 주소의 옛날 값이 상주해 있는데, DMA가 메인 메모리 원본만 몰래 업데이트해 버린 것이다. 실무 펌웨어 개발자는 DMA가 메모리에 쓰기 직전에 반드시 OS 레벨에서 칩에 캐시 무효화 명령을 내려, CPU가 다음번엔 램에서 새 데이터를 강제로 퍼 오도록 방어 코드 장벽을 세워야 한다.

2. **멀티코어 환경의 캐시 일관성 (Cache Coherence) 핑퐁**
   16코어 서버에서 두 개의 스레드가 같은 캐시 라인 내의 서로 다른 변수 구조체를 동시에 업데이트함 (False Sharing). Write-Back 정책 하에서 각 코어는 자기 L1 캐시에 신나게 값을 쓴다. 그런데 코어 1이 쓴 값을 코어 2가 읽으려 하면, 메인 메모리에는 아직 원본이 반영 안 되었으므로 옛날 값이 있다. 이를 막기 위해 버스 상에서 **Snooping** 프로토콜이 가동되어, "야! 코어 1 캐시에 있는 게 최신형이야! 램에서 읽지 말고 코어 1한테서 직접 가져와!"라는 복잡한 MESI 신호가 오간다.

3. **SSD의 내부 DRAM 캐시와 정전 사고 (PLP)**
   엔터프라이즈 DB용 SSD를 구매했는데, 싸구려 SSD는 갑작스러운 정전 시 데이터베이스 트랜잭션이 다 날아가서 코럽션이 터짐. SSD 내부 컨트롤러도 속도를 위해 내부 DRAM을 **Write-Back** 모드로 쓴다. OS가 쓰기 명령을 내려도 낸드에 안 쓰고 자기 DRAM에만 쓰고 "저장 끝!"이라고 뻥을 친다. 이때 정전이 나면 DRAM 데이터가 다 날아간다. 엔지니어는 반드시 슈퍼콘덴서가 내장되어 정전 시에도 DRAM의 데이터를 낸드로 영구 기록해 주는 **PLP (Power Loss Protection)** 기능이 있는 기업용 SSD만 채택해야 한다.

### 안티패턴
- **Write-Through로 설정된 구형 메모리 매핑 장치(MMIO)에 대량 쓰기**: 그래픽카드 프레임 버퍼 주소를 CPU 메모리 공간에 매핑해놓고, 화면을 렌더링 한답시고 픽셀 데이터를 `for` 문으로 1바이트씩 100만 번 쓰는 코딩. MMIO 영역은 시스템 안정성을 위해 캐시를 안 거치는 Write-Through로 설정되는 경우가 많다. 100만 번의 쓰기가 곧이곧대로 100만 번의 PCIe 버스 트래픽을 유발하여 시스템이 초당 1프레임으로 박살 난다.

- **📢 섹션 요약 비유**: Write-Back 캐시를 믿는 것은 신용카드를 쓰는 것과 같습니다. 평소엔 현금(메모리 대역폭) 없이도 마음껏 수정할 수 있어 너무 편하지만, 결제일(Eviction)이 다가오면 그동안 밀린 빚을 한 방에 갚아야 하는 엄청난 트래픽 부담이 터집니다.

---

## Ⅴ. 기대효과 및 결론

### 기술 진화와 미래 전망
- **Non-Volatile RAM (NVDIMM/옵테인)의 혁명**: Write-Back의 유일한 단점은 "정전 시 캐시에 있는 수정본이 날아간다"는 점이다. 메인 메모리 자체가 전기를 꺼도 데이터가 보존되는 비휘발성 램으로 바뀌는 시대가 오면, Write-Back 중에 전기가 끊겨도 데이터가 증발할 걱정이 없어지므로 캐시 동기화 아키텍처 자체가 완전히 재설계될 것이다.
- **디렉터리 기반 코히런시**: 코어가 64개 이상으로 늘어나니, 각자 Write-Back한 놈이 누구인지 버스에 소리치며 찾는 방식(Snooping)은 통신량이 너무 많아 터져버렸다. 현대의 서버용 프로세서는 캐시의 갱신 상태를 중앙 전화번호부(디렉터리)에 기록해 두고 핀포인트로 통신하는 방식으로 진화했다.

### 결론
쓰기 정책은 속도를 얻기 위해 데이터의 무결성을 언제, 어떻게 희생할 것인가를 다루는 하드웨어의 줄타기다. **Write-Back의 발명**은 폰 노이만 병목을 극복하는 데 있어서 캐시 용량 증대 못지않은 혁명이었다. 메모리로 나가는 쓰기 트래픽의 90%를 칩 안에서 삼켜버림으로써, 데이터 버스의 숨통을 틔워 주었고 지금의 멀티코어 전성시대를 가능케 했다. "모든 것을 즉시 보고하지 마라. 네 선에서 고치고, 쫓겨날 때 최종 결과만 보고하라"는 이 위임의 철학이 오늘날의 마이크로프로세서를 1초에 50억 번 뛰게 만드는 진짜 비결이다.

- **📢 섹션 요약 비유**: Write-Back 정책은 훌륭한 중간 관리자의 표본입니다. 실무진(CPU)이 문서를 고칠 때마다 일일이 사장님(메모리)께 보고하는 짓은 사장님을 과로사시킵니다. 중간 관리자가 모든 수정을 자기가 안고 있다가, 부서를 이동할 때(쫓겨날 때) 완벽한 최종 보고서 하나만 사장님 책상에 올리는 것이 가장 훌륭한 회사 시스템입니다.

---

### 📌 관련 개념 맵

| 개념 명칭 | 관계 및 시너지 설명 |
|:---|:---|
| **Write-Through** | 캐시와 메모리를 항상 즉시 똑같게 맞추는 정책으로 속도는 느리지만 무결성이 완벽한 극상성 정책. |
| **더티 비트** | Write-Back 정책에서 캐시의 값이 메모리 원본과 달라졌음을 하드웨어에 알리는 단 1비트의 꼬리표. |
| **MESI 프로토콜** | Write-Back으로 인해 각 코어의 캐시 값이 서로 다르게 놀아나는 무질서를 막고 데이터를 일치시키는 멀티코어 동기화 마법. |
| **희생양 방출** | 꽉 찬 캐시에서 자리를 빼앗길 때, 더티 비트가 켜져 있으면 메모리에 무거운 쓰기 작업을 치르고 전사하는 과정. |
| **쓰기 버퍼** | Write-Through의 느린 메모리 쓰기 지연을 가리기 위해, CPU의 쓰기 명령만 잽싸게 받아두고 뒤에서 처리하는 작은 큐. |

---

### 👶 어린이를 위한 3줄 비유 설명
1. 내가 그림을 그릴 때 스케치북에 연필로 그렸다가 지우개로 10번을 고치고 나서 마지막에 벽에 예쁘게 딱 한 번만 붙이는 걸 '나중 쓰기(Write-Back)'라고 해요.
2. 반대로 연필을 한 번 움직일 때마다 벽에 붙은 도화지까지 뛰어가서 똑같이 고쳐 그리는 피곤한 방식을 '동시 쓰기(Write-Through)'라고 한답니다.
3. 컴퓨터는 한 번 고칠 때마다 벽까지 뛰어가면 너무 힘드니까, 무조건 스케치북에서 다 완성한 다음에 나중에 딱 한 번만 벽에 붙이는 빠르고 똑똑한 방식을 쓴답니다!