클라우드플레어 무료라길래 막 만들었더니
무료 한도가 넉넉하겠거니, DB도 작겠거니 하고 학원 시스템을 막 만들었더니 하루 읽기 한도 500만 줄을 넘겨 조회와 저장이 전부 멈췄습니다. 화면은 열리는데 데이터만 안 나오던 며칠의 기록과, 대충은 로컬까지만이라는 교훈입니다.
무료 한도가 넉넉하다길래 그냥 믿었습니다. 실제로 얼마인지는 찾아보지도 않았고요. 데이터도 어차피 작을 테니 DB야 뭐 얼마나 크겠어 싶어서, 막 만들었습니다.
그랬더니 조회도 저장도 전부 멈췄습니다. 화면은 멀쩡히 열리는데 데이터만 하나도 안 나옵니다. 하루 읽기 한도 500만 줄을 넘긴 거였고, 이런 건 살면서 처음이었습니다.
먼저 말해 두면 클라우드플레어 탓이 아닙니다. 한도에 걸린 건 Pages가 아니라 데이터베이스(D1)였고, Pages는 여전히 제 최애입니다. 소규모 서비스를 막 찍어내기에 이만한 게 없습니다. 명령어 한 줄이면 배포가 끝나고(업로드가 4초도 안 걸립니다), 배포마다 미리보기 주소가 따로 생기고, 서브도메인도 금방 붙습니다. 블로그도, 외주 소개 사이트도, 앱 데모도 전부 이렇게 찍어냈습니다. 그 편함에 취해서 한도는 확인도 안 했던 겁니다.
바이브코딩은 대충 해도 되는 게 로컬까지입니다. 남이 쓰는 순간부터는 다른 게임이었습니다.
무료 한도, 이렇게 셉니다
몰랐던 게 하나 있었습니다. 한도는 DB가 얼마나 크냐가 아니라 얼마나 훑었냐로 셉니다. 클라우드 데이터베이스(D1)는 화면에 보여 준 줄이 아니라 답을 찾느라 훑은 줄로 셉니다. 5,000줄짜리 표를 조건 없이 읽으면 결과가 1줄이어도 5,000줄입니다.
하루 무료 한도는 읽기 500만 줄입니다. DB가 작으니 괜찮을 줄 알았는데, 아니었습니다. 사용량은 DB 크기가 아니라 쌓인 기록의 길이와 화면을 여는 횟수를 곱한 만큼 늘어납니다.

9월 21일 밤
한도 초과 오류가 두 번 찍혔습니다. 조회도 저장도 다 실패. 일단 개발과 배포를 멈췄고, 알아서 돌던 자동 실행기도 껐습니다.
9월 22일, 일단 유료로
유료 요금제로 바꾸니 바로 살아났습니다. 읽기 한도가 월 250억 줄이라 돈 걱정은 크지 않았습니다. 그날 1차 수정도 배포했습니다.
그런데 이건 수리가 아니라 반창고였습니다. 한도 실패만 사라졌을 뿐, 낭비하는 구조는 그대로였으니까요.
아니나 다를까 9월 23일에 다시 폭주했습니다. 하루 약 534만 줄입니다.

