
배포가 느릴 때 추측 말고 단계별로 재야 하는 이유
배포 한 번에 대략 9분이 걸렸습니다. 나중에 거꾸로 따져 본 추정치지만, 오타 한 글자를 고쳐도 그만큼 기다려야 했습니다.
사내 그룹웨어를 저전력 NAS 한 대에 올려 돌리던 때입니다. 직원 수십 명이 매일 여는 시스템이었습니다.
범인은 뻔해 보였습니다. 그런데 그 범인을 잡고도 시간은 기대만큼 줄지 않았습니다.
앱 빌드 222초라는 확신
배포 스크립트는 소스를 NAS로 보내고, NAS가 그 소스로 앱을 통째로 빌드했습니다. Next.js 빌드 한 번에 222초가 걸렸습니다.
NAS의 CPU는 저전력 셀러론입니다. 무거운 컴파일을 약한 CPU가 매번 처음부터 하고 있으니 누가 봐도 병목이었습니다.
고치는 방향도 정석이 있습니다. 빌드는 빠른 곳에서 한 번만 하고, 서버에는 결과물만 보내 실행만 맡기는 방식입니다.
저는 시간을 재 보지 않고 바로 이 작업부터 들어갔습니다. 222초가 9분 중 가장 큰 덩어리라고 믿었기 때문입니다.
빌드를 PC로 옮기기까지
옮기는 일도 간단하지 않았습니다. 이미지 처리 라이브러리가 운영체제별 네이티브 바이너리를 쓰고 있었습니다.
윈도우 PC에서 빌드한 결과물은 리눅스 서버에서 돌지 않습니다. 그래서 PC 안의 리눅스 컨테이너에서, 서버와 같은 amd64 환경으로 빌드했습니다.
빌드가 끝난 앱 폴더를 꺼내 18MB짜리 압축 파일로 묶었습니다. 서버는 기본 Node 이미지에 이 파일을 풀어 넣기만 합니다.
서버에서 앱을 만드는 시간이 222초에서 8초로 줄었습니다.
서버에 올리기 전에 PC에서 먼저 확인했습니다. 리눅스용 바이너리로 이미지 변환이 되는지, 조립한 이미지가 부팅해서 상태 점검에 답하는지 봤습니다.
PC 쪽 빌드는 캐시를 살렸습니다. 처음 빌드는 123초, 코드 일부만 바뀐 빌드는 76초, 바뀐 게 없으면 10초 정도였습니다.
이 캐시는 PC에서만 쓸 수 있었습니다. 서버의 컨테이너 엔진은 버전이 낮아 빌드 캐시를 따로 붙잡아 두는 기능이 없었습니다.
그래서 빌드 설정 파일을 용도별로 나눴습니다. PC의 증분 빌드용, 서버의 조립 전용, 그리고 만일을 위한 서버 소스 빌드용입니다.
기존 경로는 지우지 않았습니다. PC의 컨테이너 데몬이 꺼져 있으면 예전처럼 서버에서 소스를 빌드하게 뒀습니다.
첫 시도는 549초
새 방식으로 처음 배포한 결과는 549초였습니다. 줄이려던 작업이 오히려 시간을 늘렸습니다.
원인은 권한 상승 명령이었습니다. "미리 만든 결과물로 조립하라"는 설정을 환경 변수로 넘겼는데, sudo가 실행되면서 환경 변수를 비웠습니다.
설정을 못 받은 서버는 기본값인 소스 빌드를 그대로 돌렸습니다. PC에서 한 번, 서버에서 또 한 번 빌드한 셈입니다.
sudo 뒤에 env로 변수를 직접 적어 넘기도록 고치자 조립이 8초로 돌아왔습니다.
캐시가 매번 깨지는 함정도 있었습니다. 지난 배포의 압축 파일이 빌드 폴더에 남아, 빌드 도구가 매번 소스가 바뀌었다고 판단했습니다.
결과물 폴더를 빌드 전에 지우는 것으로 막았습니다.
222초를 지우고 남은 5분
두 함정을 걷어 내고 다시 쟀습니다. PC 빌드가 캐시를 전부 맞은 상황에서도 배포 전체는 331초였습니다.
222초를 덜어 냈는데 5분 반이 남았습니다. 가장 큰 비용은 처음부터 다른 곳에 있었습니다.
그제야 배포 스크립트의 단계마다 경과 시간을 찍는 몇 줄을 넣었습니다. 단계가 끝날 때마다 몇 초가 흘렀는지 남기는 정도입니다.
단계별로 찍어 본 숫자
| 서버 쪽 단계 | 걸린 시간 |
|---|---|
| 전송·정리·압축 풀기 | 5초 |
| 스키마 파일 57개 적용 | 68초 |
| 보조 서비스 재빌드 | 131초 |
| 무중단 전환과 헬스체크 | 154~181초 |
여러 번 배포하며 단계마다 잰 값이라, 더해도 한 회차 합계인 331초와 맞지 않습니다. 154~181초도 회차마다 달라 범위로 적었습니다.
가장 긴 줄은 무중단 전환이었고, 그다음이 보조 서비스 재빌드였습니다. 둘 다 제가 의심하지 않던 단계입니다.
보조 서비스는 실시간 연결 같은 기능을 맡는 작은 서비스 두 개입니다. 소스가 거의 바뀌지 않는데도 배포 때마다 다시 빌드되고 있었습니다.
건너뛸 단계와 남길 단계
숫자가 나온 뒤에는 단계마다 줄여도 되는지를 따졌습니다.
보조 서비스 재빌드는 안전하게 줄일 수 있었습니다. 마지막으로 빌드한 소스의 해시를 PC에 기록해 두고, 해시가 같으면 재빌드 없이 기존 이미지로 띄웁니다.
비교에 쓰는 상태를 PC에 두었기 때문에 서버의 정리 단계와 DB는 건드리지 않습니다. 결과는 131초에서 1초였습니다.
스키마 68초는 일부러 남겼습니다. 같은 방식으로 "바뀐 스키마가 없으면 건너뛰기"를 만들 수는 있었습니다.
이 단계는 DB 구조를 코드에 맞추는 마이그레이션입니다. 건너뛰기 판단이 한 번 틀리면 새 코드가 옛 테이블 위에서 돌게 됩니다.
1분을 아끼려고 그 위험을 지고 싶지 않았습니다. 스키마 단계를 더 잘게 재 보려던 측정도 운영 DB에 쓰기가 필요해서 그만뒀습니다.
남은 181초는 하드웨어 몫
무중단 전환은 새 컨테이너를 띄우고, 헬스체크가 통과하면 요청을 넘기는 단계입니다. 실패하면 이전 컨테이너가 그대로 서비스를 계속합니다.
이 단계를 들여다보니 컨테이너 데몬의 아주 단순한 동작도 10~18초씩 걸렸습니다. 약한 CPU와 디스크가 데몬 자체를 느리게 만들고 있었습니다.
캐시나 건너뛰기가 닿지 않는 시간입니다. 장비를 바꾸기 전에는 바닥으로 보고 더 파지 않았습니다.
| 항목 | 이전 | 이후 |
|---|---|---|
| 서버 쪽 앱 빌드 | 222초 | 8초 |
| 보조 서비스 재빌드 | 131초 | 1초(소스 변경 없을 때) |
| 스키마 적용 | 68초 | 68초(유지) |
| 무중단 전환·헬스체크 | 측정 전(앱 빌드 포함) | 154~181초 |
| 배포 전체(변경 없는 배포) | 약 540초(예전 방식 추정치) | 332초 |
단계 계측은 앱 빌드를 PC로 옮긴 뒤에 넣었습니다. 예전에는 앱 빌드가 무중단 전환 스크립트 안에서 돌았기 때문에, 이전 열의 숫자를 더해도 배포 전체가 되지 않습니다.
변경 없는 배포 기준으로 약 38% 줄었습니다. 보조 서비스까지 다시 빌드해야 하는 배포는 487초였습니다.
외주 배포를 맡긴 대표라면
배포가 오래 걸린다고 물으면 "서버가 느려서요"라는 답을 듣기 쉽습니다. 이번에도 181초는 정말 서버 탓이었습니다.
다만 그 답을 받아들이기 전에 단계별 시간표를 요청해 보세요. 표가 있으면 어디가 장비 탓이고 어디가 설정으로 줄일 몫인지 같이 볼 수 있습니다.
표를 받았을 때는 가장 긴 줄부터 보세요. 그 줄을 줄이는 방법이 DB를 건드리는지도 함께 물어보세요.
지금도 이 배포 구조로 사내 그룹웨어를 업데이트합니다. 그 그룹웨어가 어떤 화면으로 돌아가는지는 그룹웨어 데모에서 확인하세요.
자체 서버에 올린 시스템이 업데이트 한 번에 몇 분씩 걸린다면, 지금 배포 과정을 단계별로 재는 일부터 같이 볼 수 있습니다. 문의 양식에 지금 배포 방식과 걸리는 시간만 적어 두셔도 출발점으로 충분합니다.
다음 배포 개선 후보
이번에 가장 크게 틀린 건 순서였습니다. 단계별 계측을 넣은 시점이 앱 빌드를 옮긴 뒤였습니다.
다음 배포 개선에서는 아래 순서를 지키려고 합니다.
- 배포 스크립트에 단계별 경과 시간을 찍는 줄을 처음부터 넣고, 끝나도 지우지 않습니다. 이번에 넣은 계측도 그대로 남겨 두었습니다.
- 숫자가 나오면 가장 긴 줄부터 봅니다. 의심 가는 단계는 그다음입니다.
- 줄일 방법을 안전한 것과 위험한 것으로 나누고, 안전한 것만 먼저 씁니다.
- 장비 탓으로 남는 시간은 초 단위로 적어 둡니다. 나중에 장비를 바꿀지 판단할 근거가 됩니다.
방법을 나눌 때는 이번 사례를 이렇게 분류했습니다.
| 줄이는 방법 | 분류 | 이번 판단 |
|---|---|---|
| 빌드 위치를 PC로 옮기기 | 안전(서버와 같은 리눅스 환경 확인 필요) | 적용, 222초→8초 |
| 소스 해시 비교로 재빌드 건너뛰기 | 안전(DB 무접촉) | 적용, 131초→1초 |
| 스키마·마이그레이션 건너뛰기 | 위험(DB 구조 어긋날 수 있음) | 보류, 68초 유지 |
| 컨테이너 데몬 속도 | 장비 한계 | 수치만 기록, 181초 |
181초 아래로 내려가려면 컨테이너 데몬이 도는 장비를 바꿔야 합니다. 장비 교체를 따질 때 비교할 기준이 이 181초입니다.
이어서 읽기

