워드프레스는 업데이트를 확인하며 서버 명세서도 보냅니다
플러그인을 하나도 깔지 않은 워드프레스는 바깥과 얼마나 대화할까요. 아무것도 안 할 것 같지만 그렇지 않습니다. 12시간마다 세 번, 바깥으로 전화를 겁니다. 그리고 그 통화에서 워드프레스가 보내는 양은 받아 오는 양의 세 배에 가깝습니다.
이 서버에서 그 요청을 전부 가로채 바이트 단위로 쟀습니다. 받아 오는 것은 “최신 버전은 몇 번입니다”라는 짧은 답인데, 보내는 쪽에는 이 서버의 PHP 확장 모듈 목록 55개가 통째로 실려 있었습니다.
어떻게 쟀는가
워드프레스에는 바깥으로 HTTP 요청을 보내고 응답을 받을 때마다 호출되는 http_api_debug라는 자리가 있습니다. 여기에 기록기를 하나 붙이면 요청 주소, 보낸 본문, 받은 응답, 걸린 시간이 전부 손에 들어옵니다. 요청을 가로막지 않고 지켜보기만 하므로 평소 동작은 그대로입니다.
측정 대상은 블로그 세 개가 들어 있는 워드프레스 멀티사이트 한 벌입니다. 활성 플러그인 0개, 설치된 테마 4개, 워드프레스 7.0.7, PHP 8.4.26, MariaDB 10.5.29입니다. 업데이트 확인 결과는 캐시에 저장되고 12시간 동안 재사용되므로, 캐시를 비운 직후에 재야 실제로 나가는 요청을 볼 수 있습니다.
이 설치에서 바깥으로 나갈 수 있는 예약 작업은 세 가지입니다. 코어 버전 확인, 플러그인 확인, 테마 확인이고 전부 12시간 주기입니다. 나머지 예약 작업은 오래된 임시 파일 삭제처럼 서버 안에서 끝나는 일입니다. 이 예약 작업을 누가 깨우는지는 워드프레스 크론을 깨우는 것은 방문자가 아니었다에서 따로 쟀습니다.
한 번 확인할 때 오간 바이트
캐시를 비우고 세 가지 확인을 차례로 돌렸습니다. 요청은 정확히 세 건이 나갔습니다.
| 확인 | 보냄 | 받음 | 걸린 시간 |
|---|---|---|---|
| 코어 버전 | 3,160B | 1,515B | 587ms |
| 테마 | 2,805B | 946B | 584ms |
| 플러그인 | 1,006B | 47B | 562ms |
| 합계 | 6,971B | 2,508B | 1,862ms |

