내 Ghost blog는 왜 느릴까? - (2)

앞선 글에서 느린 Ghost blog 의 원인을 찾고 개선(?)을 했다. 남겨진 문제를 해결하는 과정을 살펴보자.

남겨진 문제

서버 시작 후 첫 접근에서 8~10 s 의 시간이 소요되는 문제가 발견되었다. 그러나, 따로 "서버 시작 후 첫 로딩이 엄청 느려요" 라는 문서를 찾아볼 수는 없었다. 답답한 마음에, 서버포럼으로 가서 질문글을 남겨보았고, 다음과 같은 답변을 얻었다.

낮은 사양의 호스트 PC에서 가상화까지... 좀 무리지 싶습니다. 싱글코어 2.9Ghz 이상이면 날라다닐겁니다.

이전 글에서는 첫 분석에서 "호스트는 문제가 아니야...!" 라고 단정을 지었다. 그런데, 이 답변을 보고 난 뒤, 호스트가 진범일 수 있겠다 싶었다.

호스트 PC 사양 변경

기존에 블로그 서버가 탑재되어있던 호스트 PC 의 사양은 다음과같다.

CPU - Intel N4100
RAM - 8 GB
SSD - SATA WD GREEN 120G

VM에 모든 자원 부여

Proxmox -> VM -> Docker --- Ghost container 및 4개의 컨테이너

다시 생각해보면, 결과로 얻어낸 100ms 내외의 렌더 속도도 "빠르다" 라고 하기에는 너무나 느렸다. Ghost 블로그를 self-host 하고 있는 블로그를 직접 찾아가 응답 속도를 살펴보면 이보다 빠르다. 심지어 50ms 내외로 나오는 곳도 많다.

그래서 한번 Docker container 가 위치한 호스트를 변경해보기로 했다. 마침 성능 짱짱한 Deskmini 호스트가 하나 놀고 있다. 이 녀석의 스펙은 다음과 같다.

CPU - AMD Ryzen 4750G
RAM - 64G
SSD - nvme SSD 500G

서버 운영할 VM
CPU - 16 vCPU
RAM - 32G

VM 의 성능을 최대로 끌어서 줬으며, 자체 CPU의 성능도 쓸만하다. 저전력 / 무소음이라서 CPU 클럭 자체가 낮은 이전 호스트와 달리, CPU 클럭도 3.6Ghz로 넉넉하다.

migration을 할 때 딱히 다른 것을 변경하지는 않았고, 연결된 volume 과 설정 통채로 host PC 로 옮겼고 그대로 테스트를 진행했다.

테스트

  • 이전 상황과 동일하게 도커 컨테이너 restart 이후 browser / Ghost response time 확인
  1. 브라우저 응답시간
  • host 변경 전
    • '/' (home)
      • Browser
        • 7~10 sec
      • Ghost
        • 7~10 sec
    • '/some-article-page' (post page)
      • Browser
        • 7~10 sec
      • Ghost
        • 7~10 sec
        • 304 상황에서는 100~200ms
  • host 변경 후
    • '/' (home)
      • Browser
        • 700 ms 전후
      • Ghost
        • 700 ms 전후
    • '/some-article-page' (post page)
      • Browser
        • 70 ms 전후
      • Ghost
        • 70 ms 전후
        • 304 상황 또한 20ms 전후

ㅋㅋㅋ.. 놀랄만치 빠르게 바뀌었다. 특히, 글을 읽는 페이지에서 괄목할만한 변화가 생겼다. 덩달아서 재접속 상황에서도 100ms 전후에서 50ms 전후로 개선이 되었다. 오히려 서버 내부가 아닌 외부에서 걸리는 시간이 눈에 띄는 수준이다.

proxy를 켜면 어떻게 달라질까?

사양 변경을 하고 너무 문제가 쉽게 해결되어 허탈했다. 하루 종일 뭐가 문제인지 파고 있었는데, 이렇게 해결이 될 줄이야. 그렇다면, 이전에 문제로 지적되었던 cloudflare 의 proxy 를 다시 켤 때는 속도가 어떻게 될까?

우선 내 가정은 다음과 같다. proxy가 있을 때 약 700ms 내외의 응답시간을 보였다. 이는 주로 네트워크 지연 시간이지만, cloudflare 에서 내 서버로 갔다 오는 시간도 어느정도 포함될 수 있다. 내 서버의 응답시간이 개선되었으니 300ms ~ 500ms 내외의 시간으로 감소하거나, 캐싱이 되고 있다면 그대로 유지될 것이다.

한번 proxy를 켜보고 다시 테스트를 해보자

정말 길게는 1sec 내외, 평균적으로는 300~400ms 의 응답시간을 보인다.

서버 로그와 대조해봤을 때, 서버는 그대로 20~30ms 으로 200 응답을 주고 있었고, 나머지 시간은 온전히 미국에 있는 cloudflare 의 CDN 에 갔다오는 시간이다. 아마 내 추측대로, cloudflare<->server 사이의 응답 시간이 줄어들었고 그 시간은 약 100ms 정도가 될 것이다. 대략 100 ~ 200 ms 정도 감소했으니, 얼추 맞는 값이다.

