어읽로꾸거
[Python] Celery Execution Pools 셀러리 풀에 관하여 본문
어떤 외국 글 번역함
셀러리는 작업 큐입니다. 이 셀러리에 풀이라는 옵션이 있는 이게 뭘까
셀러리 워커
셀러리 워커는 작업을 하지 않는다. 워커는 자식 프로세스(혹은 스레드)들을 호출해서 실제 작업을 실행한다. 이 자식들은 Execution Pool 이라고 한다. 이 자식 프로세스들의 개수가 셀러리가 동시에 처리하는 프로세스들의 수다. 더 많을수록 더 많이 동시에 작업함
이걸 정하는게 사실 엄청 복잡함. 얼마나 많이 실행할지에 대해서는 너가 프로세스를 쓰느냐 스레드를 쓰느냐에 따라서 달림. 그리고 프로세스를 쓸지 스레드를 쓸지는 니 작업이 뭐할지에 따라서 달림
--pool (-P) 옵션
너는 --pool 옵션을 통해 프로세스와 스레드 중에서 고를수 있다.
아래처럼 gevent를 쓰면, 100개의 그린 스레드를 생성한다 (pip에서 gevent설치해줘야함)
(역자: 윈도우에선 풀옵션 지정 안하면 안돌아감 gevnet는 잘돌아가긴해 그냥 도커로 리눅스 쓰자)
# start celery worker with the gevent pool
~$ celery worker --app=worker.app --pool=gevent --concurrency=100
그린 스레드가 뭘까? 이제 알아보자. 셀러리는 이런 풀 옵션들을 제공함
- prefork
- solo
- eventlet
- gevent
옵션 안정해놓으면 셀러리가 기본으로 prefork씀
1. Prefork
prefork는 파이썬의 멀티프로세싱 패키지에 기반한다.
이것은 파이썬의 GIL(https://docs.python.org/dev/glossary.html#term-global-interpreter-lock)을 우회하고 멀티프로세스를 신나게 즐기도록 한다.
너는 CPU범위 내의 작업을 하고싶으면 이걸 쓰면 된다. CPU범위 내라는건 대부분의 시간을 CPU자원을 쓰는데 쓰는것을 말함. CPU가 빠르면 작업도 빨리끝나겠지이
이용 가능한 코어의 개수는 프로세스들의 동시작업 개수를 제한한다. CPU가 가능한 한 병렬로 돌아감. 그래서 셀러리 기본 concurrency 옵션이 기본적으로 CPU코어 개수만큼 지정됨.(따로 설정 안해주면)
CPU가 가능한만큼 동시에 돌아가는 prepork를 써보자
2. Solo
솔로 얘는 좀 특별한애임.
엄격히 말하며는 얘는 스레드나 프로세스 기반이 아님.
더 엄격히말하면 예는 pool이 아니다 왜냐햐면 혼자니까.
그리고 더더 엄격하기 말하면 얘는 워커가 직접 일 안한다는 사실까지도 반박해버림(워커가 자식안만들고 직접 일한다는 뜻)
얘는 워커에서 돌아간다. 이거는 뭐 오버헤드 이런게 없어서 빠르다. 하지만 일 진행중에 다른일이 또 큐에 들어오면 실행되는동안 좀 기다려야겠지. 대신 한번에 한개의 일만 함 순서대로
3. Eventlet & Gevent
자 너가 외부 REST API에 수천개의 http요청을 날린다고 해보자. 대부분의 시간은 CPU를 안쓰면서 그냥 기다림. 이경우는 CPU에 병목현상이 아님. I/O에 대해 병목현상이 일어남 I/O가 끝나야 일이 끝남.
너가 1개의 자식 스레드로 돌리면 한번에 1개만 처리할수있음 근데 수천개하려면 오래걸림 그래서 더 많은 프로세스를 생성함 그런데 어느순간부터 프로세스를 더 생성하면 성능에 안좋아지는 수량이 있음. 프로세스 관리하는 오버헤드가 더 커져서 그럼
이런경우 스레드를 늘리는게 더 효율적임. 셀러리는 2개의 스레드 기반 셀러리 풀을 제공함 : eventlet / gevent
실행 풀이 워커랑 같은 프로세스에 있음, 정확히는 두개 다 greenlet을 이용하고 스레드를 이용하지 않음.
Greenlets - 그린 스레드라고 불림, 이것은 스레드를 주지만 스레드를 안씀. 이것은 커널에서 관리되는게 아니라 어플리케이션에서 관리됨. 스케줄러없이 특정시점에 서로 자원을 낭비함.
이것은 greenlet이 엄청난 숫자의 non-blocking 일을 할때 효과가 좋음. 너의 앱은 더 효율적으로 관리할 수 있음. 더 많은 숫자의 이런 일을 이렇게 관리하는 것은 운영체제가 스케줄링하는거보다 더 확장가능하다. gevent나 eventlet을 이용하면 램을 늘리지 않아도 성능이 늘어난다.
Concurrency 옵션
최고의 옵션을 고르기 전에, 너는 CPU위주 일인지 I/O위주 일인지를 먼저 봐야한다. CPU중심 일인 경우는 Prefork를 쓰는게 낫다. I/O일의 경우는 gevnet/eventlet을 쓰는게 낫다.
concurrency는 기본적으로 CPU개수에 맞게 설정된다. 이것 prefork에 맞는 설정이긴 하다. 그렇긴 한데 다른 많은 프로세스가 컴터에서 돌아가고 있으면 적당히 조정하는게 맞다.
기본 설정으로 gevent/eventlet을 쓰는건 바보같은 짓이다. 이거는 너의 CPU코어랑은 상관이 없으니 적당히 많이 쓰면 된다 한 500개정도
솔로풀의 경우엔 이거 옵션을 줄수있기는 한데 의미가 없음.
그래서 결론적으로 항상 concurrency를 명시하는게 좋은거같음
결론
셀러리는 2개의 컨셉을 지원한다: Prefork / Greenlets.
Prefork는 멀티프로세싱에 기반을 두고 CPU기반의 일할때(풀은 CPU코어에 맞게), Greenlets는 I/O기반의 일할때 써라(풀 몇백개 천개 이렇게 만들어라)
원문
https://www.distributedpython.com/2018/10/26/celery-execution-pool/
'정리' 카테고리의 다른 글
[수학] 2의 보수, 1의 보수 (+ 왜 필요한지 이유) (0) | 2022.09.04 |
---|---|
[Python] Fast Api 에서 Eureka 연결하기 (0) | 2022.08.27 |
[Javascript] 알아야 할 7가지 자료형 (0) | 2020.11.09 |
Visual Studio Code 터미널이 새창으로 열릴때 해결법 (0) | 2020.10.15 |
[Python] collections.deque 정리 (0) | 2019.09.28 |