세 건 모두 응답 시간이 560~590ms 사이였습니다. 다섯 번 더 반복해 보니 최소 559.7ms, 중앙값 580.2ms, 최대 592.8ms였고 응답 크기는 다섯 번 모두 1,515B로 같았습니다. 거리가 만든 지연이지 서버 사정에 따른 흔들림이 아니라는 뜻입니다. 요청의 제한 시간은 3초로 걸려 있습니다.
질의문 2,028바이트의 81.4%는 확장 모듈 목록입니다
코어 버전 확인이 보내는 3,160B는 주소 뒤에 붙는 질의문 2,028B와 본문 1,132B로 나뉩니다. 질의문에는 항목이 71개 들어 있었는데, 그 구성이 한쪽으로 크게 쏠려 있었습니다.
| 항목 | 개수 | 바이트 | 비중 |
|---|---|---|---|
| PHP 확장 모듈과 버전 | 55 | 1,651B | 81.4% |
| 지원하는 이미지 형식 | 5 | 185B | 9.1% |
| 운영체제와 비트 수 | 2 | 57B | 2.8% |
| 설치 당시 DB 버전 | 1 | 25B | 1.2% |
| 데이터베이스 버전 | 1 | 22B | 1.1% |
| 멀티사이트 여부 | 1 | 20B | 1.0% |
| 워드프레스 버전 | 1 | 14B | 0.7% |
| 언어 | 1 | 13B | 0.6% |
| PHP 버전 | 1 | 11B | 0.5% |
| 블로그 수 / 사용자 수 | 2 | 16B | 0.8% |
버전을 묻는 데 꼭 필요한 정보는 워드프레스 버전 14B 하나입니다. 나머지 2,014B는 “이 서버는 이런 구성입니다”라는 설명입니다. 확장 모듈 목록은 어떤 모듈이 몇 번 버전으로 올라가 있는지를 줄줄이 적은 것이고, 여기에 블로그가 몇 개이고 사용자가 몇 명인지까지 함께 나갑니다. 본문 1,132B는 설치된 코어 번역 네 벌의 목록입니다.
1,006바이트를 보내고 47바이트를 받습니다
가장 기울어진 쪽은 플러그인 확인이었습니다. 이 설치에는 활성 플러그인이 0개고, 비활성 상태로 들어 있는 것이 하나뿐입니다. 그런데도 1,006B를 보냈고 돌아온 응답은 47B였습니다. 21배입니다.
이유는 간단합니다. 플러그인 확인은 활성 여부와 무관하게 설치된 플러그인 전부의 정보를 보내고, 받는 쪽은 그중 갱신이 있는 것만 돌려줍니다. 갱신할 것이 없으면 빈 목록이 오고, 그래서 응답이 47B로 끝납니다. 테마도 같은 구조라 네 벌의 정보 2,805B를 보내고 946B를 받았습니다.
블로그가 세 개라도 요청은 세 건입니다
예약 작업 목록만 보면 걱정스럽습니다. 블로그 세 개가 각각 세 가지 확인을 12시간마다 돌리니 하루에 18번입니다. 블로그를 늘릴 때마다 바깥으로 나가는 요청이 비례해서 늘어난다면 멀티사이트는 불리한 구조가 됩니다.
그래서 캐시를 비운 뒤 블로그 1, 2, 3 순서로 같은 확인을 돌려 봤습니다.
| 순서 | 바깥 요청 | 보냄 | 걸린 시간 |
|---|---|---|---|
| 블로그 1 | 3건 | 6,971B | 1,862ms |
| 블로그 2 | 0건 | 0B | 8ms |
| 블로그 3 | 0건 | 0B | 8ms |
두 번째와 세 번째 블로그는 요청을 한 건도 보내지 않았고 8밀리초 만에 끝났습니다. 업데이트 확인 결과가 블로그별 저장소가 아니라 네트워크 공용 저장소에 들어가기 때문입니다. 실제로 데이터베이스를 뒤져 보니 세 가지 캐시가 모두 네트워크 공용 테이블에 1건씩 있었고, 블로그별 옵션 테이블에는 0건이었습니다.
결국 하루에 예약은 18번 잡히지만 바깥으로 실제로 나가는 것은 6번입니다. 바이트로는 하루에 약 14KB를 보내고 5KB를 받습니다. 한 달이면 보내는 쪽이 400KB 남짓입니다. 사진 한 장보다 작습니다.
방문자가 올 때는 나가지 않습니다
속도 걱정은 다른 이야기입니다. 방문 요청마다 바깥으로 전화를 건다면 560ms가 그대로 체감 지연이 됩니다. 기록기를 붙여 둔 채로 실제 페이지를 호출해 봤습니다.
| 요청한 주소 | SQL 쿼리 | 바깥 요청 |
|---|---|---|
| 홈 | 39 | 0 |
| 글 두 편 | 63 / 64 | 0 |
| 소개 페이지 | 31 | 0 |
| 없는 주소(404) | 30 | 0 |
| 로그인 화면 | 11 | 0 |
| RSS 피드 | 28 | 0 |
| REST 글 목록 | 48 | 0 |
아홉 번 호출하는 동안 바깥으로 나간 요청은 한 건도 없었습니다. 업데이트 확인은 예약 작업에서만 돌고, 이 서버의 예약 작업은 방문자가 아니라 시스템 스케줄러가 깨웁니다. 글 한 편에 SQL 쿼리가 63개 나가는 것은 그대로인데, 이 부분은 글 한 편 여는 데 SQL 쿼리 63개에서 어디서 나오는지 뜯어 봤습니다.
막으면 조용히 거짓말을 합니다
워드프레스에는 바깥 요청을 전부 막는 설정이 있습니다. 켜 두고 다시 쟀습니다. 결과는 예상과 두 군데에서 달랐습니다.
첫째, 요청 시도가 3건이 아니라 6건으로 늘었습니다. 암호화 연결로 보내려다 막히면 워드프레스가 평문 연결로 한 번 더 시도하기 때문입니다. 실제로 나가지는 않으므로 바이트는 0이고, 세 가지 확인이 200밀리초 만에 끝났습니다.
둘째가 문제입니다. 응답을 한 글자도 받지 못했는데 세 가지 캐시가 모두 새로 만들어졌고, 확인 시각이 지금으로 찍혔으며, 코어 업데이트는 “0건”으로 기록됐습니다. 막기 전 상태로 되돌려 실제로 확인해 보니 이 설치는 7.0.7이고 7.1.3이 나와 있었습니다. 큰 자리가 올라간 갱신입니다.
즉 바깥 요청을 막으면 관리 화면은 “최신입니다”라고 말합니다. 업데이트가 없어서가 아니라 물어보지 못해서인데, 화면에는 그 차이가 드러나지 않습니다. 막으려면 허용 목록에 업데이트 서버를 넣어 두는 쪽이 안전합니다. 참고로 허용 목록 판정은 생각보다 좁아서, 자기 도메인과 localhost라는 이름은 통과하지만 127.0.0.1이라는 주소는 차단 대상으로 잡혔습니다. 사이트 상태 점검이 쓰는 자기 호출까지 같이 막힐 수 있다는 뜻입니다.
그 자기 호출도 재 봤습니다. 사이트 상태 점검은 자기 자신의 wp-cron.php를 한 번 불러 보고 응답이 오는지 확인하는데, 이 서버에서는 50밀리초 만에 200으로 돌아왔고 판정은 정상이었습니다.
다시 잴 것
이번 측정은 7.0.7에서 7.1.3이 나와 있는 시점의 것입니다. 갱신할 것이 있는 상태와 없는 상태에서 응답 크기가 어떻게 달라지는지는 아직 모릅니다. 코어를 7.1.3으로 올린 뒤 같은 측정을 다시 해서, 응답 1,515B가 얼마나 줄어드는지 확인하려고 합니다. 플러그인 응답 47B는 바닥값일 테니 비교 기준으로 쓸 수 있습니다.
기록기는 측정이 끝난 뒤 걷어 냈습니다. 상시로 붙여 두면 요청마다 파일에 쓰는 비용이 생기고, 그 자체가 측정값을 흔듭니다.
자주 묻는 것
이 요청을 막아도 됩니까
막을 수는 있지만 그냥 막으면 관리 화면이 거짓으로 “최신”이라고 표시합니다. 응답을 못 받은 것과 갱신이 없는 것을 구분하지 않고 둘 다 0건으로 기록하기 때문입니다. 막아야 한다면 업데이트 서버를 허용 목록에 넣어 두고, 자기 자신을 부르는 요청이 함께 막히지 않는지도 확인해야 합니다.
멀티사이트면 사이트 수만큼 늘어납니까
늘어나지 않습니다. 예약 작업은 블로그마다 따로 잡히지만 결과는 네트워크 공용 저장소에 한 벌만 저장됩니다. 블로그 세 개로 측정했을 때 첫 번째만 3건을 보냈고 나머지 둘은 0건이었습니다. 다만 테마와 플러그인은 네트워크 전체 기준으로 집계되므로, 쓰지 않는 테마를 지우면 보내는 양이 줄어듭니다. 테마 네 벌에 2,805B였으니 한 벌당 700B 정도입니다.
방문자가 느려집니까
이 설치에서는 아닙니다. 아홉 가지 주소를 불러 보는 동안 바깥 요청이 0건이었습니다. 느려지는 경우는 예약 작업을 방문자 요청이 대신 깨우도록 두었을 때입니다. 그러면 운 나쁜 방문자 한 명이 560ms짜리 통화 세 건을 떠안게 됩니다. 시스템 스케줄러로 옮겨 두면 이 문제가 사라집니다.