청구서를 열 때마다 RDS 한 줄이 제일 굵은데 그 데이터베이스가 정말 관리형이어야 하는지 스스로 물어보신 적 있으신가요?
안녕하세요? 정리하는 개발자 워니즈입니다. 이번 글은 개인 블로그 한 대를 굴리면서 RDS 비용 항목을 통째로 걷어낸 과정을 4단계 절차로 정리한 기록입니다. 자랑하려고 쓰는 글이 아니라 어떤 순서로 무엇을 확인했는지 남기는 것이 목적이라서 중간에 제가 낸 사고 한 건도 숨기지 않고 적었습니다.
한 줄 요약입니다. 트래픽이 작은 단일 서버 사이트에서 RDS 비용의 대부분은 관리형 인스턴스 시간 요금이고 애플리케이션 서버에 이미 깔려 있는 DB로 합치면 그 줄이 통째로 사라집니다. 다만 무중단 전환이라는 말은 그 순간에도 쓰기가 들어온다는 뜻이라서 컷오버 직전에 다른 쓰기 주체를 멈추지 않으면 데이터가 갈라집니다.
먼저 결론 세 줄을 접어둡니다.
- 관리형 DB를 쓰는 이유가 다중화나 자동 백업이 아니라 그냥 처음에 그렇게 만들어서라면 RDS 비용은 줄일 수 있는 고정비입니다.
- 옮길 때 쓸모없는 데이터는 지우는 것이 아니라 덤프 단계에서 안 가져가는 쪽이 안전하고 빠릅니다.
- 되돌릴 길을 남기는 비용은 아주 작으므로 최종 스냅샷 한 장은 남기고 지우는 편이 낫습니다.
목차입니다.
- RDS 비용은 어디에서 새고 있나요
- 관리형 DB를 걷어내면 무엇이 같이 사라지나요
- 1단계, 지금 무엇이 돈을 쓰는지 확인한다
- 2단계, 옮길 데이터를 고른다
- 3단계, 무결성을 해시로 증명한다
- 4단계, 컷오버하고 되돌릴 길을 남긴다
- RDS 비용을 줄이는 다른 선택지와 견주면 어떤가
- 안 되는 것, 중지로는 안 끊기고 컷오버 중에도 쓰기는 들어온다
- RDS 비용 줄이기는 누구에게 맞고 누구에게는 굳이인가 그리고 필자의 결론
1. RDS 비용은 어디에서 새고 있나요
개인 사이트에서 RDS 비용이 커지는 이유는 쿼리를 많이 날려서가 아닙니다. 관리형 데이터베이스는 트래픽이 0이어도 인스턴스가 떠 있는 시간만큼 과금되고 거기에 스토리지와 백업 스토리지가 따로 붙습니다. 그래서 하루 방문이 적은 블로그일수록 요청당 원가가 올라가고 청구서에서 RDS 비용이 차지하는 비중이 커지는 구조가 됩니다.
| 과금 축 | 무엇으로 계산되나 | 트래픽이 0이면 |
|---|---|---|
| 인스턴스 시간 | 인스턴스 클래스와 가동 시간 | 그대로 나온다 |
| 할당 스토리지 | 프로비저닝한 용량 기준 | 그대로 나온다 |
| 백업 스토리지 | 할당 용량을 넘는 분량 | 대체로 소액 |
| 데이터 전송 | 가용 영역을 넘는 통신량 | 거의 없다 |
여기서 제일 굵은 축은 첫 줄입니다. 관리형 DB의 가치는 장애 조치와 자동 백업과 패치 자동화인데 단일 인스턴스로 띄워 두었다면 그 가치의 절반은 애초에 사지 않은 셈입니다. 그러면 RDS 비용은 쓰지 않는 기능의 구독료가 됩니다.
정확한 단가는 리전과 시점마다 달라지므로 이 글에 숫자를 박아 넣지 않았습니다. 대신 자기 환경의 RDS 비용을 직접 계산하려면 두 곳만 보면 됩니다. 인스턴스 클래스별 시간 단가는 Amazon RDS for MySQL 요금 페이지에 리전별로 나와 있고 스토리지와 백업까지 합친 월 예상액은 AWS Pricing Calculator에서 인스턴스 클래스와 용량을 넣으면 바로 나옵니다. 이 두 페이지를 근거로 잡아야 남이 쓴 블로그 숫자를 그대로 옮겨 적는 실수를 피할 수 있습니다.
필자가 실제로 걷어낸 구성은 이렇습니다
워드프레스 블로그 한 대였고 애플리케이션 서버는 소형 인스턴스 한 대였습니다. 데이터베이스만 별도의 소형 관리형 인스턴스로 떠 있었고 단일 가용 영역 구성이라 장애 조치 기능은 쓰고 있지 않았습니다. 정리하면 RDS 비용을 매달 내면서 관리형이 주는 핵심 이점은 하나도 쓰지 않는 상태였습니다.
2. 관리형 DB를 걷어내면 무엇이 같이 사라지나요
통합을 결심하기 전에 무엇을 포기하는지부터 적어야 합니다. RDS 비용이 사라지는 대신 아래 넷이 같이 사라집니다.
- 자동 백업과 시점 복구입니다. 로컬 DB에서는 덤프를 거는 잡을 직접 만들어야 합니다.
- 마이너 버전 자동 패치입니다. 이제 DB 업그레이드 일정은 제가 챙겨야 하는 일이 됩니다.
- 장애 조치입니다. 원래 단일 인스턴스였다면 잃는 것이 없습니다.
- 자원 격리입니다. 이것이 가장 실질적인 대가인데 8번 항목에서 다시 적겠습니다.
반대로 얻는 것은 세 가지입니다. 고정비에서 한 줄이 통째로 빠지고 애플리케이션과 DB 사이의 네트워크 왕복이 없어지며 DB 접속 경로가 서버 안쪽으로 들어가 외부에 열린 면이 줄어듭니다.
그래서 판단 기준은 단순합니다. 다중화와 자동 백업을 실제로 쓰고 있다면 RDS 비용은 기능값이고 쓰지 않는다면 그냥 고정비입니다.
사라진 자동 백업을 무엇으로 메우나요
여기가 통합에서 제일 미루기 쉬운 자리입니다. 관리형에서는 백업이 기본값으로 켜져 있어서 아무도 신경 쓰지 않는데 로컬로 내려오면 켜는 사람이 없으면 아무 일도 일어나지 않습니다. 최소 구성은 덤프를 하루 한 번 떠서 같은 디스크가 아닌 다른 저장소에 올리는 잡 하나입니다. 같은 서버의 다른 디렉터리에 두는 것은 백업이 아니라 복사본이고 디스크나 인스턴스가 통째로 날아가는 사고에서는 원본과 같이 사라집니다. 저는 이 숙제를 아직 끝내지 못했고 그 상태를 9번 항목에 그대로 적어 두었습니다.
3. 1단계, 지금 무엇이 돈을 쓰는지 확인한다
첫 단계는 옮기는 작업이 아니라 세는 작업입니다. 감으로 RDS 비용이 크다고 말하면 통합을 마친 뒤에도 무엇이 줄었는지 설명하지 못하고 다음에 같은 판단을 다시 할 근거도 남지 않습니다.
확인할 것은 셋입니다. 청구서의 서비스별 지출에서 데이터베이스 항목이 차지하는 비중을 먼저 보고 그 다음 인스턴스가 다중 가용 영역인지 단일인지를 콘솔에서 확인합니다. 마지막으로 애플리케이션 서버에 이미 DB 엔진이 깔려 있는지를 봅니다.
첫 번째 확인은 비용 관리 콘솔의 서비스별 보기에서 합니다. 여기서 봐야 할 것은 총액이 아니라 순위입니다. 데이터베이스가 1위인지 아닌지에 따라 이 작업의 값어치가 갈리고 2위 이하라면 RDS 비용보다 먼저 손댈 축이 따로 있다는 뜻입니다. 저는 컴퓨팅과 스토리지와 고정 아이피를 전부 합친 것과 데이터베이스 한 줄이 비슷한 크기였기 때문에 우선순위가 바로 정해졌습니다.
서버에 DB가 이미 깔려 있는지 먼저 보세요
제 경우 세 번째 확인에서 판이 끝났습니다. 서버가 Bitnami 워드프레스 스택이었는데 이 스택은 MariaDB를 함께 설치하고 구동까지 해 둡니다. 즉 데이터베이스 프로세스가 이미 서버 안에서 돌고 있었고 워드프레스만 바깥의 관리형 인스턴스를 바라보고 있었습니다.
이 구조에서 통합에 필요한 작업의 본체는 wp-config.php의 DB_HOST 한 줄 교체입니다. 새 서버를 띄우지도 않고 엔진을 새로 깔지도 않습니다. Bitnami 계열 이미지나 원클릭 설치본으로 서버를 만든 뒤 별도로 RDS를 붙였다면 지금 서버에 접속해 DB 프로세스가 떠 있는지부터 보시길 권합니다. RDS 비용을 내면서 쓰지 않는 DB 엔진을 같은 서버에 켜 두고 있을 가능성이 낮지 않습니다.

