내게 가장 익숙한 언어는 Python이고, 백엔드 엔지니어인 내게 가장 익숙한 웹 프레임워크는 Flask다. 처음 백엔드를 시작하고 썼던 게 JavaVert.x였는데, Flask는 비교적 훨씬 간단하게 웹 API 서버를 개발할 수 있었다. Flask를 처음 마주쳤을 땐 소프트웨어 쪽으론 아는 게 정말 없었기에, '간단함'은 Flask라는 프레임워크에 빠져들기에 충분한 이유였던 것 같다.

사실 내가 처음 Flask를 시작했을 땐 Flask의 메이저 버전이 0대였고, 0.11, 0.12같은 걸 stable 버전으로 사용했었다. 동시에 Flask의 인기가 꽤 많아지기 시작했고, 2018년 4월 27일 새벽에 Flask 1.0이 릴리즈되었다. Flask는 마이크로 프레임워크기에, 정석적으로 정해져 있는 틀이 딱히 없어서 구조나 모범 사례들에 대해 자주 고민하게 됐었다. 근데 지금 생각해 보면, 무언가에 대해 그토록 깊게 고민해봤던 적이 없던 것 같다. 그래서 Flask는 내게 정말 고마운 프레임워크다.

Flask

마이크로 프레임워크, 멀티 스레드 형태의 요청 처리 방식을 사용하는 웹 프레임워크이다. Python으로 개발되었으며, WSGI(CGI의 Python 구현체) 툴킷으로 Werkzeug를, 템플릿 엔진으로 Jinja2를 사용한다. Flask는 The Pallets Projects라는 팀에서 개발하고 있는데, Flask가 의존하고 있는 Werkzeug와 Jinja2 또한 동일한 팀에서 개발되고 있다.(The Pallets Project는 clickitsdangerous라는 라이브러리로도 유명하다.)

Flask는 비슷한 느낌의 이름을 가진 bottle이라는 마이크로 프레임워크를 겨냥하여 만들어졌고, 따라서 API도 비슷한 점이 많다.

마이크로 프레임워크 답게 간단한 웹 서버REST API 서버를 빠르게 개발하기 좋고, 나만의 어플리케이션 구조를 만들어나가는 재미도 쏠쏠하다. AWS Lambda + AWS API Gateway 위에 서버리스 어플리케이션의 배포를 돕는 zappa도 Django, Pyramid, Bottle과 함께 Flask를 지원한다. 풀 스택 프레임워크인 Django와 함께, 가장 인기가 많은 파이썬 웹 프레임워크가 아닐까 싶다.

다양한 스타일의 라우팅 방식 지원, context와 설정 데이터 관리, 테스트 등에서 프레임워크가 정말 많은 부분에 대해 깊게 고민해 주었다는 것을 느낄 수 있고, 공식 문서와 코드가 매우 잘 정리되어 있다. '파이썬을 여행하는 히치하이커를 위한 안내서'라는 책에서는, '훌륭한 코드를 읽기' 챕터에서 Flask를 예로 들어 설명하고 있을 정도다. Lightweight, Minimal, Open source, Documentation, Easy to use, Well designed 정도가 Flask를 사용하는 이유다.

GET '/' -> 'Hello World'

Flask를 이용해, 3000번 포트에서 동작하며 '/'에 대해 GET 요청을 하면 'Hello World'를 반환하는 간단한 웹 서버를 만들어 보도록 하자. 먼저 pip를 통해 Flask를 설치해야 한다. 가상 환경이 필요하다면 별도로 준비하도록 하자.

$ pip3 install flask

setup.py에 의해 Flask와 함께 의존성 라이브러리인 Werkzeug, Jinja2, itsdangerous, click이 동시에 설치된다. 그리고 아래는 위에서 이야기한 요구사항을 맞춘 Flask 어플리케이션이다.

1번 라인에서는 flask 패키지에서 Flask 클래스를 import했다. __init__.py가 import를 중계해 주기에, 실제로 잡히는 경로는 flask/app.py 모듈의 Flask 클래스다.

3번 라인에서는 Flask 객체를 생성하고 있다. import_name이라는 인자에 Flask 어플리케이션 패키지의 이름을 전달하며, 일반적으로 __name__을 사용한다.

5~7번 라인은 API의 정의에 대한 부분이다. Flask에서 지원하는 라우팅 방식 중 가장 기본형은, 위와 같이 route 데코레이터함수를 이용하는 것이다. 첫 번째 위치 인자로 전달되는 문자열은 해당 API의 URL rule이 되고, 키워드 인자로 HTTP 메소드 등 추가적인 옵션을 붙일 수 있다. 별도로 메소드를 명시하지 않으면 GET에 대해서만 동작하며 다른 메소드로 접근 시 405 Method Not Allowed가 response된다.

Flask에선 위처럼 API의 로직을 처리하는 함수를 view function이라고 부른다. view function의 이름은 식별자로 사용되기에 unique해야 하며, return 문에서 반환된 값은 Flask에서 Response라는 클래스의 인스턴스로 wrapping하여 응답으로 전해진다. 위의 경우, 'Hello World'라는 문자열을 return했으므로 response data는 'Hello World'가 되고, Flask에서 content type과 status code를 각각 기본값인 text/plain, 200으로 설정하여 response한다.

10번 라인은 Flask 어플리케이션을 실행하는 구문이다. 여기에도 debug 모드 등 몇가지 옵션을 추가할 수 있다.


