Bucket Place/기타

[Apache] 아파치 서버 최적화, 그리고 추가적으로 Rails Queue

Cloud Travel 2015. 4. 22. 14:48

 1. 여는


 안녕하세요. 아름다운 집을 만들기 위해 노력하는 버킷플레이스의 개발자 CloudTravel입니다. 새로운 버전 업데이트와 함께 버킷플레이스가 오늘의 집으로 바뀐것을 알려드리며, 오늘의 글을 시작합니다. 오랜만에 블러그에 글을 작성해봅니다. 그간 여러가지 일이 있어서 바뻐서 도통 하질 못했내요. 새로운 개발자분도 오셨으니 여유가 되는 만큼 글을 작성하려고 합니다. ^^


 오늘은 서버프로그램중 많이 사용되는 아파치를 최적화 하는 방법에 대해서 알아보도록 합시다. 리눅스 기반의 파일 구조에서 설명하므로 몇몇 분들에게 있어서 약간 불편한 점이 있을 수 있음을 알려드립니다.




 2. Apache 서버 설정 파일


 설정에 앞서서 Apache서버 설정 파일은 어디에 있는가를 알아봅시다. Apache 서버 설정은 /etc/apache2 폴더 이하에 있는 파일들에 의해서 이루어집니다.  일반적인 글에서는 httpd.conf를 열어서 서버를 설정하게 되어있는데, httpd.conf를 열었을 때 텅텅빈 파일을 보고 놀라시는 분이 있을 수 있습니다. 이 경우에는 apache2.conf 파일이 존재하는 것을 볼 수 있습니다. 또한, apache2.conf 파일을 잘 읽어 보시면 마지막 부분에 다른 파일들을 Include 시키는 부분을 찾을 수 있을 것입니다.


 /etc/apache2 폴더를 살펴보면 위와 같은 구조로 되어있습니다. 설정에 사용되는 각각의 파일 및 디렉토리를 설명하면 아래와 같습니다.


  apache2.conf 

 메인 설정 파일입니다. 서버 설정에 대한 왠만한 것들은 다 여기 정의되며 Include를 이용해

 다른 파일을 첨부시킬 수 있습니다.

  ports.conf

 특정 포트에 대해서 작동하는 방식을 설정 할 수 있습니다. SSL을 사용할 경우 이 곳을

 꼭 바꿔야 합니다.

  conf.d/

 아파치 특성을 보다 자세하게 정의 할 수 있습니다. 

 예를 들어, SSL 설정을 하거나 보안 설정을 선택할 수 있습니다. 

  sites-available/

 사람들이 서버로 접속했을 때 어떤 곳으로 연결을 해줄지에 대한 정보들을 가지고 있는

 폴더입니다. 이 디렉토리 아래의 파일들은 실제로 사용되는 파일이 아니고 설정 정보 만을 

 가지고 있습니다.

  sites-enabled/

 실질적으로 사람들이 서버로 접속했을 때 어떤 곳으로 연결해줄지에 대한 정보를 담고 있는

 폴더입니다. sites-available에 설정된 설정 파일들 중 하나를 symbolic link로 연결 해주는 

 것이 일반적입니다.

  mobs-[enabled, available]

 모듈들에 대한 정보를 갖고 있는 폴더이며 sites에서 나눠진 것과 같이 똑같은 역할을 수행하게

 됩니다.


























 이번글에서 알아볼 내용은 메인설정 부분입니다. 즉 apache2.conf파일(또는 httpd.conf)을 설정하는 방법입니다. 




 3. 준비 사항 1: 컴퓨터의 성능 및 메모리 사용량 조사

 

 아파치를 설정하기에 앞서서 컴퓨터 성능, 아파치 하나하나의 Thread가 차지하는 메모리의 양 그리고 아파치 이외에서 사용되는 메모리의 양을 알아야한다.

 

 아래는 예시에 값들이다.


 1) 사용된 컴퓨터의 성능 

   4vCPU, 8GB(8192MB) RAM, OS : Ubuntu LTS 12.04 server


 2) 아파치 하나하나의 Thread가 차지하는 메모리의 양

   아래의 스크립트를 이용하면 손쉽게 아파치가 사용하고 있는 메모리의 양을 알 수 있다.