직접 확인 1, 로컬 DB의 정체를 먼저 확인했습니다
서버 안에 있던 로컬 데이터베이스는 2023년에 설치되고 방치된 기본 스키마였습니다. 테이블 12개에 0.6MB였고 글 4개가 들어 있었으며 사이트 주소가 루프백으로 잡혀 있었습니다. 실제로 쓰이지 않는 껍데기임을 확인한 뒤에야 덮어쓰기로 방향을 잡았습니다. 이 확인을 건너뛰고 바로 부었다면 무엇을 지웠는지 모르는 상태가 됩니다.
4. 2단계, 옮길 데이터를 고른다
여기가 이 글에서 가장 재사용성이 높은 부분이라고 생각합니다. 제 DB는 1,017MB였는데 그 가운데 931MB가 스팸 가입 계정이었습니다. 2018년부터 열려 있던 회원가입 기능으로 구독자 권한 계정이 54만 개 넘게 쌓였고 사용자 메타 테이블에는 767만 행이 붙어 있었습니다. 실제 사람 계정은 네 개였습니다.
| 테이블 | 통합 전 행 수 | 성격 |
|---|---|---|
| 사용자 메타 | 767만 행 | 스팸 계정의 기본 프로필 키 11종 |
| 사용자 | 54만 행 | 구독자 권한이 대부분 |
| 글 | 3,042행 | 실제 콘텐츠 |
| 나머지 47개 테이블 | 합계 약 27MB | 설정과 분류와 플러그인 |
삭제해도 되는지는 따로 판정했습니다. 구독자 권한 계정 가운데 글을 가진 계정과 댓글을 가진 계정이 각각 0이었기 때문에 재할당할 대상이 없었고 메타 행도 워드프레스 기본 프로필 키만 붙어 있었습니다. 이 판정 없이 사용자 테이블을 건드리면 남의 글의 작성자가 사라지는 사고로 이어집니다.
지우지 말고 덤프에서 빼는 이유가 무엇일까요
보통은 운영 DB에서 스팸 계정을 삭제한 다음 옮깁니다. 저는 지우지 않고 덤프 단계에서 제외했습니다. 이유가 셋입니다.
- 운영 DB에 쓰기 작업이 0입니다. 살아 있는 사이트에서 대량 삭제를 돌리지 않습니다.
- 롤백이 한 줄입니다. 원본이 손대지 않은 상태로 남아 있으니 되돌릴 때 접속 주소만 바꾸면 됩니다.
- 가져오기가 곧 테이블 재구축이라 단편화가 저절로 정리됩니다. 별도로 최적화 명령을 돌릴 필요가 없습니다.
명령은 세 줄입니다. 전체에서 사용자 계열 두 테이블을 빼고 받은 다음 남길 계정만 조건으로 걸어 따로 받습니다. --where 옵션의 동작은 MySQL 공식 mysqldump 문서에 정의되어 있습니다.
OPT="--single-transaction --quick --skip-lock-tables --default-character-set=utf8mb4"
mariadb-dump $OPT --ignore-table=$DB.wp_users --ignore-table=$DB.wp_usermeta $DB > 01_main.sql
mariadb-dump $OPT --where="ID IN ($KEEP)" $DB wp_users > 02_users.sql
mariadb-dump $OPT --where="user_id IN ($KEEP)" $DB wp_usermeta > 03_usermeta.sql
결과로 덤프 용량이 1,017MB에서 87.7MB가 됐습니다. 백업 스토리지와 복구 시간이 함께 줄어드는 것이라 RDS 비용을 정리하는 작업의 부산물치고는 꽤 큽니다.
직접 확인 2, 엔진이 다르면 덤프를 먼저 읽습니다
관리형 쪽은 MySQL 8.4였고 서버 안 로컬은 MariaDB 11.1이었습니다. 두 엔진은 이름이 비슷하지만 버전 게이트 주석 처리에서 갈립니다. MariaDB는 자기 버전 번호가 커서 MySQL이 넣어둔 /*!8xxxx */ 조건부 주석을 조건 충족으로 보고 실행해 버립니다. 이것이 MySQL 8 덤프를 MariaDB에 넣을 때의 대표 사고 지점입니다.
그래서 파이프로 바로 붓지 않고 덤프 파일을 서버 디스크에 떨어뜨린 다음 읽었습니다.
grep -o '/\*!8[0-9]*' 01_main.sql | sort | uniq -c
grep -c 'utf8mb4_0900' 01_main.sql
| 검사 항목 | 실측 결과 |
|---|---|
/*!8xxxx 버전 게이트 주석 |
0건이고 전부 4.x 대 주석이었다 |
| 콜레이션 | utf8mb4_unicode_520_ci 단일이라 MariaDB가 받는다 |
utf8mb4_0900 계열 |
0건 |
INVISIBLE, GENERATED ALWAYS, DEFINER= |
전부 0건 |
MySQL 8의 기본 콜레이션인 utf8mb4_0900_ai_ci가 섞여 있었다면 MariaDB가 받지 못해 덤프를 다시 만들어야 했습니다. 제 사이트는 워드프레스가 옛 콜레이션을 쓰고 있어 통과했습니다. 여기서 걸리는 분이 있다면 그 상태로는 통합을 진행하지 마시고 콜레이션 변환부터 계획하셔야 합니다.
5. 3단계, 무결성을 해시로 증명한다
가져오기는 5초대에 끝났습니다. 문제는 그 다음입니다. 행 수가 같다는 것은 내용이 같다는 뜻이 아닌데 많은 이전 작업이 행 수 대조에서 멈춥니다.
저도 처음에는 행 수와 아이디 집합만 봤습니다. 그 방법으로는 아이디가 같고 내용이 다른 행을 잡지 못합니다. 그래서 검사를 한 층 더 넣었습니다.
대조는 운영 DB가 아니라 검증용 스키마에서 합니다
운영 DB를 건드리지 않으려고 검증 전용 스키마를 새로 만들고 덤프 세 개를 그대로 부었습니다. 이러면 덤프를 뜬 그 시점의 상태가 재현되므로 비교 축이 두 개로 갈립니다.
| 대조 축 | 무엇을 묻는가 |
|---|---|
| 검증용 스키마와 원본 DB | 덤프가 놓친 것이 있나 |
| 검증용 스키마와 라이브 DB | 가져오기가 실패한 것이 있나 |
대조 방법은 전 컬럼 해시입니다. 컬럼 목록을 information_schema에서 순서대로 뽑아 문자열로 이어 붙인 다음 행마다 해시를 내고 정렬해 집합 차분을 냅니다. NULL과 빈 문자열을 구분하려고 센티널 문자열을 끼워 넣었습니다.
SELECT MD5(CONCAT_WS('|', IFNULL(ID,'~N~'), IFNULL(post_name,'~N~'), IFNULL(post_content,'~N~')))
FROM wp_posts ORDER BY ID;
실제로는 위처럼 컬럼 세 개가 아니라 테이블마다 전 컬럼을 동적으로 이어 붙였습니다. 개념만 보이려고 줄인 형태입니다.

직접 확인 3, 48개 테이블 중 44개가 바이트 단위로 일치했습니다
한글 본문이 들어 있는 글 테이블과 메타 테이블이 전부 해시 일치했습니다. MySQL 8.4에서 MariaDB 11.1로 넘어가면서 utf8mb4 한글이 깨지지 않았다는 것이 이렇게 실증됐습니다. 인코딩 변환은 가장 무섭고 가장 조용한 사고 유형이라 이 확인을 넣은 값을 했다고 봅니다.
차이가 난 것은 네 개 테이블 23행뿐이었고 정체가 전부 설명됐습니다. 그 가운데 20행은 컷오버 도중에 만들어진 글 하나의 부산물이었고 나머지는 만료된 임시 값과 크론 잠금 같은 휘발성 상태였습니다. 라이브 쪽에서는 핵심 10개 테이블에서 덤프에만 있고 라이브에 없는 기본 키가 0건이었습니다.
실패한 검증도 적어 둡니다
본문 해시를 비교할 때 수정 시각이 컷오버보다 이른 글만 거르는 조건을 양쪽에 걸었더니 45건 불일치가 나왔습니다. 처음에는 훼손을 의심했는데 원인은 필터였습니다. 컷오버 이후에 수정된 글이 라이브 쪽에서만 조건에서 빠져 대상 건수가 애초에 달랐던 것입니다. 본문 길이가 짧아진 글은 0건이었습니다.
교훈은 한 줄입니다. 대조 대상 건수가 양쪽에서 다르면 불일치를 보기 전에 그 차이부터 설명해야 합니다.
6. 4단계, 컷오버하고 되돌릴 길을 남긴다
접속 주소를 바꾸는 작업 자체는 한 줄입니다. 기존 주소 줄은 지우지 않고 주석으로 남겨 두면 롤백이 주석 두 개를 뒤집는 일이 됩니다. 서버 재시작도 필요 없었습니다.
전환 완료 판정은 설정 파일이 아니라 트래픽으로 합니다
설정 파일을 고쳤다고 전환이 끝난 것이 아닙니다. 캐시나 상주 프로세스가 옛 커넥션을 붙들고 있으면 파일만 바뀐 상태가 됩니다. 그래서 양쪽 DB의 누적 쿼리 카운터를 전후로 재고 델타를 봤습니다.
라이브 요청을 여덟 개 넣자 로컬 쪽 카운터만 네 자리로 올라갔고 관리형 쪽 델타는 측정 쿼리 두 개뿐이었습니다. 프로세스 목록에도 애플리케이션 커넥션이 남지 않았습니다. 여기까지 봐야 트래픽이 어디로 가는지가 확정됩니다.
판정을 더 굳히려고 관리형 인스턴스를 콘솔에서 중지시키고 사이트를 다시 쟀습니다. 25초 간격으로 폴링했더니 인스턴스가 실제로 도달 불가가 된 시점 이후에도 홈과 REST 응답과 로그인 화면과 사이트맵이 전부 200이었습니다. 원본이 꺼진 상태에서 사이트가 멀쩡한 것을 본 다음에야 삭제로 넘어갔습니다.
직접 확인 4, 데이터가 메모리가 아니라 디스크에 있는지 봤습니다
삭제 직전에 하나를 더 했습니다. 로컬 DB 프로세스를 죽였다가 다시 올린 다음 데이터가 그대로인지 본 것입니다. 통합 직후에는 캐시에 올라와 있던 것을 보고 있을 가능성을 배제할 수 없기 때문입니다.
| 확인 항목 | 재시작 전 | 재시작 후 |
|---|---|---|
| DB 프로세스 아이디 | 기존 값 | 새 값으로 바뀜 |
| 발행 글 수와 전체 글 수 | 같음 | 같음 |
| 전체 본문 지문 해시 | 기준값 | 동일 |
| 사이트 응답 | 200 | 200 |
전체 본문 지문은 글마다 해시를 내고 그것들을 다시 한 번 해시한 값입니다. 프로세스가 실제로 새로 뜬 것을 아이디 변화로 확인했고 그 뒤에도 지문이 같았으니 데이터가 디스크 파일에 있다는 뜻입니다. 데이터 디렉터리가 루트 볼륨 위에 있어서 서버 이미지를 뜨면 DB도 함께 실린다는 점까지 같이 확인했습니다.
삭제할 때 최종 스냅샷은 남기세요
삭제 다이얼로그에서 최종 스냅샷 생성을 체크하고 이름에 날짜를 박았습니다. 자동 백업 보존은 해제했습니다. 최종 스냅샷과 겹치는데 백업 스토리지가 따로 붙기 때문입니다. 스냅샷은 완전 무료가 아니지만 실제 데이터가 1GB 남짓이면 인스턴스 시간 요금과는 자릿수가 다릅니다. RDS 비용을 줄이는 목적과 복구본을 남기는 목적이 여기서 미세하게 충돌하는데 저는 스냅샷 쪽을 택했습니다.
주의할 점이 하나 있습니다. 이 스냅샷은 계정이 살아 있는 동안만 유효합니다. 계정을 닫으면 같이 사라지므로 계정 자체를 정리할 계획이라면 스냅샷이 아니라 덤프 파일을 다른 곳에 내려두셔야 합니다.

7. RDS 비용을 줄이는 다른 선택지와 견주면 어떤가
통합만이 답은 아닙니다. 제가 실제로 시도했거나 검토한 선택지를 견주면 이렇습니다.
| 선택지 | RDS 비용에 주는 효과 | 걸리는 지점 |
|---|---|---|
| 인스턴스 클래스 축소 | 시간 요금이 줄지만 축은 남는다 | 메모리 하한에 곧 닿는다 |
| 인스턴스 중지 | 인스턴스 시간 요금만 멈춘다 | 최대 7일 뒤 자동 재기동된다 |
| 로컬 DB 통합 | 인스턴스 축이 통째로 사라진다 | 자원 경합과 백업이 내 일이 된다 |
| 관리형 유지 | 없다 | 다중화를 쓴다면 이쪽이 맞다 |
중지 선택지는 특히 오해하기 쉽습니다. 콘솔의 동의 문구에 이미 적혀 있는데 중지한 인스턴스는 일정 기간이 지나면 자동으로 다시 켜집니다. 저는 두 번 중지했고 두 번 다 되살아났습니다. 두 번째는 35분 만이었습니다. 이벤트 로그에는 복구 시작과 재시작이 연달아 찍혀 있었고 그 인스턴스가 마이너 버전 자동 업그레이드 대상이면서 유지 관리 보류 항목을 가지고 있었습니다. 강제 롤아웃 때문으로 보이지만 AWS 내부 동작을 제가 볼 수단은 없어서 원인은 미확인으로 둡니다.
확실한 것만 적으면 이렇습니다. 중지 직후에 상태가 중지됨으로 바뀐 것을 보고 RDS 비용을 끊었다고 판정하면 안 되고 몇 시간 뒤에 상태를 다시 확인해야 합니다.
중지 다이얼로그에는 함정이 하나 더 있었습니다. 확인 버튼만 누르면 아무 반응 없이 실패하는데 에러 배너도 뜨지 않습니다. 다이얼로그 안에 동의 체크박스가 따로 있고 그것을 먼저 체크해야 버튼이 동작합니다. 저는 두 번 조용히 실패한 뒤에야 원인을 찾았습니다. 콘솔 조작에서 상태가 안 바뀐 것을 성공으로 오판하지 않으려면 클릭한 다음 상태 문자열을 반드시 다시 읽어야 합니다.
8. 안 되는 것, 중지로는 안 끊기고 컷오버 중에도 쓰기는 들어온다
여기가 이 글에서 제일 중요하게 읽히길 바라는 절입니다. 성공한 절차만 적으면 다음 사람이 같은 자리에서 넘어집니다.
컷오버 도중에 다른 쓰기 주체가 붙어 있었습니다
삭제 직전 정밀 검사에서 원본에만 있는 글 1행과 메타 2행이 나왔습니다. 아이디 집합만 보면 그냥 세 행 차이인데 자연키로 대조하니 상황이 달랐습니다. 같은 아이디 번호를 양쪽 DB가 서로 다른 객체에 독립적으로 발급하고 있었습니다.
| 아이디 | 원본 쪽 | 로컬 쪽 |
|---|---|---|
| 3593 | 초안 상태의 글 | 같은 글의 발행 상태 |
| 3594 | 이미지 첨부 레코드 | 전혀 다른 리비전 |
| 3595 | 리비전 | 없음 |
시각을 정리하니 원인이 분명했습니다. 덤프를 뜨고 접속 주소를 바꾼 뒤 2분이 지난 시점에 원본 쪽에 새 글 레코드가 기록되어 있었습니다. 같은 시간대에 다른 자동화 작업이 이 블로그에 글을 올리고 있었고 컷오버 직후 남아 있던 요청이 옛 경로로 들어간 것입니다. 그 결과 두 데이터베이스가 같은 자동 증가 구간을 각자 소비했습니다.
제가 놓친 것은 기술이 아니라 절차였습니다. 무중단 전환이라 안전하다고 봤는데 무중단이라는 말은 그 순간에도 쓰기가 들어온다는 뜻입니다.
실제 피해는 크지 않았습니다. 이미지 파일 다섯 종이 디스크에 남았는데 로컬 DB에 첨부 레코드가 없어 미디어 라이브러리에 안 보이는 상태가 됐습니다. 해당 글은 정상 발행됐고 대표 이미지도 다른 첨부를 쓰고 있어 독자에게 보이는 손상은 없었습니다. 그래도 운이 좋았던 것이지 절차가 막아준 것이 아닙니다.
같은 사고를 막는 절차 세 줄
- 컷오버 전에 크론과 발행 파이프라인과 자동화 세션을 먼저 멈춥니다. 붙어 있는 쓰기 주체를 목록으로 적고 하나씩 끕니다.
- 행 수 일치를 전환 완료 근거로 쓰지 않습니다. 덤프 시점 이후에도 원본이 쓰기를 계속 받으면 그 일치는 금방 깨집니다.
- 아이디 집합 비교와 자연키 비교를 같이 돌립니다. 파일 경로나 슬러그처럼 사람이 만든 키가 있어야 같은 번호 다른 내용을 잡습니다.
메모리는 줄고 경합은 새로 생깁니다
통합 직후 서버의 사용 가능 메모리는 오히려 줄었습니다. 통합 전 496MB였던 것이 401MB가 되어 95MB가 빠졌는데요, 워드프레스가 바깥 DB로 커넥션을 유지하던 몫은 사라졌지만 로컬 DB 프로세스가 새로 차지하는 상주 메모리가 그보다 컸기 때문입니다. 그 상주 메모리 자체는 100MB 아래였으니 감소 폭은 예상 범위 안이었습니다. 그런데 이 숫자는 지금 트래픽 기준입니다. 방문이 늘면 웹 서버와 DB가 같은 메모리 풀을 나눠 쓰게 되고 그때는 둘 중 하나가 밀립니다. 관리형을 쓸 때는 이 경합이 아예 없었으니 RDS 비용을 줄이면서 산 위험이 정확히 이것입니다.
통합해도 안 풀리는 것도 있습니다
통합은 RDS 비용을 없애지만 그 서버가 원래 안고 있던 문제까지 고쳐주지 않습니다. 제 경우 리다이렉션 플러그인이 참조하는 테이블 두 개가 없어서 요청마다 DB 에러가 쌓이고 있었는데 이것은 관리형 쪽에도 똑같이 없던 선행 결함이었습니다. 이전 작업 중에 발견한 문제를 이전 탓으로 오인하지 않으려면 통합 전 상태를 먼저 기록해 두는 편이 낫습니다.
9. RDS 비용 줄이기는 누구에게 맞고 누구에게는 굳이인가 그리고 필자의 결론
먼저 맞는 쪽입니다. 단일 가용 영역으로 관리형 DB를 쓰고 있고 애플리케이션 서버에 DB 엔진이 이미 깔려 있으며 데이터가 수 기가바이트 이하인 개인 사이트라면 이 4단계는 하루 안에 끝납니다. 얻는 것은 매달 반복되는 고정비 한 줄이고 잃는 것은 지금도 쓰지 않던 기능입니다.
굳이인 쪽도 분명합니다. 다중 가용 영역을 켜 두었거나 시점 복구를 실제로 써 본 적이 있거나 DB가 여러 애플리케이션의 공용이라면 RDS 비용은 기능에 대한 값이므로 걷어낼 대상이 아닙니다. 서버 메모리가 이미 빠듯하다면 더욱 그렇습니다.
그래서 필자는 무엇을 하기로 했는가
필자는 이 블로그에서 관리형 DB를 다시 쓰지 않기로 했습니다. 통합 뒤 데이터베이스가 애플리케이션과 같은 인스턴스에 올라왔으니 메모리 경합이 새 위험으로 들어온 것이 사실이고 앞으로 트래픽이 늘면 가장 먼저 흔들릴 자리도 거기입니다. 그 대가를 알고도 받아들였습니다. 지금 이 사이트에서 관리형이 주는 이득은 쓰지 않는 기능이었고 매달 나가는 RDS 비용은 실재하는 지출이었기 때문입니다.
동시에 아직 안 한 것도 적어 둡니다. 로컬 DB의 상시 백업 잡을 아직 만들지 않았습니다. 최종 스냅샷과 이전 작업 때 뜬 덤프 파일이 남아 있어 당장의 복구본은 있지만 그것은 이전 시점에서 멈춘 사진이고 어제 쓴 글은 지켜주지 않습니다. 이 글을 쓰는 시점에서 가장 급한 숙제가 그것이라고 봅니다. RDS 비용을 걷어내는 순간 백업은 관리형이 대신 해주던 일에서 제 일로 넘어오는데 그 인수인계를 아직 안 끝낸 상태입니다.

비슷한 계열로 요금과 무료 한도를 직접 재본 글이 셋 있습니다. 리뷰 카테고리의 일레븐랩스 무료 10분과 제한 5가지는 무료 구간의 상한이 어디서 끊기는지를 재본 글이고 퍼플렉시티 무료 한도와 Pro 차이 5가지는 유료 전환 전에 무엇을 확인해야 하는지를 정리한 글입니다. 단가 구조를 등급별로 쪼갠 GPT Image 2.5 요금과 화질 5단계도 같은 축입니다. 쓰는 돈의 정체를 먼저 재고 나서 줄이는 순서라는 점에서 이 글과 이어집니다.