본문 바로가기
개발공부/Python알고리즘

[Python] Flask vs FastAPI vs gRPC 비교와 예제

by 왜지? 2023. 1. 29.
반응형

API란?

- Application Programming Interface로 요청하는 쪽과 응답하는 쪽 간에 통신 방법을 정의.

- 일반적으로 Server와 Client로 구분되어 사용.

  → Client에서 Server로 요청을 보내면, Server는 이에 응답함

- API의 사용 목적에 따라 다양한 종류의 API가 사용 중. 

  → RESTfull 방식 : 최근 가장 많이 사용되는 방식으로, HTTP/1.1 기반 통신을 사용하며 json, xml 형식의 데이터를 직접 전달한다. 

  → RPC 방식 : Remote Procedure Call로 Client가 원격으로 Server에 접속해 통신. gRPC가 등장하며 많이 쓰이는 추세이다.

- Python 라이브러리는 RESTful(Flask, FastAPI) 방식과 rpc(gRPC) 방식 모두 구현 가능. 

RESTful
rpc 방식

Flask

- 가볍고 간편하게 구현할 수 있는 Rest API 라이브러리.

- 소규모 & 중규모 프로젝트에 적합하며 표준화되지 않았다.  

- HTTP/1.1 통신은 Connecttion 당 하나의 처리만 가능하기때문에 동시에 많은 요청을 처리할 때 병목이 발생할 수 있다.

- 프로토타입이나 기능 Test 시 사용 권장

from flask import Flask, request, jsonify
from flask_swagger_ui import get_swaggerui_blueprint

app = Flask(__name__)

SWAGGER_URL = '/swagger'
API_URL = '/static/swagger.json'
swaggerui_blueprint = get_swaggerui_blueprint(
    SWAGGER_URL,
    API_URL,
    config={
        'app_name': "My Flask App"
    }
)
app.register_blueprint(swaggerui_blueprint, url_prefix=SWAGGER_URL)

@app.route('/')
def hello():
    """
    This is a simple example of a Flask endpoint
    ---
    description: Returns a simple message
    responses:
      200:
        description: A simple message
    """
    return 'Hello, World!'

@app.route('/user/<username>')
def show_user_profile(username):
    """
    This is an example of a Flask endpoint with a parameter
    ---
    parameters:
      - name: username
        in: path
        type: string
        required: true
        description: The username to look up
    responses:
      200:
        description: Returns a message with the specified username
    """
    return f'User {username}'

@app.route('/post', methods=['POST'])
def create_post():
    """
    This is an example of a Flask endpoint that accepts a POST request
    ---
    parameters:
      - name: body
        in: body
        required: true
        schema:
          type: object
          properties:
            message:
              type: string
    responses:
      201:
        description: Returns the data sent in the request in JSON format
    """
    data = request.get_json()
    return jsonify(data), 201

if __name__ == '__main__':
    app.run(debug=True)

 

FastAPI

- Flask 대비 속도가 빠르고 효율성을 높인 Framework이다.

- asyncio와 type hint를 통해 개발 생산성은 높이고 버그를 줄여준다. 

- 고성능을 보장하여 Flask 대비 장점이 많은 것으로 평가받음.  

- Flask처럼 HTTP/1.1 통신의 한계를 가지고 있다. 

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI(title="My FastAPI App", docs_url="/docs", redoc_url="/redoc")

class Item(BaseModel):
    name: str
    price: float

@app.get("/")
def read_root():
    """
    This is a simple example of a FastAPI endpoint
    """
    return {"Hello": "World"}

@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
    """
    This is an example of a FastAPI endpoint with a path parameter
    """
    return {"item_id": item_id, "q": q}

@app.post("/items/")
def create_item(item: Item):
    """
    This is an example of a FastAPI endpoint that accepts a JSON request
    """
    return item.dict()

@app.get("/docs")
def docs():
    """
    This is an example of a FastAPI endpoint for swagger documentation
    """
    return JSONResponse(content=app.openapi())

@app.get("/redoc")
def redoc():
    """
    This is an example of a FastAPI endpoint for redoc documentation
    """
    return HTMLResponse(content=app.openapi(dumps=lambda x: x))

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

 

gRPC

- HTTP/2.0 이용한 양방향 스트리밍 제공 ( 서버가 일방적으로 제공하는 것이 아님 ) 

  → Latency와 리소스 사용 측면에서 HTTP/1.1의 성능을 끌어올렸다. 

  → Connection 당 여러개의 처리가 가능하다. 

- protobuff로 바이너리 형태의 값을 전달하여 속도가 매우 빠르다.

- MSA 프로젝트 시 사용 권장

 

1) .proto 파일 구현

syntax = "proto3";

package greet;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloResponse) {}
}

message HelloRequest {
  string name = 1;
}

message HelloResponse {
  string message = 1;
}

 

2) gRPC 서버 구현

import grpc
from concurrent import futures
import time

from protos.greeter_pb2 import (
    HelloRequest,
    HelloReply
)
from protos.greeter_pb2_grpc import (
    GreeterServicer,
    add_GreeterServicer_to_server
)

class MyGreeterServicer(GreeterServicer):
    def SayHello(self, request, context):
        return HelloReply(message='Hello, {}!'.format(request.name))

def run_server(host, port):
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    add_GreeterServicer_to_server(MyGreeterServicer(), server)
    server.add_insecure_port(f'{host}:{port}')
    server.start()
    print(f"Server started at {host}:{port}...")
    try:
        while True:
            time.sleep(60 * 60 * 24)  # one day in seconds
    except KeyboardInterrupt:
        server.stop(0)

if __name__ == '__main__':
    run_server('0.0.0.0', 50051)

3) gRPC Client 구현

import grpc

from protos.greeter_pb2 import HelloRequest
from protos.greeter_pb2_grpc import GreeterStub

def run_client(host, port):
    channel = grpc.insecure_channel(f'{host}:{port}')
    stub = GreeterStub(channel)
    response = stub.SayHello(HelloRequest(name='John Doe'))
    print(response.message)

if __name__ == '__main__':
    run_client('localhost', 50051)

 

4) gRPC Swagger 구현

def run_server(host, port):
    server = SwaggerDecoratedServer(
        grpc.server(futures.ThreadPoolExecutor(max_workers=10)),
        swagger_host=host,
        swagger_port=port+1,
    )
    add_GreeterServicer_to_server(MyGreeterServicer(), server)
    server.add_insecure_port(f'{host}:{port}')
    server.start()
    print(f"gRPC Server started at {host}:{port}...")
    print(f"Swagger documentation available at http://{host}:{port+1}/docs")
    try:
        while True:
            time.sleep(60 * 60 * 24)  # one day in seconds
    except KeyboardInterrupt:
        server.stop(0)

 

비교

  Flask FastAPI gRPC
통신방법 RESTful RESTful RPC
네트워크 HTTP1.1 HTTP1.1 HTTP2.0
데이터 형식 json,xml 등 json,xml 등 바이너리
속도 느림 빠름 빠름
사용처 테스트, 프로토타입 WEB/APP 서비스 MSA 개발 시

비교 표를 위해 이렇게 표현했지만, Flask도 아직까지 충분히 좋은 성능을 보여주고 있어 많은 부분에서 사용 중이다. 하지만 성능적인 부분을 고려하면 앞으로는 FastAPI와 gRPC를 상황에 맞게 사용하게 될 것 같다.

반응형

댓글