← 컴퓨팅 인프라
심층 리포트DEEPER INTO TECHNOLOGY

Cloudflare Origin Range Requests: 부분 다운로드의 전송량은 왜 클까?

Cloudflare Origin Range Requests는 부분 다운로드의 원점 전송량을 어떻게 바꾸며, 내 파일 배포에도 적용할 수 있을까?

댓글 남기기 ↓
먼저 읽는 핵심

사용자가 받은 파일 조각의 크기와 CDN이 원점에서 가져온 크기는 다를 수 있다. Origin Range Requests는 저장된 조각과 진행 중인 다운로드를 조정해 대용량 파일을 제공한다. 도입 판단에는 작은 요청의 전송 증폭뿐 아니라 원점의 부분 응답, 파일 버전 일치, 전체 파일의 캐시 자격을 함께 봐야 한다.

2 KiB를 읽었는데 원점에서는 더 많이 내려온다

모델 배포 도구가 큰 가중치 파일의 메타데이터만 읽거나, 영상 플레이어가 재생 위치를 옮기는 상황을 생각해 보자. 전체 파일을 내려받지 않아도 되는 작업이다. 그런데 사용자가 받은 양은 작은데 저장소의 전송량이 늘고 첫 응답도 늦다면, 사용자에게 보낸 구간과 원점에서 가져온 구간을 따로 조사해야 한다.

2026년 10월 23일 Cloudflare는 Origin Range Requests를 모든 요금제에서 직접 설정할 수 있다고 발표했다. 고객이 구간 크기를 고르던 방식에서, 내부 캐시 조각을 기준으로 필요한 부분을 가져오는 방식으로 바뀐다. R2에서 p99 첫 바이트 시간이 대략 절반으로 줄었다는 수치는 공급자의 관측이다. 내 파일의 완료 시간이나 요금이 절반이 된다는 보장은 아니다.

이 글은 대용량 파일을 제공하는 팀의 도입 판단에 초점을 둔다. 공식 구현 설명과 HTTP 규격을 대조했고, 아래 수치는 가정에 따른 계산이다. Cloudflare 계정 설정·실제 원점·CDN 성능은 시험하지 않았다. 그림도 제품 화면이나 모니터링 캡처가 아닌 자체 설명도다.

부분 응답은 어느 연결의 부분인가

Range는 파일에서 원하는 위치를 요청하는 HTTP 헤더다. 바이트 위치는 0부터 세고 양 끝을 포함하므로 bytes=100-2147은 2,048바이트다. 정상적인 단일 부분 응답 206의 Content-Range는 반환 위치와 전체 길이를, Content-Length는 이번 본문 길이를 설명한다. 서버는 Range를 무시하고 200 전체 응답을 줄 수도 있다. RFC 9110의 Range·206 정의가 기준이다.

CDN이 끼면 통신은 적어도 두 구간이다. 클라이언트가 CDN에 보낸 요청 하나가 원점 요청 하나와 일대일로 대응한다고 가정할 수 없다. 따라서 클라이언트에서 확인한 206은 요청 구간을 받았다는 단서일 뿐, 원점도 같은 양만 보냈다거나 캐시에 적중했다는 증거가 아니다.

Cloudflare의 현재 동작 문서는 원점 요청을 1 MiB 경계에 맞추며 여러 단일 구간 요청으로 나눌 수 있다고 설명한다. 생성한 원점 요청에는 Accept-Encoding: identity를 넣는다. 클라이언트로 향하는 일반 압축까지 비활성화한다는 뜻은 아니다. 문서는 10월 24일 확인했으며 표시된 수정일 9월 14일을 제품 공개일로 해석하지 않는다.

이 차이는 원점 로그를 읽는 방법도 바꾼다. 클라이언트가 요구하지 않은 앞뒤 바이트가 보이거나 원점 요청 수가 늘어도 즉시 오작동으로 판단하지 않는다. 먼저 같은 파일·버전·관측 시간의 요청을 연결하고, 확대된 구간이 예상한 정렬과 맞는지 확인한다. 반대로 206만 보고 절감 성공으로 보고해서도 안 된다.

같은 2 KiB도 경계를 넘으면 계산이 달라진다

다음은 16 MiB 파일, 빈 캐시, 변하지 않는 하나의 표현을 가정한 계산이다. 필요한 1 MiB 조각을 끝까지 가져오고 재시도·압축·헤더·캐시 계층 사이의 추가 전송은 제외한다. 실제 네트워크 사용량 측정이나 과금 예측이 아니다.

클라이언트 요청 위치 반환할 양 가정상 원점에서 가져올 양
100부터 2,147까지 2 KiB 1 MiB
1,047,552부터 1,049,599까지 2 KiB 2 MiB
1,048,576부터 2,097,151까지 1 MiB 1 MiB