범인을 찾아 봤습니다
조회별 통계에서 많이 읽은 순서대로 뽑고, 코드에서 그 조회를 찾았습니다. 쿼리 계획을 열어서 전체를 훑는지(SCAN), 목차를 쓰는지(SEARCH)도 봤습니다.
범인은 하나가 아니었습니다. 세 가지가 곱해져 있었습니다.
- 목차가 없는 조회: 학생 번호로 찾는 조회에 색인이 없어서 매번 표 전체를 훑었습니다. 학생 한 명의 보고서를 여는데 모든 학생의 기록을 꺼낸 셈입니다
- 통째로 읽는 첫 화면: 직원 앱을 열거나 저장한 뒤 다시 불러올 때, 26개(나중엔 약 35개) 표에서 모든 반의 몇 달 치 이력을 한꺼번에 읽었습니다
- 짧은 간격의 자동 새로고침: 관리실 화면은 탭이 보이는 동안 12초마다 쿼리 9개 이상을 돌렸습니다. 하루 80분만 열어 둬도 약 400회입니다
여기에 한 가지가 더 있었습니다. 어느 반에서 무엇을 입력하든 학원 전체의 번호 하나가 올라가서, 열려 있던 모든 반의 뷰어가 처음부터 다시 만들어졌습니다. 교실 하나 칠판을 고쳤는데 학원 전체 방송으로 모든 교실이 칠판을 다시 쓰는 꼴이었습니다.
9월 22일 하루, 특히 많이 읽은 조회는 이랬습니다.
| 조회 | 횟수 | 읽은 줄 | 화면 |
|---|---|---|---|
| 회차별 시험·과제 개수 세기 | 51회 | 약 143만 | 학생 상세 보고서 |
| 듣기 결과 목록 계산 | 402회 | 약 76만 | 관리실 보드 |
| 시험별 수업·과목 찾기 | 18회 | 약 62만 | 학생 상세 보고서 |
이 셋이 상위 20개 조회의 약 67%였습니다. 다만 상위 20개의 합계(약 418만 줄)가 그날 전체 사용량은 아닙니다.
의외였던 건 주범이 학생 앱이나 학부모 앱이 아니라 직원 화면이었다는 점입니다. 손님이 쓰는 쪽이 아니라 우리가 쓰는 쪽이 범인이었습니다.
고쳤습니다
- 9월 22일: 이미 있는 걸 또 넣는 요청과 반복 재조회를 없앴습니다. 목차를 달았고, 연속 수정은 묶어서 한 번만 새로고침, 숨긴 탭에서는 미룹니다
- 9월 25일: 다른 반의 입력 때문에 내 반 뷰어가 다시 만들어지지 않게 반과 날짜 단위로 판단합니다. 이력은 120일 창으로 자르고, 같은 성적이 두 번 들어가지 않게 중복 방지 키를 달았습니다
- 9월 27일: 읽기 목차를 더하고, 바뀐 게 없으면 다시 읽지 않게 했습니다. 마지막 수정 번호만 확인해서 같으면 “그대로 쓰세요” 하고 끝냅니다
- 감시: 15분마다 하루 사용량을 읽어서 무료 한도의 50%, 80%, 100%에서 단계별로 경고합니다
데이터베이스를 바꾸거나 기록을 지워서 비용을 줄이는 일은 일부러 하지 않았습니다. 지금 근거로는 바꿀 이유가 없다고 봤습니다.
지금은 어떤가
수업 없는 날인 9월 26일에 하루 약 13만 줄이었습니다. 폭주하던 날 저녁 한 시간에 16.4만 줄 읽던 게 3.4천 줄로 줄었습니다. 약 48분의 1입니다.
다만 좋아졌다고 딱 잘라 말하기엔 이릅니다. 수업이 있는 날의 실측이 아직 없고, 자동 실행기를 멈춘 효과와 코드를 고친 효과가 섞여 있습니다. 같은 부하끼리(수업일 대 수업일) 비교해야 진짜 수치가 나옵니다. 그 전까지는 절감률을 말하지 않기로 했습니다.
바이브코딩 101
로컬에서는 대충 해도 됩니다. 화면이 뜨면 일단 성공이니까요. 그런데 남이 쓰는 서버에 올리는 순간, 화면이 뜬다는 것은 아무것도 보장하지 않습니다. 이번에는 화면이 열린 채로 데이터가 전부 실패했습니다.
- 새 조회를 만들면 쿼리 계획으로 전체 훑기가 아닌지 봅니다
- 자동 새로고침은 30초 이상 간격으로, 숨긴 탭에서는 멈춥니다
- 한도 근접 경고가 뜨면 기능 개발을 멈추고 사용량부터 줄입니다
- 유료 전환은 응급처치입니다. 낭비 구조를 고치지 않으면 한도 실패만 사라집니다
그래도 클라우드플레어는 계속 씁니다. 다만 이제는 만들기 전에 한도표부터 봅니다.
이 시스템이 어떻게 생겼는지는 빌드 노트에 적었습니다.
여러 에이전트와 작업 폴더를 쓰다가 최신 화면이 옛 배포로 덮인 일은 배포 롤백을 복구한 기록에 따로 적었습니다. 운영에서는 사용량뿐 아니라 어느 소스가 공개됐는지도 확인해야 했습니다.
새 글 소식
새 글이 나오면 메일로 알려 드립니다.
새 글 주소와 한 줄 요약만 보냅니다. 광고는 보내지 않습니다.