서버 자원의 효율성을 극대화하기 위해서는 흔히 비동기 프로그래밍 방식을 적용합니다. 파이썬에서도 비동기 프로그래밍 방식으로 웹서비스를 제공하기 위해서 여타 웹프레임워크 프로젝트가 탄생했습니다. Tornado부터 시작하여, Aiohttp, Sanic, Vibora 등과 같은 프로젝트가 이러한 목적을 갖고 있는 프로젝트입니다. 그 중에서도 Vibora나 Sanic 등과 같은 프로젝트는 서로 자기가 처리 능력이 좋다며 자랑하고 있습니다. 그 이유로 비동기 방식을 활용하기 때문이라고 하는데, 설명을 들여다보면 빠지지 않고 나오는 단어가 있습니다. 바로 uvloop입니다.
uvloop이 무엇인지 궁금하여 알아보면, 다시 libuv라는 라이브러리를 만날 수 있습니다.
이 프로그램에서는 libuv가 어떤 방향성을 갖고 디자인되었으며, 어떤 기능을 갖고 있기에 다수의 프로젝트에서 사용하게 되었는지, 파이썬의 기본 라이브러리인 asyncio와는 어떤 차이점이 있는지를 알아봅니다. 또한 파이썬으로 만들어진 몇몇 웹프레임워크가 어떤 처리 능력을 보여주는지 직접 테스트해본 결과를 공유합니다.
3. •프로그램의 주 실행흐름을 멈추지 않고 진행할 수 있는가의 여부.
•코드의 실행 결과 처리 및 활용을 별도의 채널에 맡겨둔 뒤 결과를 기다리지 않고
바로 다음 코드를 실행하는 방식으로 프로그램을 진행.
•예: Future, Promise, Coroutine 등.
!3
sync vs. async programming
4. •입출력 처리를 완료될 때까지 기다릴 것인지 혹은 시작만 해두고
다음 작업을 계속 진행할 것인지 여부.
•I/O 작업이 완료된 이후에 연결해서 진행할 후속 작업이 있는 경우,
Polling이나 Callback 함수를 사용.
!4
blocking vs. non-blocking I/O
5. •asynchronous programming vs. non-blocking I/O
•Blocking I/O를 사용했어도 이 부분이 별도의 채널을 통한 작업으로 이루어짐으로써
어떤 프로그램의 주 실행흐름을 막지 않았다면,
이 프로그램은 Asynchronous Programming으로 개발했다고 할 수 있음.
!5
async vs. non-blocking
8. •Flask와 유사한 프레임워크.
•가장 빠른 파이썬 웹 서버를 만드는 것이 목표.
•멀티 프로세스 아키텍쳐로, 멀티 CPU 코어를 기본적으로 사용.
•가능한 경우, uvloop과 C로 구현된 더 빠른 방식을 사용함.
!8
Vibora
9. •Flask와 유사한 프레임워크.
•가장 빠른 파이썬 웹 서버를 만드는 것이 목표.
•멀티 프로세스 아키텍쳐로, 멀티 CPU 코어를 기본적으로 사용.
•가능한 경우, uvloop과 C로 구현된 더 빠른 방식을 사용함.
!9
Vibora
이게 뭘까?
10. •asyncio를 사용하는 비동기 HTTP 클라이언트이자 서버 프레임워크.
•서버와 클라이언트 웹소켓을 둘 다 지원.
•웹서버는 미들웨어와 시그널을 제공.
!10
AIOHTTP
https://aiohttp.readthedocs.io/en/stable/
11. •Able to read and write cookies
•높은 성능의 HTTP서버를 쉽게 구축하고 확장할 수 있도록 만드는 것이 목표.
•클래스 기반의 뷰 제공
•블루프린트라는 기능을 통해 서브라우팅 제공.
•uvloop 기반의 비동기로 HTTP를 빠르게 처리할 수 있는 프레임워크.
!11
Sanic
12. •파이썬 웹 프레임워크이자 비동기 네트워크 라이브러리.
•HTTP의 클라이언트와 서버 둘 다 제공.
•코루틴 라이브러리인 tornado.gen 과 yield 문법을 통해 비동기를 구현.
•이 방식으로 인해 콜백 체이닝을 하지 않아도 코드를 깔끔하게 구현할 수 있었음.
!12
Tornado
14. •asyncio는 async/await 구문을 사용하여 동시성 코드를 작성하는 라이브러리
•asyncio는 다음과 같은 작업을 위한 고수준 API 집합을 제공
•파이썬 코루틴들을 동시에 실행 및 제어
•자식 프로세스를 제어
•동시성 코드를 동기화
•저수준 API도 제공
•네트워킹, 자식 프로세스 실행, OS 시그널 처리 등의
비동기 API를 제공하는 이벤트 루프를 만들고 관리
!14
asyncio
25. •대기중인 콜백이 호출됨.
•I/O 콜백은 대부분 I/O 폴링 직후에 호출됨.
•그러나 다음 루프로 호출이 지연되는 콜백도 있음.
•이전 반복에서 지연된 I/O 콜백은 이 시점에서 호출됨.
25
26. •유휴(idle) 핸들 콜백이 호출됨.
•이름은 쉬고 있는 핸들이지만, 활성화 상태라면 모든 루프에
서 실행됨.
26
27. •핸들 준비 콜백이 호출됨.
•루프가 I/O를 차단(block)하기 직전에 준비 핸들이
콜백을 호출함.
27
28. •I/O를 차단하기 전에 루프는 얼마나 오래 차단(block)해야
하는지 폴링 타임아웃을 계산.
•루프가 I/O를 차단(block).
•이 시점에서 루프는 이전 단계에서 계산된 지속 시간 동안
I/O를 차단(block).
•읽기 또는 쓰기 조작에 대해 주어진 파일 디스크립터를
모니터링하고있는 모든 I/O 관련 핸들은 이 시점에서
호출된 콜백을 가져옴.
28
33. !33
사전 준비물
•AWS EC2 m5.2xlarge Instance - Dedicated Tenancy
•8 vCPU, 32 GiB Memory
•ubuntu 18.04
•https://github.com/vibora-io/benchmarks
•pip install 로 버전 지정없이 설치되는 최신 안정화 버전 웹 프레임워크들
34. !34
Forms Parsing
•multipart-form으로 몇 개의 파라미터와
하나의 귀여운 파일을 POST로 전송하는 시나리오
•Vibora code
@app.route('/', methods=['POST'], cache=False)
async def home(request: Request):
return JsonResponse({'count': len(await request.files())})
36. !36
Redis API
•JSON 데이터를 POST로 넘겨받아서 검증을 하고
Redis에서 간단한 데이터를 하나 가져와서 반환하는 시나리오
•Vibora code
@app.route('/', methods=['POST'])
async def home(request: Request, redis: Redis):
schema = await SimpleSchema.load_json(request)
value = await redis.get(schema.key_name)
return Response(value)
42. •Django 3.0에서 ASGI와 함께 동작할 수 있는 완전한 비동기 방식을 지원할 예정
•Django 3.0은 2019년 12월 배포 예상
•동기 방식 코드를 그대로 사용하면 SynchronousOnlyOperation 에러를 볼 수 있음
•기존 코드는 거대한 마이그레이션이 필요할 것으로 보임
!42
Django X async
https://docs.djangoproject.com/en/dev/releases/3.0/#asgi-support