프로그램 유지보수 비용, 다 만든 뒤 매달 무엇에 돈이 드나
업무 시스템은 다 만든 뒤에도 배포가 저절로 깨지고 백업이 조용히 멈춥니다. 지점 대시보드와 지사 시스템의 실제 운영 기록으로 유지보수비와 서버비가 무엇을 사는지, 견적서와 계약서에서 어떤 줄을 먼저 읽어야 하는지 짚었습니다.

사내 시스템이 갑자기 느려졌을 때, 문의 화면 폴링 한 줄이 범인이었던 사례
로그인에 8~21초가 걸리던 사내 그룹웨어를 진단한 기록입니다. 서버 사양 탓으로 보이던 느림 뒤에는 2.5초마다 도는 쓰기 한 줄과 디스크 점검의 겹침이 있었습니다. 두 번 틀린 측정과 그걸 바로잡은 진단 순서까지 담았습니다.

서버 이중화했는데 장애 때 안 넘어가는 이유와 점검법
복제 로그는 매번 OK였는데 대기 서버의 앱은 켜지지도 못하고 있었습니다. 사내 그룹웨어 이중화를 다시 뜯어보며 찾은 고장 지점과 고친 구조, 손실 범위를 1분으로 줄인 과정, 대기 서버가 정말 뜨는지 확인하는 4층 점검표를 적었습니다.