'Server'에 해당되는 글 3건

  1. WSGI로 보는 웹 서버의 개념 (1)
  2. Ubuntu에 개발환경 셋팅하기 (2)
  3. Ubuntu에 개발환경 셋팅하기 (1) (2)

WSGI로 보는 웹 서버의 개념

Web server, WSGI, Middleware, Application

예전에 웹 서버와 WAS, WSGI를 공부하면서 블로그에 포스팅을 몇 개 한 적이 있는데, 이제서야 개념정리가 좀 되어 한 글에 정리하기로 했다.

웹 서버

khanrc: 웹서버, WAS, CGI
웹 서버는 정적이다. 리퀘스트가 들어오면 그 리퀘스트를 분석하여 알맞는 리소스를 리턴한다.

이 웹서버를 동적으로 기능하게 하기 위해서 웹서버 위에 flask, django, rails, node.js따위의 프레임워크를 얹는다. 그게 바로 WAS 다.

웹서버의 구조

apache라고 하자.

  1. 80번 포트를 listening
  2. 리퀘스트가 들어오면 리퀘스트를 처리하기 위한 apache process를 fork
  3. 포크된 아파치 프로세스는 리퀘스트에 붙어 처리하고 원래 있던 프로세스는 그대로 listen

이게 과거의 아파치다. 문제는, 프로세스는 무겁다. nginx는 이를 쓰레드로 전환하여 속도를 향상시켰다. 지금은 아파치도 쓰레드 형태로 전환하여 비슷한 퍼포먼스가 나온다고 한다.

프로세스: code, data, heap, stack 모두 갖고 있는 하나의 덩어리. 즉 독자적인 메모리를 갖고 있다.
쓰레드: 라이트웨이트 프로세스. 하나의 프로세스 안에서 code, data, heap을 공유하고 stack만을 별도로 가지고 있다. 즉 메모리를 공유한다.

WAS

웹 서버 위에 서버 어플리케이션을 얹은 것이 바로 WAS.

WSGI

khanrc: WSGI와 CGI의 차이
ko.wiki: WSGI
Web Server Gateway Interface. 파이썬에서 어플리케이션, 즉 파이썬 스크립트가 웹 서버와 통신하기 위한 명세다. 프로토콜 개념으로 이해하면 될 듯.

WSGI는 서버와 앱 양단으로 나뉘어져 있다. WSGI 리퀘스트를 처리하려면 서버에서 환경정보와 콜백함수를 앱에 제공해야 한다. 앱은 그 요청을 처리하고 콜백함수를 통해 서버에 응답한다.

Middleware

이러한 커뮤니케이션을 WSGI 미들웨어가 보충한다. 이 미들웨어는 서버의 관점에서는 앱으로, 앱의 관점에서는 서버로 행동한다. 이 미들웨어는 아래와 같은 기능을 가진다.

  • 환경변수가 바뀌면 타겟 URL에 따라서 리퀘스트의 경로를 지정해준다.
  • 같은 프로세스에서 여러 애플리케이션과 프레임워크가 실행되게 한다.
  • XSLT 스타일시트를 적용하는 것과 같이 전처리를 한다.

미들웨어에는 mod_wsgi, uwsgi, gunicorn, twisted.web, tornado 등등이 있다.

어플리케이션의 관점에서는 이 미들웨어를 통해 앱이 실행되므로 앱을 실행시켜주는 어플리케이션 컨테이너(Application Container)라고도 할 수 있다.

Framework

서버 어플리케이션을 만들기 위해 사용하는 최상단 웹 프레임워크. Flask로 대표되는 Micro 프레임워크와 Django로 대표되는 Full-stack 프레임워크로 나눌 수 있다.

spoqa tech blog: Flask로 만들어 보는 WSGI 어플리케이션

