[트러블 슈팅] Redis too many connection - 100-hours-a-week/5-yeosa-wiki GitHub Wiki

1. 개요

  • 멀티 프로세스 + 레디스 테스트를 vm 환경에서 했을때, redis too many connection 에러가 발생했음.

    image

  • 이에 원인을 분석하여 문제를 해결하고자 함.

2. 원인 분석

a. 가설: FastAPI 서버에서 레디스 커넥션 풀을 이용하지 않고 있을 것이다. - 거짓

가. Redis connection pool 생성

def init_redis() -> Redis:
    global _redis
    pool = ConnectionPool(
        host=REDIS_HOST,
        port=REDIS_PORT,
        db=REDIS_DB,
        max_connections=20,
        decode_responses=True,
    )
    _redis = Redis(connection_pool=pool)
    return _redis

def get_redis() -> Redis:
    if _redis is None:
        raise RuntimeError("Redis가 초기화되지 않았습니다.")
    return _redis

나. 워커 프로세스 실행 시, Redis connection pool 초기화

app.state.redis = init_redis()

다. 캐시를 이용해야 하는 부분에서 이용

async def get_cached_embedding(key: str) -> Any | None:
    redis = get_redis()

b. 문제 식별: max_connections 크기가 작음

async def get_cached_embeddings_parallel(keys: list[str]) -> tuple[list[Any | None], list[str]]:
    """
    비동기로 여러 키를 Redis에서 조회합니다. 실패한 키도 기록합니다.
    """
    t0 = time.perf_counter()

    results = await asyncio.gather(
        *(get_cached_embedding(key) for key in keys),
        return_exceptions=True
    )
  • 워커에서 캐시 조회가 필요한 경우
    • get_cached_embeddings_parallel 메서드에서 get_cached_embedding를 사진 장수(임베딩 수)만큼 호출
  • 30장짜리 요청에서 커넥션 30개를 필요로 함
  • Redis connection pool에서 max_connection 20으로 설정함
  • 이로 인해 Too many connection 에러 발생

3. 해결

a. 해결 방안: 워커 프로세스 당 커넥션풀 크기 100으로 증가

image 1

  • Redis 설정 확인 결과, 위와 같이 10000개의 연결 허용
  • 워커 프로세스 당 100의 연결을 허용함
  • 그 결과, 에러 발생하지 않음

b. 추후 고려: 워커 프로세스 당 커넥션 풀 크기 고민

  • gunicorn에서 권장하는 워커 프로세스 개수는 vCPU 개수*2 + 1
  • 만약 4vCPU 서버에서 8개 워커 프로세스 생성하면 800개의 연결 생성
  • 많은 연결을 생성하는 것이 Redis 서버에 오버헤드가 되지 않는지 고려 필요.