택시짱의 개발 노트

25장. 비동기 태스크 큐 본문

Django(장고)

25장. 비동기 태스크 큐

택시짱 2021. 12. 9. 14:00

비동기 태스크 큐(asynchronous task queue)란 태스크가 실행되는 시점이 태스크가 생성되는 시점과 다르고 태스크의 생성 순서와도 연관 없이 실행되는 작업을 의미한다.

  1. 브로커(broker)
    • 태스크들이 보관되어 있는 장소. 데이터를 지속적으로 보관할 수 있는 도구라면 무엇이든지 이용할 수 있으나 장고에서는 RabbitMQ와 Redis가 가장 일반적으로 쓰인다.
  2. 프로듀서(producer)
    • 나중에 실행될 태스크를 큐에 넣는 코드. 장고 프로젝트를 구성하는 애플리케이션 코드다.
  3. 워커(wocker)
    • 태스크를 브로커에서 가져와 실행하는 코드. 일반적으로 하나 이상의 워커가 있다.

25.1 태스크 큐가 정말로 필요한가?

  • 상황에 따라 다르다. 태스크 큐를 도입하면 구조가 복잡해지긴 하지만 사용자 경험(user experience) 측면에서 봤을 때 매우 큰 도움이 된다. 특별한 코드에서 병목 현상이 나타날 경우 더 많은 CPU가 가능할 때 까지 해당 코드 실행을 잠시 미뤄 둘 수 있다.

태스크 큐가 정말로 필요한지 가늠해 볼 수 있는 규칙은 다음과 같다.

  1. 어떤 작업을 처리하는데 시간이 걸린다: 태스크 큐를 이용
  2. 사용자에게 결과를 바로 제공 해야한다: 태스크 큐를 이용하지 말아야 한다.
태스크 큐를 이용할 것인가? 작업 내용
이용한다 단체 이메일 보내기
이용한다 파일 수정 작업(이미지 포함)
이용한다 3rd party로 부터 다량의 데이터 가져오기
이용한다 테이블에 많은 양의 레코드를 추가하거나 업데이트 하기
이용하지 않는다 사용자 프로필 업데이트
이용하지 않는다 블로그나 CMS 엔트리 추가
이용한다 긴 시간을 요구하는 연산
이용한다 웹훅(webhook)을 보내거나 받기

사이트 트래픽에 따른 예외가 있기 때문에 모든 케이스가 위의 상황을 따라갈 수는 없다.

  1. 트래픽이 작거나 중간 정도인 사이트의 경우, 이러한 여러 작업 내용에 상관 없이 태스크 큐를 이용할 필요가 없다.
  2. 트래픽이 많은 사이트의 경우 모든 작업 내용에 대해 태스크 큐가 필요하다.

25.2 태스크 큐 소프트웨어 선택하기

소프트웨어 장점 단점
celery 사실상 장고의 표준으로 저장 형식이 다양하고 유연하며 기능이 풍부하고 대용량에 적합 세팅 절차가 까다롭고 트래픽이 적은 사이트의 경우 오히려 낭비적인 측면이 발생
redis queue 레디스를 기반으로 한다. 유연하고 셀러리에 비해 적은 메모리를 이용한다. 샐러리에 비해 기능이 적다. 세팅의 어려움은 중간 정도에 해당한다. 오직 레디스만 사용 가능
django-background-tasks 셋업 절차가 매우 쉽다. 이용이 간편. 작은 크기나 배치 작업에 적합. 장고 ORM을 백엔드로 이용???? 장고 ORM을 백엔드로 이용함으로써 중간 이상의 볼륨을 처리하는데 문제가 된다.
  • 용량이 작은 프로젝트부터 용량이 큰 프로젝트까지 대부분 레디스 큐를 추천 한다.
  • 태스크 관리가 복잡한 대용량 프로젝트에는 샐러리를 추천
  • 주기적이 배치 작업을 위한 소규모 프로젝트에는 django-background-tasks를 추천한다.

25.3 태스크 큐에 대한 실전 방법론

25.3.1 태스크를 뷰처럼 다루자

  • 코드상에서 메서드와 함수들을 다른 곳에서 호출함으로써 뷰를 가능한 작게 구성하기를 지속적으로 권장. 이와 같은 방법론을 똑같이 태스크에 적용
  • 태스크 큐는 사용자에게 노출되는 코드가 아니기 때문에 태스크 함수의 코드가 길어지고 복잡해지기도 한다. 이를 피하기 위해 태스크 코드를 함수 안으로 밀어 넣고 함수를 헬퍼 모듈에 위치시킨 후 해당 함수를 태스크 함수로부터 호출하기를 추천 한다.
  • 태스크 함수를 좀 더 쉽게 테스트할 수 있는 보통의 함수로 만들어 호출하면 코드 자체에 대한 디버깅이 쉬워진다

25.3.2 태스크 또한 리소스를 이용한다.

  • 리소스가 많이 필요한 코드를 태스크로 실행한다고 하더라고 코드는 가능한 단순 명료해야 하며 리소스를 낭비하지 않는 쪽으로 작성해야 한다.

25.3.3 JSON화 가능한 값들만 태스크 함수에 전달해라

  • 뷰와 같은 탵스크 함수의 인자는 JSON화 가능한 값만으로 제한하기를 바란다. 정수, 부동 소수점, 문자열, 리스트, 튜플, 딕셔너리 타입만 허용할 수 있다는 이야기. 복잡하게 얽힌 객체를 인자로는 이용하지 말아야 한다.
  1. ORM 인스턴스와 같은 영속적 데이터 객체를 함수의 인자로 이용하는 것은 경합 상황을 유발한다.
  2. 복잡한 형태의 객체를 함수의 인자로 태스크 큐에 넘겨주는 경우 시간과 메모리가 더 많이 든다.
  3. 복잡한 형태의 객체보다는 JSON화 된 값들을 디버깅하기가 더 쉽다.
  4. 사용 중인 태스크 큐에 따라 JSON화 된 형식만 허용되는 경우도 있다.

25.3.4 태스크와 워커를 모니터링하는 방법을 익혀 두라

25.3.5 로깅!

  • 에러가 일어나기 쉬운 태스크의 경우 각 탵스크 함수 내에 로그를 남기는 방법을 추천 한다.

25.3.6 백로그 모니터링하기

25.3.7 죽은 태스크를 주기적으로 지우기

25.3.8 불필요한 데이터 무시하기

25.3.9 큐의 에러 핸들링 이용하기

  • 네트워크나 서드 파티 API의 문제 또는 예상치 못한 여러 이유 때문에 태스크가 실패하는 경우도 있다.
  1. 태스크에 대한 최대 재시도 횟수 (Max retries for a task)
  2. 재시도 전 지연 시간 (Retry delays)

25.3.10 태스크 큐 소프트웨어의 기능 익히기

요약

  • 비즈니스 로직을 최소화하여 뷰처럼 큐를 관리하기 추천
반응형
Comments