종합

  1. http 리퀘스트가 들어오면
  2. 웹 서버가 그 리퀘스트를 받고
    • 서버사이드 처리가 필요 없으면 리스폰스를 리턴(static한 웹 서버)
  3. 서버사이드 처리가 필요하면 wsgi 미들웨어를 통해 파이썬 어플리케이션으로 리퀘스트 전달
  4. 파이썬 어플리케이션이 리퀘스트를 받아 처리 후 wsgi 미들웨어 - 웹서버를 통해 리스폰스 리턴.

의 구조라고 할 수 있다.

정리하자면, 상식대로 웹 서버 위에 서버 어플리케이션이 올라가는데 이 어플리케이션과 웹 서버간의 커뮤니케이션을 위해 wsgi 미들웨어가 존재하는 것. 이 미들웨어를 어플리케이션을 적재하는 어플리케이션 컨테이너라고도 할 수 있다. 자바는 잘 모르지만, 자바 서블릿 컨테이너도 동일한 개념으로 보인다.

Ubuntu에 개발환경 셋팅하기 (2)

Ubuntu에 개발환경 셋팅하기 (2)

Redis

레디스를 깔자.

$ apt-get install redis-server

이것만 하면 깔린다.

cp /etc/redis/redis.conf /etc/redis/redis.conf.default

환경설정은 미리미리 백업해 두도록 하자.

redis-server /etc/redis/redis.conf

레디스 서버를 실행시켜 보면 아무 반응도 없는 것 같지만 ps aux로 프로세스를 확인해보면

$ ps aux | grep redis
redis    12649  0.0  0.0  10680  1420 ?        Ss   17:28   0:00 /usr/bin/redis-server /etc/redis/redis.conf

레디스가 동작하고 있는 것을 확인할 수 있다.

redis-cli로 레디스 클라이언트도 정상 작동한다.

$ redis-cli
redis 127.0.0.1:6379>

위에 링크로 걸어둔 문서는 내용이 알찬 것 같으니 읽어보자.

Flask

플라스크 한글 문서
플라스크든 뭐든, 파이썬 환경설정은 virtualenv를 추천하지만 우리는 하나의 프로젝트를 진행할 뿐이므로 System-wide로 설치한다.

$ sudo pip install Flask

그냥 이러면 설치 끝!

SSH

설치 하는데 자꾸 접속이 끊겨서 불편했다. 그래서 타임아웃 시간을 늘려주기로 함.
타임아웃 시간을 컨트롤하는건 크게 두가지 방법이 있는데, 서버에서 타임아웃 시간을 늘려주는 방법과 클라이언트에서 ssh가 알아서 주기적으로 서버에 ack을 보내 스스로가 살아있음을 알리는 방법이다.

우리 팀원들도 분명 긴걸 좋아하리라 굳게 믿고 서버의 타임아웃 시간을 수정하였다.

$ cd /etc/ssh/
$ sudo vim sshd_config

ssh와 sshd가 있는데 ssh는 ssh-client고 sshd는 ssh daemon1으로 ssh-server역할을 하는 것 같다.

ClientAliveInterval 600
ClientAliveCountMax 3

그리고 sshd_config에 이 내용을 추가. 이렇게 설정해 두면 반응이 없는 클라이언트가 살아있는지 600초마다 한번씩 최대 3번 클라이언트에게 데이터 전송을 요청한다.

$ sudo service ssh restart

로 마무리. /etc/init.d/ssh restart도 가능하지만 써보니까 service를 사용하라고 권고하더라.

클라이언트에서 타임아웃 시간을 늘리는 방법은 위 링크를 참조하자.

참고

ps aux

리눅스에서 프로세스들을 보여주는 명령어
http://superuser.com/questions/117913/ps-aux-output-meaning

$ ps aux  
USER       PID  %CPU %MEM  VSZ RSS     TTY   STAT START   TIME COMMAND
timothy  29217  0.0  0.0 11916 4560 pts/21   S+   08:15   0:00 pine  
root     29505  0.0  0.0 38196 2728 ?        Ss   Mar07   0:00 sshd: can [priv]   
can      29529  0.0  0.0 38332 1904 ?        S    Mar07   0:00 sshd: can@notty

