성능
워드프레스 관리자 화면만 10초 걸릴 때: 범인은 DB 쓰기와 시놀로지 Photos 인덱싱
글 페이지는 빠른데 wp-login과 wp-admin만 2~12초 걸린 원인을 구간별로 재서 DB 쓰기 fsync와 Photos 인덱싱의 디스크 포화로 좁히고 MariaDB 설정으로 0.1초대로 되돌린 기록입니다.
NAS에서 워드프레스 7개를 운영하고 있는데, 어느 날부터 로그인 화면(wp-login.php)이 뜨는 데 2.5초에서 길게는 12초가 걸렸습니다. 관리자 화면(/wp-admin/)도 2~4초였습니다. 이상한 건 방문자가 보는 글 페이지는 0.3~1초로 멀쩡했다는 겁니다.
결론부터 말하면 PHP도 워드프레스도 아니었습니다. 데이터베이스에 쓰는 순간만 느렸고, 그 원인은 같은 디스크에서 돌던 시놀로지 Photos의 사진 인덱싱이었습니다.
층을 하나씩 떼어서 재 봤습니다
느린 게 어디인지 모를 땐 요청이 지나가는 길을 잘게 잘라 따로 잽니다. 제가 잰 순서와 값입니다.
| 측정 대상 | 걸린 시간 | 뜻 |
|---|---|---|
| 정적 파일 | 0.015초 | 웹 서버와 네트워크는 정상 |
| PHP + DB 연결만 하는 테스트 파일 | 0.12초 | PHP와 DB 접속은 정상 |
워드프레스 부팅(wp-load.php) | 0.075~0.63초 | 조금 느리지만 수 초는 아님 |
| SELECT 쿼리 | 약 1ms | 읽기는 빠름 |
| INSERT / UPDATE 한 건 | 1.3~2.7초 | 여기가 범인 |
쿼리별 시간은 임시 mu-plugin으로 SAVEQUERIES를 켜서 봤습니다(확인 후 바로 지웠습니다).
그럼 왜 로그인 화면만 느렸냐면, 로그인 화면과 관리자 화면은 열기만 해도 DB에 씁니다. 로그인 시도 제한 플러그인이 트랜지언트 2개를 쓰고, 관리자 화면은 Action Scheduler가 잠금 행을 UPDATE하고, wp-cron은 _transient_doing_cron을 씁니다. 캐시된 글 페이지는 읽기만 하니 멀쩡했던 거고요.
쓰기가 느리면 디스크를 봅니다
MariaDB는 커밋할 때마다 로그를 디스크에 확실히 적으려고 fsync를 부릅니다. 쓰기가 한 건에 2초씩 걸린다면 그 fsync가 느린 겁니다. 디스크가 얼마나 바쁜지는 /proc/diskstats로 10초 동안 바쁜 시간이 얼마나 늘었는지 보면 됩니다.
a=$(awk '$3=="md2"{print $13}' /proc/diskstats); sleep 10
b=$(awk '$3=="md2"{print $13}' /proc/diskstats)
echo "md2 util=$(( (b - a) / 100 ))%"
fsync 한 번이 얼마나 걸리는지는 dd로 4KB짜리를 동기 쓰기로 적어 보면 알 수 있습니다.
dd if=/dev/zero of=./ddtest bs=4k count=20 oflag=dsync; rm -f ./ddtest
결과는 이랬습니다.
- volume2(RAID5 하드디스크 3개, Btrfs)의 바쁜 비율이 77~90%
- 그런데 실제 처리량은 읽기 2.5MB/s + 쓰기 3MB/s뿐
- 4KB 동기 쓰기 한 번에 260~630ms
- RAID 재동기화나 스크럽은 돌고 있지 않음
바쁜데 처리량이 이렇게 낮으면 작은 조각을 여기저기 읽고 쓰는 랜덤 IO로 디스크가 꽉 찬 상태입니다. 하드디스크는 이런 작업에 약합니다.
누가 디스크를 쓰고 있었나
프로세스별로 8초 동안 읽고 쓴 양(/proc/<pid>/io)을 비교했습니다. 이건 root 권한이 필요합니다.
| 프로세스 | IO | 정체 |
|---|---|---|
synofoto-task-center | 읽기 25MB | Synology Photos 인덱싱. 패키지를 재시작한 뒤 24시간째 돌고 있었고, 얼굴 인식도 24시간째 |
postgres: walwriter | 쓰기 20MB | Photos가 쓰는 PostgreSQL |
| Btrfs 커널 워커 | - | 파일시스템 작업 |
| MariaDB | fsync 10초에 22번 | 피해자 |
사진 수십만 장을 다시 인덱싱하는 동안 같은 볼륨에 있는 DB가 순서를 기다리고 있었던 겁니다.
고친 것 — 인덱싱은 그대로 두고 DB 쪽을 바꿨습니다
Photos 인덱싱을 멈추면 바로 빨라지겠지만, 사진 검색에 필요해서 그대로 두기로 했습니다. 대신 MariaDB가 디스크를 덜 기다리게 두 가지를 바꿨습니다.
SET GLOBAL innodb_flush_log_at_trx_commit = 2;
SET GLOBAL innodb_buffer_pool_size = 1073741824; -- 1GB
innodb_flush_log_at_trx_commit=2는 커밋마다 로그를 운영체제에 넘기기만 하고, 실제 디스크 fsync는 1초에 한 번 몰아서 합니다. 대가는 있습니다. NAS 전원이 갑자기 나가면 마지막 1초 정도의 트랜잭션이 사라질 수 있습니다. 개인 블로그 7개라 그 정도는 받아들이기로 했습니다.
버퍼 풀은 확인해 보니 16MB밖에 안 돼서 읽기도 계속 디스크로 가고 있었습니다. 설정 파일에 3GB라고 적어 놨는데 왜 16MB였는지는 따로 정리했습니다. SET GLOBAL은 재시작하면 사라지니, 설정 파일에도 같이 적어서 영구화했습니다.
| 항목 | 전 | 후 |
|---|---|---|
wp-login.php | 2.5~12.7초 | 0.1~0.25초 (첫 요청 0.5~0.85초) |
/wp-admin/ | 2~4초 | 0.08~0.25초 |
| 버퍼 풀 적중률 | 85% | 98.5% |
나흘 뒤 다시 재 보니
9월 27일에 같은 측정을 다시 했습니다. 로그인 화면은 워드프레스 3곳 모두 첫 요청이 최대 0.6초, 그다음부터 0.13~0.18초로 유지되고 있습니다. volume2 바쁜 비율도 34%로 내려왔습니다.
그런데 dd 동기 쓰기는 여전히 느렸습니다. 4KB 20번에 9초, 한 번에 약 450ms입니다. 즉 디스크 자체가 빨라진 게 아니라 DB가 fsync를 덜 부르게 바꿔서 증상이 사라진 것입니다. 디스크 쪽 원인은 아직 남아 있습니다.
정리하면 순서는 이렇습니다. 관리자 화면만 느리면 먼저 읽기와 쓰기를 나눠 잽니다. 쓰기만 느리면 디스크의 바쁜 비율과 dd oflag=dsync 시간을 봅니다. 그다음 같은 볼륨에서 누가 디스크를 쓰는지 찾습니다. PHP나 캐시 플러그인을 먼저 만지면 시간만 갑니다.
확인한 공식 자료
구현 과정에서 판단 기준을 교차 확인한 공식 문서입니다. 글의 사례와 결론은 운영자가 직접 겪은 작업을 바탕으로 작성했습니다.