캐시 계층 구조, 메모리 병목을 단계별로 줄이는 원리

캐시 계층 구조, 메모리 병목을 단계별로 줄이는 원리

책상 위에는 지금 쓰는 서류 몇 장만 놓고, 자주 꺼내는 서류는 손이 닿는 서랍에, 나머지는 복도 끝 문서 보관실에 둡니다. 보관실이 아무리 크고 정리가 잘 되어 있어도 서류 한 장마다 복도를 오가면 일이 진행되지 않죠.

프로세서도 똑같은 고민을 합니다. 이 글에서 다룰 캐시 계층 구조는 용량이 작고 빠른 저장 공간을 코어 가까이에 여러 단으로 두어, 느린 메모리를 오가는 횟수를 줄이는 방법입니다.

사무실과 다른 점이 있습니다. 서류는 사람이 골라서 서랍에 넣지만, 캐시에 무엇을 둘지는 하드웨어가 자동으로 정합니다. 게다가 같은 데이터가 여러 코어의 캐시에 동시에 들어 있을 때 내용을 맞추는 문제까지 풀어야 합니다.

프로세서와 DRAM 사이에 벌어진 속도 차이

프로세서 코어는 클록 한 주기에 명령을 여러 개 처리할 수 있지만, 코어 밖의 DRAM에서 데이터를 가져오는 데는 코어의 시간으로 보아 수백 클록 사이클이 걸리는 것이 일반적입니다. 연산 성능은 빠르게 늘어 왔는데 메모리 지연은 그만큼 줄지 못했고, 이 격차를 메모리 월(Memory Wall)이라고 부르기도 합니다.

그러면 전부 빠른 메모리로 만들면 되지 않을까요? 캐시에 쓰이는 SRAM(Static Random-Access Memory)은 셀 하나에 트랜지스터가 여섯 개 들어가는 구조가 일반적이어서, 트랜지스터 하나와 커패시터 하나로 끝나는 DRAM보다 면적이 훨씬 큽니다.

같은 면적에 담을 수 있는 비트 수가 적으니 같은 용량이면 훨씬 비싸고 전력도 더 씁니다. 그래서 빠르지만 작은 SRAM과 느리지만 큰 DRAM을 함께 쓰는 절충이 필요해졌습니다.

캐시가 통하는 이유, 시간 지역성과 공간 지역성

작은 캐시로 큰 효과를 내는 비결은 프로그램의 접근 패턴에 있습니다. 한 번 쓴 데이터는 곧 다시 쓰일 가능성이 높다는 성질을 시간 지역성(Temporal Locality), 한 주소를 읽으면 가까운 주소도 곧 읽을 가능성이 높다는 성질을 공간 지역성(Spatial Locality)이라고 합니다.

반복문 안의 카운터 변수는 시간 지역성의 전형적인 예이고, 배열을 앞에서부터 차례로 훑는 코드는 공간 지역성의 예입니다. 캐시가 데이터를 바이트 하나씩이 아니라 캐시 라인(Cache Line)이라는 묶음으로 가져오는 이유가 여기에 있으며, 라인 크기는 일반적으로 64바이트입니다.

다만 캐시 계층 구조의 효과는 프로그램이 지역성을 가질 때만 나옵니다. 넓은 메모리에 무작위로 흩어진 접근, 예를 들어 포인터를 계속 따라가는 자료구조나 아주 큰 해시 테이블에서는 캐시가 도움을 덜 줍니다.

캐시 계층 구조에서 L1, L2, L3가 나뉜 이유

코어가 데이터를 찾는 과정은 가까운 곳부터 차례로 물어보는 흐름입니다. 이 순서가 곧 캐시 계층의 동작 방식입니다.

데이터를 찾는 순서

  1. 코어가 주소를 내면 가장 가까운 L1 캐시부터 확인합니다. 있으면 캐시 히트(Hit)이고 몇 사이클 만에 끝납니다.
  2. L1에 없으면 캐시 미스(Miss)이며, 다음 단인 L2 캐시를 확인합니다.
  3. L2에도 없으면 여러 코어가 함께 쓰는 L3 캐시를 확인합니다.
  4. L3에서도 미스가 나면 메모리 컨트롤러가 DRAM에 요청해 캐시 라인 하나를 가져옵니다.
  5. 가져온 라인은 왔던 길을 따라 L3, L2, L1에 채워지고, 코어는 그제야 값을 받습니다.

각 단의 크기는 제품마다 다르지만 경향은 같습니다. L1은 코어마다 전용이고 수십 KB 수준이며 명령용과 데이터용으로 나누는 경우가 많습니다. L2는 수백 KB에서 수 MB, L3는 코어 여럿이 공유하며 수 MB에서 수십 MB까지 커지는 것이 일반적입니다.

왜 한 단이 아니라 여러 단일까요? 캐시가 커지면 원하는 데이터가 어디 있는지 찾는 회로가 복잡해지고 배선도 길어져서 접근 지연이 늘어납니다. 작고 빠른 캐시와 크고 느린 캐시를 겹겹이 두면, 대부분의 접근은 가장 빠른 단에서 끝나고 놓친 일부만 아래 단이 받아 주는 구조가 됩니다.

여기서 캐시는 클수록 무조건 빠르다는 말은 흔한 오해입니다. 용량이 커지면 미스는 줄지만 한 번 조회하는 시간은 늘기 때문에, 설계자는 히트율과 지연 사이의 균형점에서 용량을 정합니다.

평균 접근 시간으로 계산해 보는 캐시의 효과