USER = user owning the process
PID = process ID of the process
%CPU = It is the CPU time used divided by the time the process has been running.
%MEM = ratio of the process’s resident set size to the physical memory on the machine
VSZ = virtual memory usage of entire process
RSS = resident set size, the non-swapped physical memory that a task has used
TTY = controlling tty (terminal)
STAT = multi-character process state
START = starting time or date of the process
TIME = cumulative CPU time
COMMAND = command with all its arguments

특정 프로세스를 찾을 때에는 ps aux | grep <string> 보다는 pgrep <string> | xargs ps 을 활용하자.

kill

kill PIDkill -9 ProcessName 으로 프로세스를 죽일 수 있다.


  1. 멀티태스킹 운영 체제에서 데몬은 사용자가 직접적으로 제어하지 않고, 백그라운드에서 돌면서 여러 작업을 하는 프로그램을 말한다. 원래 데몬이란 도깨비나 유령을 의미함.

Ubuntu에 개발환경 셋팅하기 (1)

Ubuntu에 개발환경 셋팅하기

소프트웨어 마에스트로 프로젝트 서버를 셋팅한다. 서버는 uCloud에서 구매하였다. 서버 스펙은 나중에 추가.

Server spec

Ubuntu 12.04

Setting

  • Python
    • pip
    • virtualenv
  • Python libs
    • numpy
    • scipy
    • scikit-learn
    • matplotlib
    • nltk
    • newspaper
    • goose
    • boilerpipe
    • feedparser
  • Flask
  • Redis

libs는 개발하면서 그때그때 설치하는게 맞다고 생각하나, 몇가지는 미리 깔아둠.

Python

기본적으로 2.7.3이 깔려 있다.

$ python -V
Python 2.7.3

파이썬 최신버전은 2.7.8.

맥이나 리눅스에는 기본적으로 파이썬이 설치되어 있는데, 그건 OS에서 파이썬을 쓰기 때문이다. 많은 부분들이 파이썬으로 코딩되어 있음. 따라서 이 시스템에 설치되어있는 파이썬(이하 시스템 파이썬)을 함부로 건드렸다간 시스템이 망가진다.

특히, 파이썬의 경우 메이저 버전이 다르면 호환이 안되기 때문에 함부로 업그레이드 해서는 안된다. 여기서 말하는 메이저 버전이란 소수점 둘째자리를 의미. 즉 2.6과 2.7은 호환이 안된다.

그러나 나는 최신버전을 쓰고 싶었고 현재 깔려있는 파이썬은 2.7.3으로 메이저 버전은 같았기에 업그레이드를 시도해 보기로 했다.

1차 시도

$ apt-get update
$ apt-get upgrade
$ apt-get install python2.7

실패. 이미 python2.7이 설치되어 있다고 나온다.

2차 시도

리눅스 Python 2.7 컴파일 설치
이걸 시도해보자. 이건 2.4 -> 2.7이므로 이것보다 수월하게 되리라 기대한다.

다운로드 및 설치

처음부터 막힘. 서버 세팅 문젠지는 몰라도 그냥 wget으로 받아오려면 에러가 난다. 아래처럼 —no-check-certificate 옵션을 추가해 줘야 함. 참고로 -N은 로컬에 있는 파일보다 최신버전만 받는 옵션이다.

$ cd /usr/local/src
$ wget -N --no-check-certificate https://www.python.org/ftp/python/2.7.8/Python-2.7.8.tgz
$ sudo tar xzf Python-2.7.8.tgz
$ cd Python-2.7.8/
$ sudo ./configure
$ sudo make
$ sudo make altinstall

그러고 나면

$ python -V
Python 2.7.3
$ /usr/bin/python -V
Python 2.7.3
$ /usr/local/bin/python2.7 -V
Python 2.7.8

이렇게 된다.

바꿔치기

자 그럼 대망의 바꿔치기!

$ mv /usr/bin/python /usr/bin/python_old
$ cp /usr/local/bin/python2.7 /usr/bin/python
$ python -V
Python 2.7.8