첫 요청은 한 조각 안에 들어간다. 두 번째는 1 MiB 경계 앞 1 KiB와 뒤 1 KiB를 요구하므로 조각 두 개에 걸친다. 이 모델의 가져온 양 ÷ 반환할 양은 각각 512배, 1,024배, 1배다. 큰 비율이 곧 나쁜 서비스라는 뜻은 아니다. 첫 읽기에서 가져온 나머지를 뒤의 요청이 재사용할 수 있기 때문이다.

두 개의 1 MiB 조각 사이 경계를 걸치는 2 KiB 요청. 원점에서 조각 두 개를 가져와도 클라이언트에는 요청한 2 KiB만 돌려주는 가상 계산 설명도.

단일 요청의 비용 대신 같은 파일을 읽는 작업 전체를 비교해 보자. 가령 첫 요청 다음에 같은 조각의 다른 부분을 읽는다면, 캐시가 유지되고 재사용 조건이 맞을 때 추가 원점 읽기를 줄일 여지가 있다. 반대로 사용자가 한 번 작은 부분만 읽고 떠나면 넓게 가져온 나머지는 그 사용자에게 쓰이지 않는다. 이 차이를 평균 캐시 적중률 하나로 설명하기 어렵다.

계산을 다시 사용할 때는 시작 위치를 s, 실제 필요한 길이를 n, 정렬 크기를 C로 놓는다. 파일 끝을 넘지 않는 범위에서 필요한 조각 수는 floor((s+n-1)/C) − floor(s/C) + 1이다. 마지막 조각이 파일 끝에서 짧아지는 경우는 별도로 잘라야 한다. 같은 식을 다른 CDN에 적용하려면 그 서비스의 가져오기 단위를 먼저 확인해야 한다.

본문 세 사례와 파일 끝·전체 파일 사례의 산술은 Python 3.11.12에서 확인했다. 작은 정수 입력은 바이트 집합을 직접 세는 방식으로도 대조했다. 이 검사는 경계 계산을 확인하며, Cloudflare의 요청 수·캐시 보관·동시성 구현을 재현하지 않는다. 입력과 가정은 계산 결과 JSON에 남겼다.

캐시는 파일 이름과 함께 “어디까지 있는가”를 알아야 한다

공식 발표가 설명하는 핵심은 이미 저장된 부분, 다운로드 중인 부분, 새로 가져올 부분을 한 응답에 이어 쓰는 조정이다. 다른 요청이 필요한 바이트를 이미 받고 있다면 그 다운로드에 합류할 수 있다. 구현 설명에서 말하는 공유는 이 전송 작업에 대한 설명이며 모든 동시 요청이 항상 하나로 합쳐진다는 약속은 아니다.

이 구조를 이해하려면 책 한 권이 있는지 묻는 대신, 필요한 페이지가 책상에 있는지·배송 중인지·아직 주문하지 않았는지를 나누어 생각하면 된다. 다만 파일에서는 페이지 번호뿐 아니라 판본도 맞아야 한다. 앞부분 v1과 뒷부분 v2를 붙여 놓으면 길이는 정상이어도 내용이 깨질 수 있다.

RFC 9111의 부분 콘텐츠 결합 조건은 같은 강한 검증자와 결합 규칙을 요구한다. 이는 일반 HTTP 캐시의 규칙이다. Cloudflare 원점 응답 문서는 ETag를 선택 사항으로 두되, 존재 여부와 값·전체 크기가 같은 캐시 표현의 응답 사이에서 일관돼야 한다고 명시한다. ETag 생략을 버전 혼합에 대한 안전 보증으로 읽어서는 안 된다.

파일 배포 담당자에게 남는 설계 선택은 명확하다. 같은 다운로드 URL의 바이트를 덮어쓰는 방식을 유지할지, 릴리스마다 바뀌지 않는 URL을 둘지 결정해야 한다. 후자는 이어받기 대상의 정체를 설명하기 쉽지만, 옛 파일의 보관 기간과 새 URL을 알리는 메타데이터 갱신도 필요하다. 이는 이 글의 설계 제안이며 해당 제품이 URL 버전 관리를 대신해 준다는 설명이 아니다.

이어받기에서 200은 새 파일일 수 있다

가상의 다운로드 도구가 v1 파일의 앞부분을 저장한 뒤 다시 연결했다고 하자. Range와 함께 강한 ETag를 If-Range에 넣으면, 표현이 같을 때만 부분을 요청할 수 있다. 검증자가 다르면 Range를 무시하고 전체 표현을 받는 경로로 간다. 약한 ETag는 If-Range에 사용하지 않는다. RFC 9110 §13.1.5의 조건이다.