캐시의 효과는 평균 접근 시간으로 따져 볼 수 있습니다. 어떤 단에서 미스가 나면 그 아래 단의 시간이 더해지므로, 계산은 가장 아래 단부터 안쪽으로 묶어 올라갑니다.

가상 계산 예시, 평균 접근 시간실제 제품 값이 아니라 설명을 위한 가정입니다. L1 조회 4 사이클(히트율 90%), L2 조회 14 사이클(L1 미스 중 80%가 히트), L3 조회 40 사이클(남은 것 중 75%가 히트), DRAM 200 사이클로 둡니다.

평균 접근 시간 = 4 + 0.1 × (14 + 0.2 × (40 + 0.25 × 200)) = 4 + 0.1 × (14 + 0.2 × 90) = 4 + 0.1 × 32 = 7.2 사이클입니다. 캐시 없이 매번 DRAM에 간다면 200 사이클이므로 약 28배 차이가 납니다.

이 계산에서 눈여겨볼 곳은 히트율입니다. 같은 가정에서 L1 히트율만 99%로 올리면 4 + 0.01 × 32 = 4.32 사이클이 되어, 히트율 몇 퍼센트포인트가 평균 시간을 크게 움직인다는 것을 알 수 있습니다.

미스가 나는 원인은 보통 세 가지로 나눕니다. 처음 쓰는 데이터라서 나는 미스, 작업 집합이 캐시보다 커서 나는 미스, 서로 다른 주소가 같은 자리를 두고 다투어서 나는 미스입니다. 어느 쪽인지에 따라 해법이 캐시 용량 확대일 수도, 배치 방식 변경일 수도, 코드의 접근 순서 변경일 수도 있습니다.

교체 정책과 일관성, 계층이 만든 새 숙제

캐시가 가득 찼을 때 어떤 라인을 내보낼지 정하는 규칙이 교체 정책(Replacement Policy)입니다. 가장 오래 쓰이지 않은 라인을 내보내는 LRU 방식이 대표적이고, 실제 하드웨어는 구현이 단순한 근사 방식을 쓰는 경우가 많습니다.

쓰기도 정해야 합니다. 값을 바꿀 때 캐시에만 쓰고 나중에 내보낼 때 아래 단에 반영하는 방식을 라이트백(Write-back), 바로 아래 단에도 함께 쓰는 방식을 라이트스루(Write-through)라고 합니다. 라이트백은 아래 단으로 가는 쓰기를 줄여 주는 대신 관리가 조금 복잡합니다.

코어가 여러 개면 문제가 하나 더 생깁니다. 코어마다 L1이 따로 있으니 같은 주소의 데이터가 서로 다른 값으로 남을 수 있어서, 이를 맞춰 주는 캐시 일관성(Cache Coherence) 프로토콜이 필요합니다. 캐시 계층 구조는 속도를 얻는 대신 이런 관리 회로를 추가로 떠안는 구조입니다.

L1, L2, L3와 메인 메모리 비교 표

구분L1 캐시L2 캐시L3 캐시메인 메모리(DRAM)
위치와 공유 범위코어 안, 코어 전용코어 근처, 전용 또는 소수 공유칩 안, 코어 전체 공유칩 밖 모듈이나 패키지
일반적인 용량 경향수십 KB수백 KB에서 수 MB수 MB에서 수십 MB수 GB 이상
접근 지연 경향가장 짧음, 수 사이클십여 사이클수십 사이클수백 사이클
주로 쓰는 셀SRAMSRAMSRAMDRAM
역할가장 자주 쓰는 데이터 상주L1 미스를 받는 완충코어 간 공유와 마지막 방어선전체 작업 데이터 저장
놓치기 쉬운 점캐시가 클수록 무조건 빠르다는 오해, 용량이 커지면 조회 지연도 함께 늘어납니다.

핵심 정리

프로세서와 DRAM의 속도 차이는 메모리 병목의 뿌리이고, 캐시 계층 구조는 지역성이라는 프로그램의 성질을 이용해 이 차이를 여러 단의 작은 SRAM으로 나눠 메웁니다. L1은 빠르고 작게, L3는 크고 공유하게 만들어 히트율과 지연의 균형을 잡습니다.

도입의 서랍과 보관실에 빗대면, 서랍을 아무리 키워도 책상 가까이 두면 꺼내기 불편해지고 보관실만 크게 하면 복도를 오가는 시간이 일을 막습니다. 그래서 단을 나누고 각 단의 히트율을 평균 접근 시간으로 따져 보는 것이 계층 설계의 핵심입니다.

면접 대비 질문

면접 대비 질문캐시를 한 단이 아니라 L1, L2, L3의 여러 단으로 나누는 이유를 지역성과 평균 접근 시간의 관점에서 설명해 보세요.

[답변 포인트] 프로세서와 DRAM의 속도 차이가 크고, 빠른 SRAM은 면적과 비용 때문에 크게 만들 수 없다는 점에서 시작합니다. 시간 지역성과 공간 지역성 덕분에 작은 캐시로도 높은 히트율이 나온다는 것, 용량이 커질수록 조회 지연이 늘어 단별로 용량과 속도를 나누게 된다는 것을 연결합니다. 평균 접근 시간이 히트 시간에 미스율과 미스 비용을 더한 식으로 계산되고 히트율이 조금만 달라져도 크게 변한다는 점, 멀티코어에서는 캐시 일관성이라는 추가 부담이 생긴다는 점까지 덧붙이면 좋습니다.