잘 되긴 하는데 yum이 안 됨(yum도 파이썬 스크립트임) -> yum이 안 되는줄 알았는데 알고보니 yum은 안 깔려있었다. 기존의 시스템 파이썬 일때는 yum을 깔라고 나오는데 2.7.8에서는 뭐라뭐라 파이썬 에러가 남. 암튼 이것도 뭔가 안된다는거니 문제다. 고치는 방법이 나와있긴 한데 저렇게 다 고칠수는 없는 노릇… 나 혼자 하는 프로젝트도 아니고 팀플젝이니 여기까지만 하도록 한다 -_-

pip, virtualenv

자 그럼 필요한거나 하자.
How to install pip on Ubuntu

$ sudo apt-get install python-pip python-dev build-essential 
$ sudo pip install --upgrade pip 
$ sudo pip install --upgrade virtualenv

virtualenv는 우리 프로젝트에서 안 쓸 것 같지만 필수적인 패키지 중 하나니 설치해 둔다.

python libs

numpy, scipy, scikit-learn

$ sudo pip install -U numpy scipy scikit-learn

에러 -_-

Command /usr/bin/python -c "import setuptools, tokenize;__file__='/tmp/pip_build_root/scipy/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /tmp/pip-XQ2E58-record/install-record.txt --single-version-externally-managed --compile failed with error code 1 in /tmp/pip_build_root/scipy
Traceback (most recent call last):
  File "/usr/local/bin/pip", line 9, in <module>
    load_entry_point('pip==1.5.6', 'console_scripts', 'pip')()
  File "/usr/local/lib/python2.7/dist-packages/pip/__init__.py", line 185, in main
    return command.main(cmd_args)
  File "/usr/local/lib/python2.7/dist-packages/pip/basecommand.py", line 161, in main
    text = '\n'.join(complete_log)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 72: ordinal not in range(128)

scipy를 설치하다 에러가 난 듯.

한참 삽질하다 보니 이것보다 윗단에 걸 봐야되는거 같다. 저 에러 위에 이게 있었음

numpy.distutils.system_info.BlasNotFoundError:
    Blas (http://www.netlib.org/blas/) libraries not found.
    Directories to search for the libraries can be specified in the
    numpy/distutils/site.cfg file (section [blas]) or by setting
    the BLAS environment variable.

즉 blas라이브러리를 깔아야 한댄다. 이거 깔고 나면 lapack 도 깔라고 함.

$ sudo apt-get install libblas-dev
$ sudo apt-get install liblapack-dev

로 해결. apt-get python-numpy python-scipy 로 하면 쉽게 된다는 거 같은데 여기까지 한 이상 pip로 해보기로 결심함. pip가 더 좋다는 소리도 있다. 왠진 모름 -_-

building 'dfftpack' library
error: library dfftpack has Fortran sources but no Fortran compiler found

이젠 별별 에러가 다 난다. 포트란 컴파일러를 깔아주자.

$ sudo apt-get install libamd2.2.0 libblas3gf libc6 libgcc1 \
libgfortran3 liblapack3gf libumfpack5.4.0 libstdc++6 \
build-essential gfortran python-all-dev \
libatlas-base-dev

뭘 이렇게 많이 설치해야 되는지…

감동. 이러고 설치하면 다 깔린다. 한참 걸리니 터미널을 쳐다보고 있지 말 것을 추천한다. import해서 정상적으로 임포트되는것도 확인.


오늘의 교훈 : 에러메시지를 꼼꼼히 읽자.

오늘의 과제 : pip와 apt-get의 차이는 무엇인가. apt-get은 리눅스 패키지 관리 툴 아닌가? 그렇다면 왜 pip, 즉 파이썬 패키지까지 얘가 관리하는것인가. 만약 둘다 특정 패키지를 설치할 수 있다면, numpy나 scipy같이, 둘중 아무거나로 깔아도 상관 없는 것인가. 상관 있다면 왜 그런가.