ps -ylC apache2 | awk '{x += $8;y += 1} END {print "Apache Memory Usage (MB): "x/1024; print "Average Proccess Size (MB): "x/((y-1)*1024)}'


  그리고 이것은 예제 서버에서 이 스크립트를 돌렸을 때의 결과 값이다.

  

   이 결과는 서버가 과부하 상태(Heavy load)에 가장 자세히 나오지만, 이를 알기 위해서 과부화 시킬 필요는 없다. 각자의 

  생각을 통해 여유롭게 서버 하나하나의 Size를 정해보도록하자. 

 

  글쓴이는 오랜 기간 서버를 보았을 때 쓰레드당 최대 9~10MB를 사용하는 것을 목격하여 10MB로 계산하였다.


 3) 아파치 이외에서 사용되는 메모리의 양

  여기에서 계산되는 값은 예를 들어 아래와 같다.

   - DB를 같은 컴퓨터에서 돌리고 있다면 DB가 사용하는 메모리의 양

   - 리눅스 자체에서 사용하는 시스템 메모리의 양


   예전에 안 좋은 컴퓨터를 쓸때는 세세하게 위에 나온 값들을 다 계산해서 설정했지만, 지금은 넉넉하게 512MB를 잡았다. 

   (글쓴이의 DB 서버는 나누어져 있다)




 4. 준비 사항 2: Test 프로그램


 아파치 세팅이 끝난 후에 만족한 성능을 얻었는지 파악하기 위해서 Test 프로그램이 필요하다. Test 프로그램들은 사이트로 동시에 몇명이 사용하고 총 몇개의 리퀘스트가 온다라는 것을 가정하여 진행할 수 있다.


 아파치 접속 성능을 테스트하는 방법으로는 두가지가 있다. JMeter와 AB test 방식이다. 각각의 사용 방식에 대해서는 이글에서 설명하지 않겠다. 대신 링크를 주겠다. JMeter의 경우에는 GUI로 즉각적으로 편하게 볼 수 있는게 특징이고,  AB benchmark는 console 상에서 간편하게 진행할 수 있다. AB benchmark는 가끔씩 에러가 나기도 한다. AB benchmark는 이상한 값이 나오기도 하여 JMeter 사용을 권고한다.


 JMeter: http://jmeter.apache.org/  

        https://www.digitalocean.com/community/tutorials/how-to-use-apache-jmeter-to-perform-load-testing-on-a-web-server

 AB benchmark: http://httpd.apache.org/docs/2.2/programs/ab.html




  5. 최적화 해보자


 apache2.conf 파일을 열어보자.(apache2.conf 파일이 없다면 httpd.conf 파일을 열어주면 된다.) 주석도 많이 달리고 쓸데 없는 부분도 있지만, 그런건 생략하고 설정할 부분에 대해서만 알아보도록하자.



 1) Timeout


  이 값의 기본값으로는 300이 지정되어 있다. 이는 서버에서 오류로 인해서 멈춰있어도 300초 동안 세션이 잡혀있는 상태를

 의미한다. 이는 너무 길다. Timeout 값으로 가장 적당한 값은 서버에서 반응하는 시간중 가장 긴시간 + 3~5초이다. 아무리 

 길게 잡아도 30이라는 값을 넘기지 않는 것이 일반적이다. 

 

  글쓴이는 10초로 잡았다.

 


 2) KeepAlive


    KeepAlive는 같은 TCP로 접속하는 사용자가 원할하게 사용할 수 있도록 통로를 비워두는지 여부를 설정한다.

   이 값의 기본값은 On이다. On으로 설정할 경우에는 특정 시간동안 한 라인을 점유하는 형태가 된다. 이는 서버에 심한 

   과중을 줄 수 있다. 왠만하면 Off로 설정을 바꿔주는 것이 좋다.


    하지만 이미지가 많거나 많은 자바 스크립트를 포함할 경우에는 On으로 해두는 것도 좋은 방법이다. 이 값을 On으로 하면 

   아래의 값들을 잘 설정해야 한다.


    글쓴이는 Off로 하였다.



 3) MaxKeepAliveRequest


   만일 KeepAlive를 On으로 설정했다면 이 값을 설정해줘야 한다. 한 TCP가 통로를 점유 했을때 얼마나 많은 요청을 받아 들일

  것인지를 설정한다. 이 값이 10으로 설정되 있다면, 10번의 요청한 뒤에 점유되었던 통로가 끈어지고 새롭게 연결을 하게 

  된다.



 4) KeepAliveTimeout


   만일 KeepAlive를 On으로 설정했다면 이 값도 설정해줘야 한다. 한 TCP가 통로를 점유 했을때 몇초동안 그 통로를 유지 

  할지를 설정한다. 만약 이 값이 5로 설정되어 있다면, 5초동안 아무런 요청이 없다면 통로가 끈어지게 된다.



 5) prefork MPM


   Apache 1.3에서는 일반적으로는 perfork 값만 설정해주면된다. 2.x 부터는 worker MPM이 기본이므로 이를 설정해야한다. 

  자신의 서버가 사용하고 있는 MPM정보를 알기 위해서는 컴파일 정보에서 apache2 -l 을 통해서 worker.c가 있는지 perfork.c

  가 있는지 확인하면 된다.

 

   prefork 방식은 한 Thread당 하나의 일만 처리가 가능하다. 메모리 사용량도 많고 동시접속자가 많은 경우 오작동을 일으킬 

  가능성이 크다.


   prefork MPM 하부에는 StartServers / MinSpareServers / MaxSpareServers / ServerLimit / MaxClients / 

  MaxRequestsPerChild 등의 값을 설정할 수 있다.


  5-1) StartServers : 서버가 작될 때(service apache start / restart) 생성되는 서버의 양을 설정한다.

                        필자는 50으로 했다. 이 값은 각자의 서버에서 최대 서버량(ServerLimit)보다 작은 값중 편한 것을 

                        선택하면된다. 


  5-2) MinSpareServers : 서버가 한가해도 최소한 이 값 만큼의 서버쓰레드를 유지하려고 한다. 이 값은 절대적인 것이 아니기

                             때문에 이보다 작게 쓰레드가 존재 할 수 있다. (약간 의미가 없는 값중 하나로 본다)

                             필자는 50으로 설정하였다.


  5-3) MaxSpareServers : 서버가 아무리 바뻐도 최대한 이 값 이상의 서버 쓰레드를 만들지 않으려고 한다. 이 값 또한 

                              절대적인 것이 아니기 때문에 이보다 많은 쓰레드가 존재할 수 있다. 또한 이값은 ServerLimit 보다 

                              클 수 없다. (이 값역시 의미가 없는 값중에 하나로 본다)

                              필자는 150으로 설정하였다.


  5-4) ServerLimit : 생성 가능한 최대 서버쓰레드의 양이다. 이 값은 3에서 구한 값을 이용하여 아래와 같이 계산이 가능하다.

                       (컴퓨터 메모리 - 아파치 이외 사용되는 메모리) / (아파치 쓰레드 하나당 소유 메모리)

                       필자는 위 예시에 따라 (8192 - 512) / 10 = 768 을 설정했다.


  5-5) MaxClients : 접속 가능한 최대 유저수를 계산한다. 이 값은 보통 ServerLimit과 같거나 작은 값을 갖는다.

                       필자는 ServerLimit 과 같은 값인 768을 설정했다. 


  5-6) MaxRequestsPerChild : 각각의 Thread마다 몇개의 요청을 처리할 지를 설정한다. 기본값 0은 무한대를 의미한다.

                                   필자는 Thread를 메모리상에서 Free시키는 것이 필요할 것 같아서 1500으로 설정하였다.

                                   이는 1500개의 request를 수행하면 Thread가 메모리에서 사라지는 것을 의미한다.


 6) worker MPM

 

   worker 방식은 한 Thread당 자식 Thread를 여러개 생성하여 관리한다. 이는 하나의 부모가 갖고 있는 정보를 자식들이

  공유하여 메모리 사용량 및 속도 증진을 가져올 수 있다. 이는 동시접속자수가 많은 서비스에 용의하다. 


   worker MPM 하부에는 prefork에서 사용하는 StartServers / MinSpareServers / MaxSpareServers / ServerLimit / 

  MaxClients / MaxRequestsPerChild 와 추가적으로 ThreadsPerChild 등의 값을 설정할 수 있다. prefork와 같은 내용은

  생략하겠다.


   worker를 설정할때 주의점은 다음과 같다. Server 당 자식 Thread를 갖기 때문에 

  ServerLimit * ThreadsPerChild >= MaxClients 값으로 설정해줘야 한다. 이를 주의 해서 각각의 값을 세팅해주면 된다.


  6-1) ServerLimit : 생성 가능한 최대 서버쓰레드의 양이다. 

                        필자는 이 값을 16으로 하였다.


  6-2) MaxClients : 접속 가능한 최대 유저수를 계산한다. prefork에서 serverlimit값을 계산하는 것과 같이 하면 된다.


  6-3) ThreadsPerChild : 각각의 Thread마다 몇 자식프로세스를 생성할 지를 설정한다. 

                              필자는 이 값을 48로 하였다.

                              16 * 48 = 768이다.




 6. Rails 사용자를 위해서...


 만약 Apache와 Rails를 연동하여 사용하는 사용자라면 서버 설정을 잘하여도 Heavy load에 빠지는 경우가 있다. 이는 둘을 연결해주는 passenger에서 지정한 큐의 양이 있기 때문이다. PassengerMaxRequestQueueSize가 바로 그 값이다. 이 값은 기본으로 100으로 지정되어 있다.


 이 값은 mobs-available/passenger.load 파일에 지정해주면 된다. 

LoadModule passenger_module /usr/lib/apache2/modules/mod_passenger.so

PassengerMaxRequestQueueSize 700


  ServerLimit과 같거나 작은 값을 적어 주면된다. 필자는 700으로 설정하였다. 작게한 이유는 아무 이유가 없다.




 7. 닫는글

 

  설정을 한뒤에 동시접속 테스트를 통해 서버가 견뎌내는지를 파악하길 바랍니다. 원할안 서비스를 만들기 위해서 힘냅시다. 


  오랜만에 블러그 글을 작성하여 약간 형식에서 변화가 된 느낌이 드는 것 같기도 하고 ... 잘 쓴것 같기도 하고... 

  질문은 언제나 환영이며 댓글로 부탁드립니다^^