본문 바로가기

TechLog

nginx, uWSGI 설정하다 삽질한 기록

최근 django 기반의 서비스를 만들고 서버를 구축하면서 기존의 Apache + mod_wsgi로 구성되어 있던 웹 서비스 컨테이너를 nginx + uWSGI로 교체하였다. 워낙 서버가 구차한 사양이다보니(가상 서버 호스팅이라 정체조차 알 수 없는 cpu에 램 1GB 따위 ㅇㅇ…) 조금이라도 리소스를 덜 먹고 가벼운 웹 서버를 선택하는 것이 좋겠다는 생각을 했기 때문이었다.

nginx에 대한 평가야 웹 쪽에 관련된 일을 하고 있다면 한 번쯤은 들어봤을 것이고 … uWSGI의 경우 비교적 사람들이 많이 쓰는 WSGI 서버라는 얘기도 들었고, 퍼포먼스 관련 자료를 읽다 보니 비교적 안정적이고 적은 리소스를 소모한다는 점에서 uWSGI를 선택하기로 했다. (WSGI 서버의 퍼포먼스에 자세한 내용이 궁금하신 분은 다음 링크를 참조하시라: http://nichol.as/benchmark-of-python-web-servers)

 

nginx야 요즘 워낙 많이 쓰이니 패키지 자동 설치 기능으로도 설치할 수 있고 설정하는 법도 비교적 쉬운 편이다. 헌데 uWSGI의 경우에는 워낙 쓰는 사람만 쓰는 물건이다보니 전반적으로 설정에 대한 설명이 부실하고 불친절하긴 하다. mod_wsgi 같은 모듈이야 아파치에 붙는 것이다 보니 그냥 잘 돌아가지만, uWSGI는 nginx하고만 연동되는 서버도 아니고 …

 

그리하여 비극이 시작되었다 (…)

몇 가지 겪은 일들을 열거해보면:

 

- uWSGI는 기본 init.d 스크립트를 제공하지 않는다.

원래 uWSGI 서버 자체가 필요에 따라 한 서버에서 여러 프로세스를 구동하여 여러 사이트를 호스팅하거나, 프로세스끼리 로드 밸런싱을 하거나 … 뭐 이런저런 유연하고 해괴한(?) 방식으로 서버를 구성할 수 있도록 되어 있다.

그것까지는 좋은데 … init.d 스크립트 좀 만들어주면 뭐가 어때서! 난 리눅스도 잘 못 다룬다고! ‘ㅁ`) 어쨌든 그래서 다음과 같이 스크립트를 만들고, chkconfig 유틸리티를 사용해서 init.d 서비스에 등록했다. (상단의 주석은 chkconfig가 init.d 서비스에 이 스크립트를 등록하는데 필요한 정보다)


 

보면 알겠지만, 케냘의 경우 서버에서 여러 사이트를 호스팅하고 있기 때문에, uwsgi_bitna처럼 각 사이트를 위한 uWSGI 프로세스를 별도로 실행하도록 구성해두었다. 사실 하나의 uWSGI 프로세스로 모든 사이트를 처리해도 상관은 없고, 게다가 uWSGI는 self-healing 기능도 있다고 하지만, 케냘은 왠지 맘에 안 들어서 … 어쨌든 저렇게 여러 개의 uWSGI 구동 스크립트를 만들어도 좋고, 하나의 uWSGI 구동 스크립트에서 여러 uWSGI 서버를 구동하도록 해도 좋고, 마음대로 지지고 볶아도 된다. 하지만 케냘은 init.d 스크립트를 만들어본 게 언제인지 기억도 안 나서 … 분명히 대학 다닐 때 만들어 본 것 같기도 한데 (…)

또한, 프로세스 시작/정지에 start-stop-daemon 유틸리티를 사용하고 있는데, pid를 직접 처리하는 방법을 알고 있다면(cat으로 pid 파일을 읽어들여서 kill 하는 등…) 그 방법을 사용해도 상관은 없다. 그리고, 케냘은 ubuntu를 사용하지 않고 있기 때문에 적용할 일은 없었지만, ubuntu에서는 update.rc-d 유틸리티를 사용해서 init.d 서비스를 설정할 수 있다고 한다.

 

 

- POST 요청 시 “readv() failed (104: Connection reset by peer) while reading upstream” 에러 발생하는 문제

일단 참고한 글 링크부터 달아본다: http://stackoverflow.com/questions/3970495/nginx-connection-reset-response-from-uwsgi-lost

버그 내용이 되게 당황스러운데 … POST 요청에 대한 응답이 4052 바이트 이하일 경우에 해당 요청의 HTTP BODY가 0바이트로 돌아온다. 케냘도 덕분에 API를 호출하는데 이건 뭐 불러도 대답 없는 서버고, GET 요청은 올바로 처리되고 … 어쨌든 결론은 uWSGI 서버의 post-buffering 설정을 4052 이상으로 설정해주면 된다. (케냘의 경우에는 4096으로 설정되어 있다) 현재 케냘이 사용하는 버전은 nginx 1.0.12, uWSGI 1.0.4인데, 저 글이 올라온 지 꽤 되었음에도 불구하고 같은 문제가 또 발생한다는 게 참 뭐라고 해야 할 지…

 

 

- HTTPS 요청을 처리하지 못하는 문제

이것은 nginx의 uWSGI 관련 기본 설정 때문에 발생하는 문제인데, nginx 설치 디렉토리의 uwsgi_params 파일의 마지막 줄에 다음 내용을 추가하면 된다:

uwsgi_param UWSGI_SCHEME $scheme;

이 설정을 하지 않으면 uWSGI에 대한 http/https 요청이 모두 http로 처리되어 버린다.

 

 

 

어쨌든 설치 구성을 끝내고 보니 맘에 든다. Apache를 쓸 때보다 확실히 반응 속도는 좋아졌다만, 이런 삽질을 또 겪고 싶진 않으니 앞으로 배포할 서버는 성능 최적화가 그렇게 심각한 사안이 아니면 Apache + mod_wsgi를 사용하기로 마음먹었다 (…)

 

그럼 여기서 끗.