1. 최종 테스트
실제 서비스를 운영 중인 환경과 동일하게 Proxmox VE의 VM에서 테스트를 진행한다.
가. Performance 문제
- 1차 시도
- 시작 : 00시 49분
- 결과 : IDS/IPS에서 차단해버려서 실패
- 2차 시도
- 시작 : 00시 57분
- 결과 : WordPress가 트래픽을 감당하지 못해서 실패
- 3차 시도
- worker를 4→2로 줄여서 재시도
- 시작 : 01시 01분
- 결과 : 이미지 업로드 시 지속적인 타임아웃 발생.
- 4치 시도
- 타임아웃 기준을 3→30로 줄여서 재시도
- 시작 : 01시 05분
- 결과 : 이미지 업로드 시 지속적인 타임아웃 발생.
생각보다 WordPress가 업로드 트래픽에 약하다.
기본 설정을 최대한 낮게 잡아야겠다.
- 5차 시도
- worker를 2→1로 줄이고 rate limit을 1→5초로 늘림.
- 시작 : 01시 09분
- 결과 : 이미지 업로드 시 지속적인 타임아웃 발생.
진짜 내 생각보다도 WordPress의 처리량이 작다.
극단적으로 낮은 처리량을 예상하고 설정해야겠다.
- 6차 시도
- worker : 1, rate limit : 1분에 포스팅 3개
- retry 주기 : 0.5 → 5 → 50초
- 타임아웃을 10분으로 늘려서 진행한다.
- 시작 : 14시 42분
- 결과 : 정상적으로 동작함. 다만 일부 이미지들이 업로드 크기 제한에 걸림.
- 7차 시도
- rate limit : 1분에 3→5로 늘림
- 안정적으로 처리하기 위해선 분당 3개가 한계인 듯함.
- 시작 : 15시 34분
- 결과 : “socket hang up”이란 말과 함께 업로드에 실패함.
- 8차 시도
- worker 수만큼의 socket은 유지해서 재사용한다.
- wordpress의 로그를 보니 Converter for Media 플러그인 때문에 이미지 업로드 부하가 배가 된다.
- 일단 플러그인을 비활성화 했다.
- 시작 : 20시 40분
- 결과 : 지금까지 가장 안정적이다. 오히려 rate limit을 늘려야겠다.
요청을 중간에 끊었을 때 Converter for Media가 부하를 가중하는 문제가 있다.
나. 408 socket hang up 문제
- 9차 시도
- worker → 2
- rate limit : 분당 10개
- retry : 0.5 → 2.5 → 12.5 초
- 결과 : 안정적인다. 가끔
socket hang up이 발생하지만 이것은 네트워크 문제인 것 같다.
더 올려도 되겠다.
- 10차 시도
- worker → 4
- rate limit : 분당 20개
- 결과 : 아직 여유가 있다. 더올리자.
- 11차 시도
- worker → 5
- rate limit : 분당 100개
- 시작 : 21시 10분
- 결과 :
- ??시 ??분
- 시작 글 171개 → 5분만이 글 255개 돌파
- 대략 분당 15개 처리함
안정적으로 처리하기 위해서 분당 10개가 적절한다.
중간에 서버에 문제가 생김. 원인을 파악 중. DB 트랙잭션 문제임.
중간에 한번 문제가 생기기 시작하면 계속해서 socket hang up 408 문제가 생긴다.
아! 테스트 가상머신의 용량이 다 차서 생기는 문제였다!!!
환장하겠다.
2. 최최종 테스트
- 문제가 될만한 모든 플러그인을 비활성화
- 원래 남은 용량 확인
- 공간 늘리기
- 재실행
- 남은 용량 확인
- 플러그인 실행
- 남은 용량 재확인
- 생성된 결과물 점검
- 기본값 조정
- 문서 최신화
- 버전 등록 (
package.json,git tag)
테스트 완료 후 실제 블로그에 적용.

가. 디스크 확장

