FastAPI 서버개발, 성능 최적화를 위한 캐싱 및 로드 밸런싱 전략

작성자: 조광형

발행일: [오늘 날짜]

소개

FastAPI는 Python으로 작성된 고성능 웹 프레임워크로, 빠른 개발 속도와 높은 성능 덕분에 많은 개발자들에게 사랑받고 있습니다.
하지만 성능이 좋다고 해서 모든 웹 애플리케이션이 원활하게 작동하는 것은 아닙니다. 특히 트래픽이 많은 서비스에서는
성능 최적화가 필수적입니다. 이 글에서는 FastAPI 서버의 성능을 최적화하기 위한 캐싱(caching)
로드 밸런싱(load balancing) 전략에 대해 심도 깊은 설명과 예제를 통해 소개하겠습니다.

캐싱의 필요성

캐싱은 데이터에 대한 접근 시간을 줄이기 위해 자주 요청되는 데이터를 메모리에 저장하는 기술입니다.
FastAPI와 같은 웹 애플리케이션에서 데이터를 매번 데이터베이스에서 가져오는 것은 성능 저하를
초래할 수 있습니다. 데이터베이스 쿼리는 종종 I/O 작업이 포함되어 있어 시간이 많이 소요됩니다.
따라서 캐싱을 통해 데이터를 메모리에 저장하고, 요청 시 빠르게 제공할 수 있습니다.

FastAPI에서의 캐싱 구현

FastAPI에서는 다양한 캐싱 방법을 사용할 수 있습니다. 여기서는 Redis를 사용한 캐싱을
소개하겠습니다. Redis는 오픈 소스 메모리 데이터 구조 저장소로, 높은 성능과 다양한 자료 구조를 지원합니다.

Redis 설치 및 설정

먼저 Redis를 설치합니다. 대부분의 운영 체제에서는 패키지 관리자를 통해 Redis를 쉽게 설치할 수 있습니다.
예를 들어, Ubuntu에서는 다음 명령어를 사용하여 설치할 수 있습니다.

sudo apt install redis-server

설치가 완료되면 Redis 서버를 시작합니다.

sudo systemctl start redis.service

Redis가 정상적으로 실행되고 있는지 확인하려면 다음 명령어를 사용합니다.

redis-cli ping

정상적으로 실행되고 있다면 “PONG”이라는 응답을 받을 수 있습니다.

FastAPI에 Redis 연결하기

FastAPI에서 Redis를 사용하기 위해 aioredis라는 비동기 Redis 클라이언트를 사용합니다.
먼저 필요한 패키지를 설치합니다:

pip install aioredis fastapi uvicorn

예제 코드

이제 FastAPI 애플리케이션을 작성해 보겠습니다. 아래는 Redis를 사용하여 캐싱을 구현한 예제입니다.
이 예제에서는 간단한 GET 요청을 처리하여 서버에서 데이터를 캐시하는 구현을 보여줍니다.


from fastapi import FastAPI, Depends
from aioredis import Redis, from_url
from typing import Optional
import asyncio

app = FastAPI()

# Redis 클라이언트 초기화
redis_client: Optional[Redis] = None

async def init_redis():
    global redis_client
    redis_client = await from_url("redis://localhost")

@app.on_event("startup")
async def startup_event():
    await init_redis()

@app.on_event("shutdown")
async def shutdown_event():
    await redis_client.close()

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    # 캐시에서 데이터 조회 시도
    cached_item = await redis_client.get(f"item:{item_id}")
    
    if cached_item:
        return {"item_id": item_id, "value": cached_item.decode("utf-8"), "source": "cache"}
    
    # 데이터베이스에서 데이터 조회 (가정)
    value = f"Value of item {item_id}"
    
    # 캐시에 데이터 저장
    await redis_client.set(f"item:{item_id}", value)
    
    return {"item_id": item_id, "value": value, "source": "database"}
            

이 코드는 Redis에 연결하고 특정 item_id에 대한 요청이 들어올 때 캐시에서 먼저 데이터를 조회합니다.
캐시에 데이터가 없으면 데이터베이스 (여기서는 가상의 데이터베이스)에서 데이터를 조회하고,
이를 캐시에 저장합니다.

로드 밸런싱의 필요성

