CPU, 메모리, 디스크, 브라우저 캐시, Redis 같은 DB 캐시까지…

다 따로 노는 개념처럼 보이지만, 사실 전부 “느린 것 대신 빠른 곳에 미리/자주 저장해두자”는 같은 아이디어에서 출발한다.

이번 글에서는:

  • 메모리 계층 구조
  • 캐시와 지역성의 원리
  • 캐시 히트 / 캐시 미스
  • 캐시 매핑 방식
  • 웹 브라우저의 캐시 (쿠키, localStorage, sessionStorage)
  • 데이터베이스 캐싱 계층 (Redis)

까지 한 번에 묶어서 정리해본다.


1. 메모리 계층 구조: 왜 계층이 필요할까?

CPU는 엄청 빠른데, 메모리는 그 정도로 빠르지 않다.

디스크나 네트워크까지 가면 더더욱 느려진다. 그래서 시스템 구조는 이렇게 생겼다:

레지스터 (Register)
       ↓
L1 캐시
       ↓
L2 캐시
       ↓
L3 캐시
       ↓
메인 메모리 (DRAM)
       ↓
SSD / HDD
       ↓
원격 스토리지, DB, 네트워크

아래로 갈수록:

  • 속도는 느려지고
  • 용량은 커지고
  • 비용은 싸진다

이 계층 구조 덕분에, 자주 쓰는 데이터는 위쪽(빠른 계층)에 두고,

덜 자주 쓰는 데이터는 아래쪽(느린 계층)에 둬서 속도와 비용을 동시에 잡는 전략을 쓴다.


2. 캐시(Cache)란? — “위 층에 두는 복사본”

캐시는 한 줄로 정리하면:

느린 저장장치(메모리/디스크/네트워크)에 있는 데이터를 빠른 저장장치에 “복사본”으로 보관해두는 구조

CPU 입장에서는:

  • 캐시 = 메모리의 복사본

웹 브라우저 입장에서는:

  • 캐시 = 서버 리소스(HTML, JS, 이미지 등)의 복사본

DB 입장에서는:

  • 캐시 = 디스크나 원격 DB에 있는 데이터의 복사본 (예: Redis)

공통점:

자주 쓰는 것을 더 빠른 공간에 미리 올려둠으로써 평균 접근 시간을 줄인다.


3. 지역성의 원리: 캐시가 먹히는 이유

캐시는 “운 좋으면 빠르고, 아니면 말고”가 아니다.

CPU나 프로그램이 실제로 “지역성(Locality)” 이라는 패턴을 보이기 때문에 잘 먹힌다.

3-1. 시간 지역성 (Temporal Locality)

한 번 접근한 데이터는 가까운 미래에 또 접근될 가능성이 크다.

예:

  • for 루프 안에서 같은 변수 계속 사용
  • 최근에 사용한 함수가 다시 호출
  • 스택 프레임, 전역 변수, 카운터 등

그래서 “최근에 사용한 것들을 캐시에 남겨두자”는 전략이 의미가 있다.

3-2. 공간 지역성 (Spatial Locality)

어떤 주소에 접근했다면, 그 주변 주소에도 곧 접근할 가능성이 크다.

예:

  • 배열 순회 arr[0], arr[1], arr[2] …
  • 연속된 구조체 접근
  • 코드도 메모리에 연속적으로 올라가 있으므로, 인근 명령어들을 순차 실행

그래서 캐시는 한 번에 한 워드만 가져오지 않고, 그 주변까지 한 덩어리(블록 또는 라인)로 가져온다.

3-3. 요약

  • 시간 지역성: “다시 쓸 가능성이 크다 → 캐시에 오래 보관”
  • 공간 지역성: “옆 주소도 쓸 가능성이 크다 → 주변을 같이 가져오자”

CPU 캐시, 디스크 캐시, DB 캐시, 웹 캐시 모두 이 개념을 활용한다.


4. 캐시 히트와 캐시 미스

캐시를 쓴다는 건 결국 다음 둘 중 하나다.

✔ 캐시 히트(Cache Hit)

CPU(또는 프로그램)가 찾는 데이터가 캐시에 이미 있는 경우

  • CPU: L1/L2/L3 캐시에서 찾음
  • 브라우저: 로컬 캐시에 HTML/JS/이미지 이미 있음
  • Redis: 메모리에서 바로 해당 키를 찾음