아래는 성공적인 일반 GET을 전제로 한 클라이언트 설계 판단표다. 실제 다운로드 프로그램을 실행한 결과가 아니며 인증 실패·리다이렉트·네트워크 오류 등은 별도로 처리해야 한다.

받은 응답 저장 전에 확인할 것 다음 행동
206 부분 응답 위치·실제 본문 길이·이어받을 버전 맞는 위치에 기록하고 아직 없는 구간을 추적
200 전체 응답 전체 파일을 새로 받은 이유와 버전 옛 조각 뒤에 붙이지 않고 새 다운로드로 취급
416 범위 거부 현재 파일 길이와 요청 시작점 완료 상태·파일 교체·잘못된 위치를 구분
약속한 길이 전에 연결 종료 실제 받은 바이트와 미완료 구간 완성본으로 표시하지 않고 재시도 조건 결정

특히 200을 무조건 실패로 버리거나, 무조건 성공으로 이어 붙이는 두 처리를 피해야 한다. 이 사례에서 v2 전체 본문을 v1 앞부분 뒤에 붙이면 파일이 손상된다. 저장 중인 조각의 버전을 알 수 없다면 “몇 바이트 받았다”는 숫자만으로 안전한 재개를 결정할 수 없다.

모델 파일이나 설치 패키지처럼 최종 내용이 중요하면 전송 완료 뒤 배포자가 제공한 무결성 검증 수단과도 대조한다. ETag가 항상 암호학적 파일 해시인 것은 아니다. 조각의 버전 확인, 다운로드 완료, 배포 산출물 검증은 서로 다른 단계로 기록하는 편이 좋다.

켜기 전에 내 원점과 파일 조건을 좁힌다

Cache Rules 설정 문서에 따르면 on은 일치하는 적격 GET에서 원점 부분 요청 생성을 허용한다. default는 플랫폼 기본값을 따르며 현재 기본 활성 확장자는 없다. off여도 완전한 캐시 파일에서 부분 응답을 줄 수 있다. 기능을 켠다고 캐시 불가 응답이 캐시 가능해지지는 않는다.

따라서 첫 적용 대상은 공개 가능하고 버전이 고정된 파일 경로처럼 좁히는 편이 검증하기 쉽다. 현재 설정 위치는 Caching → Cache Rules다. 아래는 기존 규칙의 action_parameters에 들어갈 문서상 설정 조각이며, 완전한 API 요청이나 이 글에서 실행한 설정은 아니다. 계정·규칙 순서·일치 조건은 포함하지 않았다.

{
  "origin_range_requests": {
    "mode": "on"
  }
}

원점의 206에는 정확한 Content-Range와 숫자 Content-Length가 필요하고, 인코딩되지 않은 본문이어야 하며 Transfer-Encoding은 없어야 한다. 원점이 Range를 무시해 200을 주면 전체 파일을 내려받을 수 있다. 원점 응답 요구사항을 실제 응답과 대조할 부분이다.

작은 조각을 요청해도 캐시 크기 제한은 전체 객체 크기에 적용된다. 1 GiB 파일에서 2 KiB만 읽는다는 이유로 작은 파일 자격을 얻지는 않는다. 현재 Cache Reserve도 지원되지 않는다. 이 두 조건은 캐싱 제한 문서에서 확인할 수 있다. 요금제별 한도는 도입 시 해당 계정 조건으로 확인한다.

원점 요청을 인증하거나 호출 수를 제한하는 구성에서는 확대된 Range와 여러 요청이 허용되는지도 살펴야 한다. 클라이언트가 요청한 작은 구간만 통과시키도록 만든 원점 검증은 새 동작과 충돌할 수 있다는 분석이다. 권한 범위를 넓혀 해결하기보다, 원점이 검증하는 대상과 CDN이 생성하는 요청을 먼저 맞춰 본다.

도입 효과는 파일 한 종류와 관측 구간 두 개로 확인한다

처음부터 모든 파일 경로에 적용하기보다, 대표 작업 하나를 고른다. 영상이라면 한 번의 탐색, 패키지라면 중단 후 재개처럼 완료 조건이 있는 작업이 좋다. 아래 절차는 독자가 자기 환경에서 수행할 미실행 검증 제안이다.

먼저 동일 파일 버전과 동일 요청 순서를 정한다. 단일 조각 안, 경계를 가로지르는 구간, 파일 끝, 이미 받은 구간의 반복을 구분한다. HEAD의 헤더만으로 본문 길이나 전송 완료를 검증하지 말고, 실제 GET의 응답 본문과 원점 로그를 대조한다. 테스트 입력에는 민감한 파일이나 운영 인증 정보를 넣을 필요가 없다.