로드 밸런싱은 여러 서버 간에 들어오는 네트워크 트래픽을 분산시키는 기술로, 애플리케이션의 가용성을 높이고
성능을 최적화합니다. FastAPI 서버는 단일 인스턴스에서 실행될 경우 높은 트래픽을 처리하는 데 한계가 있을 수 있습니다.
로드 밸런싱을 통해 여러 인스턴스에 요청을 분산시킬 수 있습니다.

로드 밸런싱을 활용하면 다음과 같은 이점이 있습니다:

  • 높은 가용성: 서버가 다운되더라도 다른 서버가 서비스를 계속 제공할 수 있습니다.
  • 성능 향상: 여러 서버가 동시에 요청을 처리하므로 응답 시간이 단축됩니다.
  • 유지보수 용이: 새로운 서버를 추가하거나 기존 서버를 제거할 때 서비스 중단이 없습니다.

FastAPI와 로드 밸런싱

FastAPI 서버를 여러 인스턴스로 실행하고 로드 밸런싱을 구현하기 위한 방법 중 하나는 Nginx를 사용하는 것입니다.
Nginx는 고성능의 웹 서버이자 리버스 프록시로, 로드 밸런싱을 지원합니다.

Nginx 설치 및 설정

우선 Nginx를 설치합니다. Ubuntu에서 설치하는 방법은 다음과 같습니다:

sudo apt install nginx

Nginx가 설치되었다면 설정 파일을 수정하여 FastAPI 서버 인스턴스에 대한 로드 밸런싱 규칙을 추가해야 합니다.

예제 Nginx 설정

아래는 Nginx의 로드 밸런싱 구성 예제입니다:


http {
    upstream fastapi_app {
        server 127.0.0.1:8000;
        server 127.0.0.1:8001;
        server 127.0.0.1:8002;
    }

    server {
        listen 80;

        location / {
            proxy_pass http://fastapi_app;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}
            

이 설정에서는 3개의 FastAPI 인스턴스를 로드 밸런싱합니다. 각 인스턴스는 동일한 서버의 서로 다른 포트에서 실행됩니다.
Nginx는 들어오는 요청을 로드 밸런싱하여 각 인스턴스에 분산합니다.

FastAPI 서버 인스턴스 실행

여러 FastAPI 인스턴스를 실행하려면 각 인스턴스를 별도의 프로세스로 실행하면 됩니다. 아래와 같이
`uvicorn`을 이용해 각각의 포트에서 FastAPI 인스턴스를 실행합니다:


uvicorn main:app --host 127.0.0.1 --port 8000 &
uvicorn main:app --host 127.0.0.1 --port 8001 &
uvicorn main:app --host 127.0.0.1 --port 8002 &
            

이제 Nginx가 80번 포트에서 로드 밸런싱을 수행하고, FastAPI 인스턴스는 각각 8000, 8001, 8002 포트에서 실행되고 있습니다.

테스트 및 성능 최적화

캐싱 및 로드 밸런싱 구현 후, 실제 트래픽을 테스트하여 성능을 측정하는 것이 중요합니다.
로드 테스트 도구인 Apache Benchmark 또는 Locust를 사용하여 성능을 측정하고
최적화를 진행할 수 있습니다.

Apache Benchmark 사용 예제

Apache Benchmark는 간단한 명령어로 웹 서버의 성능을 테스트할 수 있는 도구입니다. 다음 명령어로 성능을 테스트할 수 있습니다:

ab -n 1000 -c 10 http://localhost/

이 명령어는 1000개의 요청을 동시에 10개씩 보내는 테스트를 수행합니다.
테스트 결과를 분석하면 캐싱 및 로드 밸런싱이 성능에 미치는 영향을 평가할 수 있습니다.

결론

FastAPI는 뛰어난 성능을 제공하지만, 실제 운영 환경에서는 캐싱과 로드 밸런싱과 같은 추가적인 성능 최적화 노력이 필요합니다.
Redis를 활용한 캐싱은 데이터베이스 부하를 줄이고 응답 속도를 높이는 데 큰 도움이 됩니다.
또한, Nginx를 통한 로드 밸런싱은 웹 애플리케이션의 안정성과 속도를 향상시켜 줍니다.
이 두 가지 기술을 활용하여 FastAPI 서버의 성능을 최적화할 수 있으며, 여러분의 서비스가 더 많은 트래픽을 원활히 처리할 수 있도록 도와줄 것입니다.