→ 매우 빠르다.

→ CPU 캐시의 경우, CPU 내부 버스만 타고 끝나기 때문에 레이턴시가 극도로 짧다.

✔ 캐시 미스(Cache Miss)

캐시에 없어서 더 아래 계층(느린 계층)까지 내려가서 데이터를 가져와야 하는 경우

CPU 입장에서는:

  • 캐시에 없음 → 메인 메모리(DRAM)까지 가야 함 → 시스템 버스를 타고 왕복 → 느림

DB 입장에서는:

  • Redis에 없음 → 디스크 기반 RDB까지 조회 → 느림

웹 브라우저 입장에서는:

  • 브라우저 캐시에 없음 → 서버까지 HTTP 요청 → 느림

그래서 시스템들은 최대한 히트율(hit ratio) 을 올리려고 한다.


5. 캐시 매핑 방식 (CPU 캐시 관점)

CPU 캐시에서 데이터가 “어디에 놓이는가?” 를 결정하는 규칙이 캐시 매핑(Cache Mapping)이다.

5-1. Direct Mapped Cache

메인 메모리의 특정 블록은 캐시의 딱 한 위치에만 저장 가능

  • 장점: 구현이 단순, 빠름
  • 단점: 충돌이 많을 수 있음 (자주 쓰지만 같은 인덱스를 공유하는 데이터들)

5-2. Fully Associative Cache

메모리 블록이 캐시 어느 곳에나 저장될 수 있음

  • 장점: 충돌 최소화
  • 단점: 어디에 있는지 찾기가 복잡 (비싸고 느림)

5-3. Set Associative Cache (실제 많이 사용)

캐시를 여러 set으로 나누고,

각 set 안에서는 associative하게 배치 가능

  • 예: 4-way set associative
  • Direct와 fully associative의 타협안
  • 현대 CPU에서 가장 일반적인 방식

이 매핑과 더불어:

  • 어떤 블록을 버릴지(교체 정책: LRU, Random 등)
  • 쓰기 정책(write-back, write-through)

까지 합쳐져 캐시의 성능이 결정된다.


6. 웹 브라우저의 캐시: 메모리 계층의 “상위 레벨” 버전

웹 개발을 하다 보면 또 이런 캐시들이 등장한다:

  • HTTP 캐시 (브라우저가 리소스를 저장)
  • 쿠키(Cookie)
  • localStorage, sessionStorage

여기서 쿠키 / localStorage / sessionStorage는 좀 역할이 다르다.

6-1. 쿠키(Cookie)

  • 서버나 자바스크립트가 브라우저에 심는 작은 데이터 조각
  • 매 요청마다 HTTP 헤더에 실려서 서버로 전송됨
  • 주로 로그인 세션, 트래킹, 사용자 식별 등에 사용
  • 용량이 작음(수 KB 단위), 보안 이슈 있음(HTTP 전송)

쿠키는 “캐시”라기보다는 상태 유지용에 더 가깝지만,

“서버가 매번 다시 묻지 않기 위해” 정보를 로컬에 저장한다는 점에서 넓은 의미의 캐시로 볼 수도 있다.

6-2. localStorage

  • 도메인별로 영구 저장되는 키-값 저장소
  • 브라우저를 껐다 켜도 남아있음
  • JS에서 localStorage.setItem(key, value) 로 접근
  • 서버에 자동으로 전송되지 않음 (쿠키와 가장 큰 차이)

예:

  • 다크 모드 설정
  • 최근 본 상품 리스트
  • 사용자의 간단한 환경설정

6-3. sessionStorage

  • 탭 단위로 살아있는 저장소
  • 탭을 닫으면 사라짐
  • 페이지 리로드 시에는 유지됨

예:

  • 특정 페이지에서만 쓰는 임시 상태
  • 탭마다 분리되어야 하는 데이터

6-4. 진짜 “웹 캐시” — HTTP 캐시

여기까지 오면 진짜 캐시다운 캐시가 나온다.

  • HTML, CSS, JS, 이미지 파일 등을 브라우저가 로컬 디스크/메모리에 저장
  • 다음에 같은 URL에 접근할 때,
    • 만료 안 됐으면 그대로 사용 (Cache Hit)
    • 만료됐거나 조건부 요청시 서버에 재검증

