Nginx + Gunicorn + Django + PostgreSQL

여태 Django의 빌트-인 웹 서버를 이용하다가, Nginx와 Gunicorn을 연동해보기로 했다. 아래의 링크에서 가장 많은 도움을 받았고, 설치하며 겪었던 시행착오를 정리하기 위해서 글로 정리한다.

환경

  • OS : Ubuntu 16.04
  • Python : 3.4
  • Django : 1.8.5 (LTS)

패키지 설치

$ sudo apt-get update

$ sudo apt-get install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx

PostgreSQL

PostgreSQL은 오픈소스 RDBMS다. MySQL에 비해 SQL 표준을 잘 지키고 있고, Genetic query optimizer라고 불리는 알고리즘 덕분에 쿼리가 복잡해질 수록 성능이 더 잘나오는 편이라고 한다.

$ sudo -u postgres psql

  • psql : 쿼리문을 입력할 수 있는 데이터베이스 콘솔 실행.
  • postgres : PostgreSQL의 디폴트 사용자.

postgres=# CREATE DATABASE myproject;

postgres=# CREATE USER myprojectuser WITH PASSWORD 'password';

postgres=# ALTER ROLE myprojectuser SET client_encoding TO 'utf8';

postgres=# ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed';

postgers=# ALTER ROLE myprojectuser SET timezone TO 'UTC';

postgres=# GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;

virtualenv, virtualenv-wrapper

virtualenv는 프로젝트 개발에 필요한 파이썬 패키지를 독립된 가상환경에서 설치하고 관리할 수 있게 돕는 툴인데, virtualenv-wrapper는 기존의 virtualenv를 좀 더 편하게 쓸 수 있도록 몇 가지 기능을 추가한 툴이다.

$ pip3 install virtualenvwrapper

아래의 환경 변수와 쉘 스크립트를 .bash_rc에 추가한다.

.bash_rc

WORKON_HOME=/home/ubuntu/Envs
VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
source /usr/local/bin/virtualenvwrapper.sh
  • WORKON_HOME이 가르키는 디렉토리에 가상 환경들이 모인다.

$ source ~/.bash_rc : 변경된 .barh_rc 스크립트 실행

$ mkvirtualenv myenv : 가상환경 생성, 활성화

$ deactivate : 가상환경 비활성화

$ workon myenv : 가상환경 활성화

Django

$ workon myenv

$ pip3 install django

$ django-admin.py startproject myproject

$ cd myproject && ./manage.py migrate

settings.py

ALLOWED_HOSTS = ['server_domain_or_ip', ]

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'myproject',
        'USER': 'myprojectuser',
        'PASSWORD': '',
        'HOST': 'localhost',
        'PORT': '',
    }
}

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static_files/')
MEDIA_URL = '/uploads/'
MEDIA_ROOT = 'upload_files'

$ ./manage.py collectstatic : 프로젝트 내의 static file(css, javascript, image ..)을 STATIC_ROOT가 가르키는 디렉토리 밑으로 복사

Gunicorn

$ pip3 install gunicorn

/etc/systemd/system/gunicorn.service

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
Environment="variable=value"
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/myproject
ExecStart=/home/ubuntu/Envs/myenv/bin/gunicorn --workers 3 --bind unix:/home/ubuntu/myproject/myproject.sock myproject.wsgi:application

[Install]
WantedBy=multi-user.target

Environment : .bash_rc에 있는 환경 변수를 읽어오지 못하기 때문에 필요한 시스템 환경 변수는 여기에 작성.

User : gunicorn을 실행할 시스템 사용자의 이름

WorkingDirectory : Django 프로젝트의 경로

ExecStart : django 서버를 실행하는 명령어. ' myproject.sock ' 파일로 Nginx와 통신하게 된다.

$ sudo systemctl start gunicorn

$ sudo systemctl enable gunicorn

$ sudo systemctl daemon-reload : gunicorn.service 파일이 변경됐을 때 적용.

$ sudo systemctl status gunicorn : gunicorn의 실행 상태, 에러 여부도 알 수 있다.

NginX

/etc/nginx/site-available/default

server {
    listen 80;
    server_name my_domain.com;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        alias /home/ubuntu/myproject/static_files/;
    }

    location /uploads/ {
        alias /home/ubuntu/myproject/upload_files/;
    }

    location / {
        include proxy_params;
        proxy_pass http://unix:/home/ubuntu/myproject/myproject.sock;
    }
}

$ sudo ln -s /etc/nginx/site-available/default /etc/nginx/site-enabled/default

 - 'site-enabled' 폴더의 심볼릭 링크('site-available' 폴더의 default 파일)를 기준으로 Nginx 서버가 실행된다.

$ sudo nginx -t : Nginx 설정 파일의 문법 에러 검출.

$ sudo systemctl start nginx : Nginx 서버 재시작.

  • /var/log/nginx/error.log : 에러 로그 파일.

성능비교 ( Pingdom )


Django를 "빌트인 서버"로 실행할 때와 "Nginx+Gunicorn"로 서버를 실행했을 때, 웹 사이트 성능 비교


빌트인 서버

 


Nginx, Gunicorn

 






 자바스크립트의 동일 연산자에는 두 가지가 있다.

  • 관대한 동등/비동등 연산자 "==" "!="
  • 엄격한 일치/불일치 연산자 "===" "!=="

