Child pages
  • Google App Engine spin up time 높이기..
Skip to end of metadata
Go to start of metadata

Google App Engine(이하 GAE)를 활용해 SLiPP.net 운영을 시작하고 첫 번째 부딪히는 문제가 사용자의 트래픽이 적을 경우 GAE에서 GAE 인스턴스를 다운시켜 버린다. 인스턴스 다운되어 있는 상태에서 요청이 들어올 경우 인스턴스를 다시 시작하는데 일정 시간이 소요된다. 특히 Spring 프레임워크 기반으로 GAE를 개발할 경우 Spring 프레임워크의 ApplicationContext를 초기화, DataStore 관련 설정, jar 파일 로딩을 하는데 많은 시간이 소요된다. GAE 관리툴에서 확인해 보니 최소 5~6초 정도가 소요되는 것을 알 수 있었다.

SLiPP.net을 오픈한 첫 날에는 호기심 때문에 많은 사용자가 접속한 관계로 인스턴스가 내려가는 경우는 많지 않았다(보통 2분 정도 요청이 없으면 인스턴스가 내려가는 듯하다.). 그런데 그 다음 날부터 접근할 때마다 5,6초 이상을 기다린 후에 사이트를 접속할 수 있는 상황이 되었다. 원인을 찾아보니 일정시간 요청이 없을 경우 인스턴스를 다운 시킨다는 것을 알게 되었다. 이를 해결하려면 GAE의 Always On 기능을 활용해 해결할 수 있다. 그러나 Always On 기능을 활용하려면 0.3$/day의 비용을 지불해야 한다. 이 비용이 부담스럽지는 않지만 서비스가 활성화되지 않은 상태에서 이 비용을 지불한다는 것은 괜시리 아깝다는 생각이 든다. 또한 사용자가 점처 늘어나 트래픽이 증가한다면 지불하지 않아도 되는 비용이다.

SLiPP.net을 오픈한 초반에는 접속자도 많지 않고 다른 기능을 보완하는데 집중하느라 이에 대한 해결책은 미루고 있었다. 그러던 중 윤신(온라인 상에서 Kenny라는 닉네임으로 활동하는 친구)이가 내가 겪고 있는 문제점을 인식하고 Strategy: Cache Application Start State To Reduce Spin- 문서를 공유해 주면서 이에 대한 해결 방법이 있겠다는 생각을 하고 해결책을 찾기 시작했다.

이 문서를 보면 인스턴스가 시작할 때의 초기 상태 값을 Memcached와 같은 캐시 서버에 저장한 상태로 활용하면 인스턴스의 spin up time을 최소화할 수 있다는 내용이다. 나도 이 방식으로 해결책을 찾기 위해 접근하던 중에 해결책을 찾을 수 없으면 마지막으로 이 방법을 사용해야지 하고 생각했던 방법을 찾게 되었다. 이 방법은 생각보다 너무 간단해 바로 적용해 보기로 했다.

해결책은 무식하지만 단순하다. 특정 서버에 cronjob을 등록해 1분 간격으로 SLiPP.net의 특정 URL을 지속적으로 호출하는 것이다. 그러면 GAE 인스턴스는 다운되지 않은 상태로 유지될 것이라 생각했다. GAE가 일일 Quota가 있는데 이에 영향을 미칠 수 있겠지만 극히 미미하리라 생각했다. 그런데 나와 같은 생각을 한 개발자가 예상외로 많았다. 따라서 일단은 이 방법을 적용하기로 했다.

여러 문서 중에서도 가장 쉽게 접근할 수 있는 방법은 Heroku - Spin Up에 답변으로 올라와 있는 해결책이다.

일단 가장 단순한 이 방법을 적용했더니 30분도 걸리지 않아 문제를 해결했다. 이와 같이 설정하고 난 이후 SLiPP.net에 접속하는 속도가 상당히 빨라졌다.

1차적으로 문제를 해결했으니 다음은 다음과 같은 방법으로 문제를 해결할 계획이다.

  • http://www.pingdom.com/를 활용할 수도 있지만 썩 좋은 방법은 아닌 듯하고 GAE에서 제공하는 Cron(Scheduled Tasks With Cron for Java 기능을 활용하도록 변경한다.
  • 이 방법은 좀 단순 무식한 해결책이다. 원론적인 해결책은 캐시를 활용해 해결하는 방법이다. App Engine and Spring slow start up 문서에도 다양한 의견이 있는데 여기 나온 해결책 중에서 아이디어를 얻어오 좋을 듯 하다.
class WrapServlet implements HttpServlet { 
  DispatcherServlet disp; 
  Cache cache; 
 
  public response service(request, response) { 
    if (disp == null) { 
      disp = cache.get(dispKey); 
      if (disp == null) { 
        disp = new DispatcherServlet(); 
        cache.put(dispKey, disp); 
      } 
    } 
    return disp.service(request); 
  } 
} 

위 소스코드도 참고해 한번 접근해 보면 해결책이 나오지 않을까 생각한다. 이 이슈는 다른 이슈들을 해결한 이후에 다시 한번 도전해 봐야겠다.

Google App Engine Spin Time 문서도 이 문제를 해결하는데 참고할만한 유용한 문서이다.

  • No labels