결과적으로 cloudflare dns proxy를 사용할 경우 느려진다. 특히, 500ms 에서 100ms 으로 줄어든 것이 생각보다 눈에 띄게 차이가 났다. 500~700ms 의 응답의 경우 "기다린다" 라는 느낌이 들기 때문이다. (약 10 frame 정도 되는 시간이니..)

고부하 상황에서는...?

앞선 글에서 "호스트는 잘못이 아니야..." 라고 할 때 "그런데, 접속자 수가 늘면 곤란할 것 같아.." 라고 했다. 변경된 환경에서는 어떨까? 겸사겸사 한번 테스트해봤다.

테스트 환경은 다음과 같다.

  • siege test
    • connection : 128
    • time 30s
Lifting the server siege...
Transactions:		        1477 hits
Availability:		      100.00 %
Elapsed time:		       30.78 secs
Data transferred:	       10.33 MB
Response time:		        2.56 secs
Transaction rate:	       47.99 trans/sec
Throughput:		        0.34 MB/sec
Concurrency:		      122.83
Successful transactions:        1477
Failed transactions:	           0
Longest transaction:	        3.31
Shortest transaction:	        0.15

Throughput 이 0.05MB/sec 나오던거 생각하면 눈물이난다. 비록 128 커넥션이 동시에 유지되는 경우 2.56sec 으로 느리기는 하나, 기존 5.58 sec 에 비하면 꽤나 개선된 수치이다. 또한 지금은 2 sec 전후로 꾸준하게 나오나, 이전에는 심하면 12sec 까지 튀는 경우가 빈번했다.

글을 마치며

아무튼 대장정이 끝났다. 이게 뭐라고 하루를 온전히 썼다. 그렇지만 마냥 시간을 버린 것 같지는 않다. 이 과정에서 요런 것들을 좀 배웠다.

  • DNS 동작
    • 다계층 DNS 쿼리
      • DNS 자체가 재귀 / 반복적으로 작동함은 이해하고 있었지만, 직접 마주하면서 작업하니까 은근 쉽지 않았다. 내 경우 다음과 같이 DNS 쿼리가 날라갔다.
        • 1. 내부 DNS (pi-hole)
        • 2. 가까운 DNS (아마도 kns.kornet.net 이런 친구)
          • 대부분 여기서 다 처리된다.
        • 3. Root DNS
        • 4. TLD DNS
        • 5. Authoritative DNS
          • Cloudflare DNS
    • DNS 전파
      • pagespeed 에서 종종 분석이 불가능한 케이스가 있었는데, 보통 DNS가 제대로 전파되지 않은 경우였다.
  • DNS 캐싱
    • DNS 캐시 flush 하기 (Mac / Pi-hole DNS Server)
  • CDN 의 역할
    • 그리고 CDN이 해외에 있으면 어떻게 되는지...;;
  • Docker container migration
    • 사실은 volume migration이 조금 더 적합...

조금 더 있을 것 같긴한데, 지금 생각나는건 이 정도이다.

그리고 과정에서 서버 관련하여 보완한 것, 보완할 점들도 몇 개 있었다.

  • 서버 private service / public service 분리
    • IP 가 한정적이라, 결국 reverse proxy 를 통해서 내부 서비스들을 포워딩해야하는데, private / public service 를 한 nginx 에서 관리하고 있어 보안상의 위험성이 있었다. 따라서 private service 의 경우 완전히 격리된 네트워크 안쪽으로 가두었고, public service 를 proxy 하기 위한 별도의 nginx 를 따로 올려뒀다.
  • Docker container 모니터링
    • 현재는 proxmox 를 통해서 호스트와 VM 의 상태만 모니터링되고 있다. 그러나, 실제로 서비스를 하면서는 서비스가 속한 컨테이너가 얼마나 자원을 소모하고 있는지에 대해서 봐야할 필요가 생긴다.
    • 따라서 docker container 에 대해서도 주기적으로 모니터링을 할 수 있도록 해보려고 한다.

보완하고 보완할 것들은 추후에 더 글로 자세히 남겨보자...

어쩌다보니 오늘도 밤을 새버렸다... 홈 서버 구축 자체가 배울 것도 많고 재밌어서 시간이 후딱 간다. 끝!


Read more

대량의 더미 데이터 DB에 주입하기

대량의 더미 데이터 DB에 주입하기

대량의 더미 데이터 DB에 주입하기 현재 만들고 있는 토이 프로젝트에서는 대량의 데이터가 존재하는 DB 를 대상으로 여러가지 테스트를 수행한다. 테스트를 수행하기 위해서 더미 데이터를 주입할 방법에 대해서 모색해야했다. SQL Procedure * SQL 문으로 직접 테이블에 데이터를 주입한다. * 직접 Insert into () values (); 와 같은 구문을 작성할 수도 있지만, Procedure 혹은 function 을

By Sungjun Park
Lombok 에 대한 짧은 생각

Lombok 에 대한 짧은 생각

최근 Java / Spring 으로 스택을 변경하면서 작은 프로젝트를 하고 있다. 팀원의 추천으로 lombok 이라는 라이브러리를 사용하게 되었다. Lombok 을 쓰면 정말 간단하다. Getter, Setter, Constructor, equals, hashCode 과 같이 작성해야하지만 작성에 피로를 느끼는 코드들을 annotation을 통해서 너무 쉽게 만들 수 있다. 그런데, 이 라이브러리 사용할수록 필요성에 대한 의문이 생긴다. 생각을

By Sungjun Park