그다음 클라이언트 구간에서는 상태·본문 바이트·첫 바이트 시간·완료 시간·완료 여부를, 원점 구간에서는 요청 수·응답 상태·실제로 보낸 바이트를 따로 기록한다. 빈 캐시와 이미 읽힌 파일을 섞어 평균내지 않는다. 여러 사용자 실험은 같은 시간에 같은 파일을 읽는 조건을 고정해야 비교할 수 있다.

관측 결과 판단 방향 다음 확인
클라이언트 206, 원점 200·전체 전송 부분 전달은 되지만 원점 절감 근거 부족 원점 Range 지원·응답 변환
원점 바이트 감소, 요청 수 증가 대역폭과 요청 처리 비용의 교환 가능 원점 요청 요금·제한·오류율
첫 바이트 개선, 완료 시간 동일 시작 반응과 전체 전송 병목이 다름 처리량·느린 소비자·파일 크기
잘림·버전 불일치 발생 절감 수치보다 정확성 문제 우선 규칙 적용 중단 후 응답 계약 비교

이 비교로 선택이 달라지는 팀은 부분 읽기·재개 요청이 많고, 원점이 일관된 구간 응답을 제공하는 파일 배포 팀이다. 전체 파일을 매번 한 번만 읽는 업무, 캐시 자격이 없는 개인화 응답, 현재 지원 조합 밖의 경로는 같은 이점을 전제하기 어렵다. 속도 개선을 주장하려면 실제 업무 단위의 완료 시간까지 관측해야 한다.

도입 기록 양식을 내려받아 파일 버전·원점 조건·두 구간의 관측·되돌릴 기준을 적을 수 있다. 옛 파일이 남는 문제는 HTTP 캐시의 신선도와 재검증, 전송 도중 대기가 쌓이는 문제는 스트림과 느린 소비자로 이어진다. 다시 사용할 때는 글의 저장 기능을, 관련 주제를 찾을 때는 인프라 모음과 RSS를 이용할 수 있다.

다시 읽을 때의 기준
  • 클라이언트의 206 응답만으로 원점에서 가져온 양이나 캐시 적중을 알 수 없다.
  • 현재 문서의 원점 정렬 단위는 1 MiB다. 작은 요청도 경계를 걸치면 두 구간을 가져올 수 있다.
  • 이어받기 중 If-Range가 불일치해 200 전체 응답이 오면, 옛 조각 뒤에 붙이지 않는다.
  • 기능 활성화는 캐시 자격·전체 파일 크기 제한·Cache Reserve 지원 조건을 바꾸지 않는다.
SOURCES & CONTEXT

근거와 원자료

자료의 발행 시점과 이번 글에서 참고한 범위를 함께 기록합니다.

  1. Origin Range Requests: Serving large files without range-request tuning ↗Cloudflare Blog · 2026-10-23

    전체 요금제 공개·고정 캐시 조각·진행 중 전송 공유. R2 p99 관측은 공급자 보고이며 자체 성능 측정 아님.

  2. Cache Rules settings: Origin range requests ↗Cloudflare Docs · 상시 갱신 문서

    on/off/default, 현재 기본 활성 확장자 없음, 캐시 자격 별도. 2026-10-24 본문·앵커 재확인.

  3. Range request behavior ↗Cloudflare Docs · 상시 갱신 문서

    1 MiB 정렬·identity·원점 206 계약·전체 객체 크기 제한·Cache Reserve 제외. 표시 업데이트 2026-09-14는 공개일로 해석하지 않음.

  4. RFC 9110: HTTP Semantics ↗IETF / RFC Editor · 2022

    §13.1.5 If-Range, §14 byte ranges, §15.3.7 및 §15.5.17. 본문과 앵커 확인; 일반 규격과 공급자 구현 구분.

  5. RFC 9111: HTTP Caching ↗IETF / RFC Editor · 2022

    §3.3/3.4 불완전 응답 저장과 같은 strong validator의 부분 결합 조건. 전체 캐시 정책 설명으로 확대하지 않음.

갱신 기록

첫 원고. 공식 발표·설정·HTTP 규격을 대조하고 경계 정렬 계산과 도입 기록 양식을 작성했다. Cloudflare 운영 성능 실험은 하지 않았다.

오류를 발견했다면 댓글로 알려 주세요 →
S
Starhunter

테크독해 운영·편집. AI·IT의 개념과 기술을 연결해 읽습니다.

QUESTIONS & DISCUSSION

이 글에 댓글 남기기

댓글 공개 방식을 확인하고 있습니다. 개인정보나 비밀 값은 적지 마세요.

댓글을 불러오는 중입니다.

    새 댓글

    8자 이상. 비밀번호를 잊으면 직접 수정·삭제할 수 없습니다. 다른 서비스와 다른 비밀번호를 사용해 주세요.

    내 댓글 확인·수정·삭제

    등록 후 안내된 댓글 번호와 비밀번호를 입력하세요. 승인 대기 중인 댓글도 확인할 수 있습니다.