책에서는 동등 연산자는 너무 많은 값을 같다고 판단하므로, 일치 연산자를 사용할 것을 권장하고 있다.

그렇다면 어떤 값들을 동등 연산자로 비교했을 때, 기대한 것과 다르게 값이 나올까 궁금했다.

그리고 Stack Overflow에서 관련된 질문을 찾았고, 가장 많은 명성(?)을 얻은 답변은 다음과 같다.



 일치 연산자  ===  는 타입 변환이 안되는 것을 제외하고 동등 연산자  ==  와 동일하게 동작하며, 일치하는 것으로 간주되려면 타입이 항상 같아야 합니다.

 동등 연산자  ==  는 모든 필수적인 타입 변환을 한 후에 동등함을 비교할 것입니다. 일치 연산자  === 는 타입 변환을 하지 않기 때문에, 두 값이 같은 타입이 아니면  === 는 단순히 false를 반환합니다. 둘 다 속도는 같습니다.

 더글라스 크록포드(JSON의 아버지!)의 JavaScript: The Good Parts를 인용해보겠습니다.


 자바스크립트는 두 세트의 동일 연산자를 가집니다.  ===  와  !== , 그리고 그들의 나쁜 쌍둥이  ==  와  != . 좋은 것들은 당신이 예상하는대로 동작하는 것입니다. 만약 두 개의 피연산자가 동일한 타입, 동일한 값이면  ===  는 true를 만들고,  !== 는 false를 만듭니다. 나쁜 쌍둥이는 피연산자가 같은 타입일 때 올바르게 동작하지만, 다른 타입이라면 그들은 피연산자의 값을 마음대로 하려 할겁니다. 그들의 행동으로 형성된 법칙은 복잡하고 기억하기 어렵습니다. 여기에 몇 가지 흥미로운 케이스가 있습니다.


"" == '0' //false
0 == "" //true
0 == '0' //true

false == 'false' //false
false == '0' // true

false == undefined //false
false == null //false
null == undefined // true

'\t\r\n' == 0 // true

 타당성이 부족한 것이 놀랍습니다. 내 조언은 나쁜 쌍둥이들을 절대 사용하지 말라는 겁니다. 대신, 항상  ===  와  !== 를 사용하세요. 위의 모든 비교들은  ===  로 비교하면 false를 만듭니다.

 레퍼런스 타입에 대해서는  ==  와  ===  는 특별한 경우를 제외하고, 서로 일관성을 갖고 동작합니다.


var a = [1,2,3];
var b = [1,2,3];

var c = {x: 1, y: 2};
var d = {x: 1, y: 2};

var e = "text";
var f = "te" + "xt";

a == b // false
a === b // false

c == d // false
c === d // false

e == f // true
e === f // true


"abc" == new Striing("abc") // true
"abc" === new String("abc") // false

 여기  ==  연산자는 두 객체의 값을 검사하고, true를 반환하지만, 그들이 같은 타입인지 보는  ===  는 false를 반환합니다. 무엇이 맞을까요? 그것은 정말 당신이 비교하려는 것에 따라 달렸습니다. 나의 조언은, 질문을 완전히 돌아가서, String 생성자를 문자열 객체를 생성하는데 사용하지 말라는 것입니다.


'JavaScript' 카테고리의 다른 글

[JavaScript] Trailing Comma 번역자료  (0) 2017.10.02
[JavaScript] 변수 스코프  (0) 2017.04.13
[JavaScript] 생성자 함수  (0) 2017.02.27
[JavaScript] 배열 연결  (0) 2017.01.26

선형 자료구조의 한 종류인 리스트는 배열 리스트(Array List)와 연결 리스트(Linked List)로 나뉜다. 


# 배열 리스트 ( Array List ) 

배열 기반으로 구현된 리스트.

장점

- index를 이용한 랜덤 접근 지원

단점

- 처음에 길이를 정해줘야 하며 필요에 따라 길이를 변경할 수 없다. ( 고정 길이 )

- 추가/삭제 시 나머지 요소들의 이동이 필요하다.


# 연결 리스트 ( Linked List ) 

: 메모리에 동적할당된 공간에 데이터를 저장하고, 그 공간들을 연결해서 구현한 리스트다. 

장점

- 처음에 길이를 정할 필요가 없고 각 요소는 메모리에 동적할되므로 길이 제한에 자유롭다. ( 가변 길이 )

- 추가/삭제 시 나머지 요소들의 이동이 필요없다.

단점

- 순차 접근으로 시간 복잡도 증가.


# 자바의 Array List

: Java Collection에서도 Array List, Linked List같은 리스트 자료구조를 제공하는데, 이 중 Array List는 이름을 그대로 해석하면 "배열 리스트"지만 기존 배열기반 리스트의 단점을 보완한 특징을 가진다.

장점 

- 처음에 길이를 정할 필요가 없다. ( 가변 길이 )

- 랜덤 접근 지원.

단점

- 추가/삭제 시 나머지 요소들의 이동이 필요하다.

'Data Structure' 카테고리의 다른 글

번역] Inorder Successor in Binary Search Tree  (0) 2016.05.01

+ Recent posts