나. 실행 후 용량 확인
- 실행 조건
- worker : 5
- rate limit : 분당 10개

- 실행 직후

601 중 581개 성공, 20개 실패.
첫 성적치고는 매우 좋다.

용량은 7.2G에서 8.5G로 올랐다. 지금까지 대략 1.3GB 가량 상승했다.
[2026-01-08T14:33:12.706Z] [ERROR] retryWithBackoff - max retry attempts (3) exceeded {"error":"Request failed with status code 400"}
...
[2026-01-08T15:33:09.804Z] [ERROR] PostProcessor.process - process url failed {"url":"https://ramen4598.tistory.com/6","error":"socket hang up"}
Code language: JavaScript (javascript)
첫 로그로부터 마지막 로그까지 대략 1시간 정도 걸렸다.
분당 10개 60분 해서 정직하게 600개 가량 처리했다.

cpu 사용량을 확인했다.
순간적으로 100%를 찍지만 상승과 하락을 반복하고 있다.
worker와 interval을 줄이고 cap을 늘려서 평균처리량을 높여야 겠다.
worker는 4로, interval은 30초로, cap은 30초당 7회로 올린다.
다. 기타 산출물
- 내부 링크 추적
[
{
"source_url": "https://ramen4598.tistory.com/619",
"target_url": "https://ramen4598.tistory.com/93",
"link_text": "",
"context": "https://ramen4598.tistory.com/93"
},
{
"source_url": "https://ramen4598.tistory.com/605",
"target_url": "https://ramen4598.tistory.com/548",
"link_text": "",
"context": "https://ramen4598.tistory.com/548"
},
{
"source_url": "https://ramen4598.tistory.com/593",
"target_url": "https://ramen4598.tistory.com/134",
"link_text": "",
"context": "https://ramen4598.tistory.com/134"
},
...
{
"source_url": "https://ramen4598.tistory.com/95",
"target_url": "https://ramen4598.tistory.com/94",
"link_text": "2022.05.15 - [학부 강의/Android_Studio] - 2022-05-15 자바_입출력_스트림",
"context": "2022.05.15 - [학부 강의/Android_Studio] - 2022-05-15 자바_입출력_스트림"
},
{
"source_url": "https://ramen4598.tistory.com/95",
"target_url": "https://ramen4598.tistory.com/94",
"link_text": "",
"context": "https://ramen4598.tistory.com/94"
},
{
"source_url": "https://ramen4598.tistory.com/57",
"target_url": "https://ramen4598.tistory.com/VundleVim/Vundle.vim/commit/b50ec91aa09aa20f7524ed4bb0372338f9a58448",
"link_text": "",
"context": "Translate README into Korean · VundleVim/Vundle.vi"
}
]
Code language: JSON / JSON with Comments (json)
나중에 변경해야할 링크들 목록이다. 잘 생성된다.
- 실패 포스트 추적
{
"blog_url": "https://ramen4598.tistory.com",
"exported_at": "2026-01-08T17:36:07.493Z",
"count": 20,
"items": [
{
"tistory_url": "https://ramen4598.tistory.com/635",
"error_messages": [
"Request failed with status code 400"
]
},
{
"tistory_url": "https://ramen4598.tistory.com/602",
"error_messages": [
"socket hang up"
]
},
...
Code language: JSON / JSON with Comments (json)
실패한 포스트들 목록이다. 이 또한 잘 생성된다.
모아보니 socket hang up 원인을 파악할 수 있겠다.
3. 최최최종 테스트
중간에 재시도 로직을 수정했다.
DB 스키마에 변경이 생겨 처음부터 다시 테스트한다.
- 플러그인 비활성화
- 실행
- Export File 확인
- 실패 재시도
- 남은 용량 확인
- 플러그인 활성화
- 남은 용량 재확인
- 결과물 확인
가. 미디어 업로드 최대 크기 조정

실패한 대부분의 경우는 미디어 크기가 너무 커서다.

WordPress의 설정을 수정하고 다시 시도해보자.

----------------------------------------
- Migration Job Summary (jobId=3)
----------------------------------------
- Detected : 600
- Skipped: 1
- Completed: 582
- Failed: 18
- Total processed: 600
- Database: ./data/migration.db
- Internal links: stored in 'internal_links' table (jobId=3)
- Link mapping exported to: output/link_mapping-2026-01-09T04-40-16-138Z.json
----------------------------------------
Code language: JavaScript (javascript)
실패 개수가 18개로 전과 거의 동일하다.
설정을 되돌리고 WordPress가 아닌 php.ini를 수정해야 할 것 같다.
# docker container 진입
docker exec -it wordpress_app /bin/bash
#
# 수정 전 설정값
php -i | grep -E "upload_max_filesize|post_max_size|memory_limit|memory_limit|max_execution_time|max_input_time"
# upload_max_filesize = 2M
# post_max_size = 8M
# memory_limit = 128M
# max_execution_time = 0
# max_input_time = -1
#
# php 설정 파일 위치 확인
php --ini
cd /usr/local/etc/php/
Code language: PHP (php)
upload_max_filesize가 2M로 크기가 작다.
WordPress 공식 Docker image 기준 php.ini가 없다.
대신에 /usr/local/etc/php/conf.d/ 아래 ini 파일들을 사용한다.
아래에 확장자가 ini인 파일을 하나 추가한다.
vim heavy-upload-php.ini
# 아래 내용 입력 후 저장
upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
Code language: PHP (php)
대용량 이미지를 안정적으로 처리하기 위해서 upload_max_filesize와 post_max_size를 커스텀한다.
수정 후 도커 컨테이너를 재시작한다.
php -i | grep -E "upload_max_filesize|post_max_size|memory_limit|memory_limit|max_execution_time|max_input_time"
# max_execution_time => 0 => 0
# max_input_time => -1 => -1
# memory_limit => 256M => 256M
# post_max_size => 64M => 64M
# upload_max_filesize => 64M => 64M
Code language: PHP (php)
php 설정을 수정했다.
PHP를 이렇게 설정했는데도 업로드가 안 되면 Nginx나 Cloudflare 같은 리버스 프록시 문제일 수 있다.
나. 실패한 포스트 업로드 재시도
----------------------------------------
- Migration Job Summary (jobId=10)
----------------------------------------
- Detected : 17
- Completed: 17
- Failed: 0
- Total processed: 17
- Database: ./data/migration.db
- Internal links: stored in 'internal_links' table (jobId=10)
----------------------------------------
Code language: JavaScript (javascript)
재시도 포함 최종 성공률 100%!!!!
이로서 408 socket hang up 문제는 PHP의 업로드 파일 사이즈와 관계있음을 알게 파악했다.

용량은 7.2G → 8.5G → 8.8G로 글 604개, 이미지 2674개로 대략 1.6G 정도 필요했다.
다. Converter for Media 플러그인 활성화

최종적으로 블로그 이사를 위해서 필요한 최소 용량은 2.2GB이다.
올라가지 않은 첨부파일과 동영상을 고려하면 최소 5GB의 여유는 필요하다.
앞으로도 써야하니 넉넉하게 10GB를 할당해주자.
라. 최최최종 결과물 확인
하자가 있는지 확인한다.

메인 페이지도 정상!

목차, 북마크, 이미지도 정상!

코드 하이라이팅도 정상!

카테고리도 정상!
마. 기본값 조정

Worker 4개, Interval 30초, IntervalCap 7개로 분당 14개 정도 처리하고 있다.
아직도 서버 리소스가 많이 남는다.
Interval을 15초로 더 줄이고 IntervalCap 5로 더 늘려야겠다.
그러면 분당 20개 정도 처리할 수 있다.
4. 개발 마무리
끝없는 버그와의 싸움 끝에 1.0.0 버전을 출시했다.
힘들어 죽겠다.
당초 계획보다 10일 가량 늦었다.