이건 CPU–메모리 캐시와 거의 동일한 개념이다:

  • 원본: 서버의 리소스
  • 복사본: 브라우저 로컬 캐시
  • 목표: 네트워크 왕복 줄이기

7. 데이터베이스의 캐싱 계층 (Redis 등)

백엔드 쪽으로 가면 또 하나의 “메모리 계층” 구조가 보인다.

일반적인 구조:

CPU / 애플리케이션 (서버 코드)
          ↓
       Redis (인메모리 캐시, key-value)
          ↓
   RDBMS (MySQL, PostgreSQL 등, 디스크 기반)
          ↓
   디스크 / 스토리지

역시 똑같다.

  • 자주 읽히는 데이터는 메모리에 띄워놓고 빠르게 제공
  • 덜 자주 쓰이거나, 영구 보관이 필요한 데이터는 디스크 기반 DB에 저장

7-1. Redis의 역할

Redis는:

  • 메모리 기반 key-value 저장소
  • 읽기·쓰기 속도가 매우 빠름
  • 세션 관리, 랭킹, 카운터, 토큰 저장 등에서 자주 사용

예:

  • GET user:123 → Redis에서 바로 나오면 DB까지 안 내려감 → Hit
  • Redis에 없으면 → MySQL 쿼리 → 결과를 Redis에 저장 → Miss 후 Fill

이 구조를 통해:

  • DB 부하 분산
  • 응답 시간 단축
  • 스케일 아웃 용이

결국 DB도 자체적으로 “메모리 계층”을 쌓는 것이다.


8. 전체 그림: 모든 레벨의 캐시를 한 번에 묶어 보면

조금 과장해서 그려보면, 요즘 서비스 하나를 띄웠을 때 메모리 계층은 이렇게 된다:

[CPU 레지스터]
   ↓
[CPU 캐시 (L1/L2/L3)]
   ↓
[메인 메모리 (프로세스 힙/스택)]
   ↓
[OS 페이지 캐시, 버퍼 캐시]
   ↓
[DB 캐시 (MySQL InnoDB Buffer Pool 등)]
   ↓
[Redis 같은 인메모리 캐시]
   ↓
[디스크 기반 RDBMS 데이터 파일]
   ↓
[원격 스토리지, 백업, 데이터 레이크 …]

+ 클라이언트 쪽:
[브라우저 메모리]
   ↓
[브라우저 HTTP 캐시]
   ↓
[localStorage / sessionStorage / 쿠키]
   ↓
[네트워크 요청 → 서버]

위에서 아래로 내려갈수록:

  • 속도 ↓
  • 용량 ↑
  • 비용 ↓
  • 영속성 ↑

그 사이사이에 “캐시”라는 계층을 끼워넣어 성능을 끌어올리는 구조다.


9. 마무리 요약

  • 메모리 계층: 빠른 것(작고 비싸다)부터 느린 것(크고 싸다)까지 층을 쌓아둔 구조
  • 캐시: 느린 계층의 복사본을 빠른 계층에 두는 구조
  • 지역성의 원리 덕분에 캐시는 잘 먹힌다
    • 시간 지역성: 최근 쓴 걸 또 쓴다
    • 공간 지역성: 근처도 같이 쓴다
  • 캐시 히트/미스: 히트면 빠른 계층에서 해결, 미스면 아래로 내려가야 해서 느림
  • 캐시 매핑: 메모리 블록이 캐시에 어디에 배치되는지 결정(direct / associative / set-associative)
  • 웹 브라우저 캐시: HTTP 캐시 + 쿠키/localStorage/sessionStorage라는 다양한 형태로 존재
  • DB/Redis 캐시: DB 앞에 메모리 캐시 계층을 두어 읽기 성능을 끌어올리는 구조

결국 로우레벨(CPU 캐시)부터 하이레벨(웹, DB)까지 같은 아이디어가 반복해서 등장한다.

 

목표: Redis는 아직 사용해보지 않아서, 프로젝트에 적용해보려고 한다. 얼마나 빨라지려나!? 😬

오늘의 공부

'CS' 카테고리의 다른 글

[CS-운영체제] 컴퓨터의 요소  (1) 2025.11.17
[CS-운영체제] 운영체제의 역할과 구조  (0) 2025.11.16

+ Recent posts