결론적으로, 우리는 10줄 남짓의 코드를 통해 '/'에 대한 GET 요청을 처리할 수 있는 HTTP 서버를 구현했다. python 또는 python3 명령을 통해 모듈을 실행하고, localhost:3000에 접속하면 'Hello World'가 보일 것이다.

Django와 같은 풀 스택 프레임워크에 비해, 준비 과정이 간단하고 '파일 하나'로 천천히 시작할 수 있다. 사람마다 다르겠지만, 굳이 지금 필요없는 건 보이지조차 않아서, 내겐 차근차근 배워가기에 정말 좋았다.

'Python 계열 > Flask' 카테고리의 다른 글

GET '/' -> 'Hello World'  (0) 2019.02.12
POST '/' -> 'Hello World'  (0) 2018.09.20

SELECT 절에는 statement가 들어갈 수 있다. 단지 테이블의 특정 컬럼만이 아니라, 어떤 리터럴 값이나 을 포함할 수 있다는 것이다. 아래는 이미 우리에게 익숙한 SELECT절의 예다.

그리고 SELECT는 아래처럼 사용할 수도 있다.

한 row에, 'Hello', 20, 9라는 결과가 출력될 것이다.

응용

스키마가 동일한 두 테이블을 결합하기 위해, UNION을 사용하곤 한다.

한 row에 대해서, 레코드가 어느 테이블 소속인지를 알고 싶은 경우, literal select를 사용한다.

row마다, 레코드의 소속을 나타내는 'app' 또는 'web'이 origin이라는 이름으로 항상 포함될 것이다.

'데이터베이스 > SQL' 카테고리의 다른 글

Literal SELECT  (0) 2019.02.12
집계 함수와 조건식을 함께 사용하기(SELECT FROM SELECT)  (0) 2019.02.12
GROUP BY  (0) 2019.02.12

ProxySQL은 MySQL 호환 데이터베이스(MySQL, Persona, MariaDB 등)를 backend로 두고, 외부의 connection을 받아 쿼리를 중계해 주는 쿼리 라우팅(Query routing)을 핵심으로 하는 MySQL Proxy Database다. 설정되어 있는 backend들에 주기적으로 health check를 보내고, 이들 중 하나가 죽으면 auto failover해주는 등, 로드 밸런싱과 유사하다. 이 외에도 쿼리 캐싱, 다운타임 없는 설정 변경 등을 지원한다. Amazon RDS 등에서 이야기하는 Master/Slave 구조로 인해 데이터베이스가 많은 수로 read replication되어 있는 상태에서 이들에게 효율적으로 커넥션을 분배해 주거나, 외부에서 많은 양의 커넥션이 들어오는 경우 효과적으로 connection을 pooling하기 위해 자주 사용된다.

구성

ProxySQL은 Runtime, Memory, Disk, Config file의 4가지 계층으로 이루어져 있다. 어느 곳에서 영감을 받았는진 모르겠지만, 처음 봤을 땐 꽤 생소하다.

Runtime

ProxySQL로 들어오는 요청을 처리하는 스레드의 메모리 내 데이터 구조를 표현한다. 시스템 수준에서 디버깅을 하는 정도가 아니라면 비교적 신경쓸 일이 적다.

Memory

main이라고도 부른다. MySQL 호환 인터페이스를 사용할 수 있는, in-memory로 동작하는 데이터베이스를 나타낸다. 쉽게 말하면 여기서 설정 값이 상주하고 있고, MySQL 클라이언트로 쿼리 가능하다는 의미다. Memory 내에는 대표적으로 아래 4개의 테이블이 존재한다.

  • mysql_servers : ProxySQL이 실제로 중계할 서버들의 목록을 관리한다. 중계 대상 서버들을 백엔드 서버라고도 부른다.
  • mysql_users : ProxySQL이 관리하는 사용자의 자격 증명 목록이다. '얘는 이 데이터베이스에 read, 얘는 이 데이터베이스에 read/write 권한, ..' 같은 설정들을 다룬다.
  • mysql_query_rules : 백엔드 서버로 트래픽이 라우팅될 때 평가되는 쿼리 규칙의 목록이다. 이 테이블을 사용하면, 'LIMIT 없는 쿼리는 사용하지 못한다' 와 같은 동작이 가능하다.
  • global_variables : 프록시가 사용하도록 구성된 전역 변수의 목록이며, MySQL connection timeout이나, connect retry 횟수와 같은 메타데이터들을 다룬다.

Disk

ProxySQL 자체 데이터베이스가 실제로 동작하는 곳의 이름이 memory인 이유는, 실제로 in-memory 형태의 SQLite3 데이터베이스가 상주하고 있기 때문이다. 따라서 영속성이 보장되지 않기 때문에, memory 내 구성을 유지하기 위한 계층으로서 Disk가 사용된다.

Config file

Memory에서 돌아가고 있는 데이터베이스에 설정 값들을 dump시킬 수 있는, 전형적인 설정 파일이다.

production level의 MySQL Proxy로 ProxySQL을 가장 많이 사용하고 있는 것 같다. 설치 과정은 ProxySQL Github의 wiki에 잘 나와 있다. 백엔드 인프라의 고도화 단계엔 정말 들어가는 게 많은 것 같다.

'배경지식' 카테고리의 다른 글

ProxySQL  (0) 2019.02.12
직렬화와 JSON  (0) 2019.02.12
ORM  (0) 2019.02.12
HTTP 메소드  (0) 2019.02.12
StatsD  (0) 2019.02.11
HTTP 헤더  (0) 2018.11.02

+ Recent posts