Cloudflare Workers 무료 티어 '10ms CPU' 벽 — 1101 에러를 못 보고 넘어간 이유
서버리스 함수가 무거워지자 요청당 CPU 10ms 한도를 넘겨 1101 에러가 난 상황을, Notion에 쌓아 둔 디버깅 노트를 바탕으로 재현 가능하게 정리합니다.

서버리스 함수를 무료 티어로 올리면 “요청이 와야 돈이 나간다”는 안도감이 먼저 든다. 그런데 그 안도감이 오히려 문제를 가린다. Notion에 남겨 둔 디버깅 노트에는 “Cloudflare Workers 무료 티어의 CPU 실행 한도는 요청당 10ms“라는 줄이 있다. 무거운 반복문, 복잡한 암호화 로직, 대량 데이터 가공이 이 10ms를 넘길 위험이 있는지 전수 조사하라는 지시가 바로 옆에 붙어 있다. 실제로 함수가 어느 순간 1101 에러를 반환하기 시작했고, 나는 그 원인을 “배포 실수”에서 찾고 있었다.
사실: 1101은 ’코드가 터졌다’가 아니라 ’시간이 다 됐다’일 수 있다
Cloudflare Workers에서 1101 에러는 런타임이 예외를 못 잡고 프로세스가 종료됐을 때 흔히 보인다. 그래서 처음엔 try-catch를 더 붙이자는 생각이 먼저였다. 그런데 문제는 예외가 아니라 CPU 시간 초과였다. 무료 티어는 요청당 10ms(유료는 50ms 이상)의 CPU 실행 한도를 두고, 이를 넘기면 요청이 실패로 끝난다. 외부 API 응답을 기다리는 시간은 CPU 시간에 안 잡히지만, 반복문·JSON 파싱·암호화·정렬 같은 실제 연산은 전부 잡힌다.
노트의 두 번째 줄도 결정적이었다. 무료 티어는 요청당 서브요청(외부 API 호출, D1/R2 접근 등)이 최대 5개로 제한된다. 한 번의 Worker 실행 안에서 DB를 여러 번 조회하면 이 5개를 금방 소진한다. 나는 “API를 몇 번 호출하는지는 아무 문제없겠지”라고 넘겼는데, DB 조회 + 외부 API + 캐시 갱신이 겹치면 서브요청 카운터가 이미 한계에 닿아 있었다. 문제는 한 가지만이 아니라 CPU 10ms와 서브요청 5개가 겹쳐 터졌다.
이유: ’됐겠지’의 근거가 전부 틀리지는 않았지만, 검증이 없었다
실패의 원인은 크게 두 갈래다. 첫째, 로컬 개발(wrangler dev)에서는 무료 티어 한도가 그대로 반영되지 않는다. 로컬에서 30ms 걸리던 연산이 프로덕션에서 10ms를 넘는 일은 흔하다. 로컬 통과 = 배포 통과라는 등식이 성립하지 않는다. 둘째, 연산량을 “느낌”으로 판단했다. 파싱할 데이터 크기가 커지면 CPU 시간은 선형보다 가파르게 늘 수 있는데, 그걸 측정하지 않고 “이 정도는 가볍겠지”로 넘겼다.
노트가 지적하는 해결 방향도 명확하다. 무거운 연산을 요청 경로에서 빼내거나, 데이터를 KV/R2 캐시에 미리 올려 서브요청을 1~2개로 압축하라는 것이다. 반복 순회를 다른 방식으로 바꾸라는 지시도 있었다. 결국 나는 반복문으로 재조립하던 데이터를 캐시에서 그대로 읽도록 바꿨고, CPU 시간과 서브요청 수를 동시에 줄였다.
평가: 무료 티어는 ’예산’이지 ’제약 없음’이 아니다
시니어 실무자 시각으로 남길 교훈은 세 가지다. 첫째, 서버리스 비용은 “요청 수”만 보고 판단하지 말고 요청당 CPU 시간과 서브요청 수를 함께 본다. 요청이 적어도 한 요청이 무겁다면 실패가 난다. 둘째, 로컬 통과를 배포 성공으로 믿지 않는다. 무료 티어 한도는 프로덕션 런타임의 실제 수치로 확인해야 한다. 셋째, 측정할 수 없으면 “가벼운 코드”라는 가정을 의심한다. 데이터가 커지면서 연산이 어떻게 변하는지가 핵심이다.
이 글은 특정 시점의 사이드 프로젝트 실측을 바탕으로 한다. Cloudflare의 무료 티어 정책·수치는 수시로 바뀌므로, 지금 이 글을 읽는다면 공식 문서의 최신 한도를 다시 확인해야 한다. 그런데 “숫자가 바뀌어도 사라지지 않는 것”은, 서버리스에서 병목은 코드의 무게가 아니라 런타임이 허용하는 시간과 호출 수라는 관점이다.
부연: 다음에 다시 마주한다면
같은 실수를 반복하지 않으려면 세 가지를 먼저 확인한다. (1) 요청당 실행 시간을 로그로 남겨 무료 티어 한도와 비교한다. (2) 서브요청이 몇 개인지, 캐시로 몇 개로 줄일 수 있는지 테스트한다. (3) 무거운 파싱·암호화가 있다면 배치 작업으로 빼거나, 유료 티어의 여유를 쓸지 결정한다. 그래도 “무료로 충분하다”고 단정하지 않는다. 무료 티어는 실험용 샌드박스이지, 무거운 상용 경로의 기본값이 아니다.
한계도 밝힌다. 이 글은 내부 실측과 Notion 노트를 재구성한 것이며, 정확한 응답 코드·설정 키는 공개 범위를 고려해 일부러 생략했다. 1101이 항상 CPU 초과를 뜻하는 것은 아니다. 예외가 안 잡혀도 1101이 날 수 있으므로, 같은 에러라도 원인은 로그로 다시 확인해야 한다. 이 글이 “1101 = CPU 초과”라는 공식으로 오용되지 않길 바란다.