๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
  • ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ๐ŸŒฎ ๐Ÿ’ฌ
๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป/network

[Celery] ์ ์ ˆํ•œ concurrency ๊ฐ’ ์„ค์ •ํ•˜๊ธฐ

by ๋ฐ”์ฟ„๋ฆฌ 2025. 2. 19.

๊ฐœ์š”

Celery์—์„œ concurrency ๊ฐ’์€ ํ•œ ๋ฒˆ์— ๋ช‡๊ฐœ์˜ ์ž‘์—…์„ ๋™์‹œ์— ์‹คํ–‰ํ• ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ์ค‘์š”ํ•œ ์„ค์ •์ด๋‹ค.

์ ์ ˆํ•œ concurrency ๊ฐ’์€ ์–ด๋–ป๊ฒŒ ์„ค์ •ํ• ๊นŒ .. (ํ•˜๋“œ์›จ์–ด, ์›Œํฌ๋กœ๋“œ, ์ž‘์—… ํŠน์„ฑ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๋‹ค!)

ํ™•์ธ

concurrency

  • Celery๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ Prefork (multiprocessing) ๋ชจ๋“œ๋ฅผ ์‚ฌ์šฉ
  • concurrency๋Š” ๊ฐ worker๊ฐ€ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์—… ๊ฐœ์ˆ˜๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
  • worker๋Š” ์‹ค์ œ๋กœ Task๋ฅผ ์‹คํ–‰ํ•˜๋Š” ํ”„๋กœ์„ธ์Šค(์ž‘์—… ๋‹จ์œ„)๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

1๏ธโƒฃ CPU ์ฝ”์–ด ์ˆ˜

Celery๊ฐ€ CPU ์—ฐ์‚ฐ์„ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ์ž‘์—…(์˜ˆ: ๋จธ์‹ ๋Ÿฌ๋‹, ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ๋“ฑ)์„ ์‹คํ–‰ํ•œ๋‹ค๋ฉด, CPU ์ฝ”์–ด ์ˆ˜ ๊ธฐ์ค€์œผ๋กœ ์„ค์ •

 

CPU ์ฝ”์–ด ๊ฐœ์ˆ˜ ์ ์ ˆํ•œ concurrency ๊ฐ’
2 ์ฝ”์–ด 2~4
4 ์ฝ”์–ด 4~8
8 ์ฝ”์–ด 8~16

โœ” ๋ฉ€ํ‹ฐ์ฝ”์–ด๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก CPU ์ฝ”์–ด ๊ฐœ์ˆ˜๋งŒํผ concurrency ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ 

 

2๏ธโƒฃ ํƒœ์Šคํฌ ์œ ํ˜• (CPU-bound vs I/O-bound)

์ž‘์—… ์œ ํ˜• ์„ค๋ช… ์ ์ ˆํ•œ concurrency ๊ฐ’
CPU-bound ๋จธ์‹ ๋Ÿฌ๋‹, ์˜์ƒ์ฒ˜๋ฆฌ, ์ˆ˜ํ•™ ์—ฐ์‚ฐ ๋“ฑ CPU ์ฝ”์–ด ์ˆ˜๋งŒํผ ์„ค์ • (os.cpu_count())
I/O-bound ํฌ๋กค๋ง, DB ์กฐํšŒ, ๋„คํŠธ์›Œํฌ ์š”์ฒญ ๋“ฑ CPU ์ฝ”์–ด ์ˆ˜ * 2~4

 

โœ” CPU ์—ฐ์‚ฐ์ด ๋งŽ์€ ๊ฒฝ์šฐ (CPU-bound)

celery -A celery_tasks.celery_app worker --concurrency=$(nproc)

 

โœ” ํฌ๋กค๋ง, DB ์—ฐ์‚ฐ์ด ๋งŽ์€ ๊ฒฝ์šฐ (I/O-bound)

celery -A celery_tasks.celery_app worker --concurrency=$(( $(nproc) * 4 ))

 

 

โœ” I/O ์ž‘์—…์ด ๋งŽ์œผ๋ฉด CPU ์ฝ”์–ด๋ณด๋‹ค ๋” ๋งŽ์€ worker๋ฅผ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์ด ์œ ๋ฆฌํ•จ

 

3๏ธโƒฃ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๊ณ ๋ ค

Worker ํ”„๋กœ์„ธ์Šค๋งˆ๋‹ค ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ฐจ์ง€ํ•˜๋ฏ€๋กœ, ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋ถ€์กฑํ•œ ๊ฒฝ์šฐ concurrency ๊ฐ’์„ ๋„ˆ๋ฌด ๋†’์ด๋ฉด Out of memory (OOM) ๋ฐœ์ƒ ๊ฐ€๋Šฅ

 
์„œ๋ฒ„ RAM ์ ์ ˆํ•œ concurrency ๊ฐ’
2GB 2~4
4GB 4~8
8GB ์ด์ƒ 8~16

โœ” ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ 2GB๋ฐ–์— ์—†๋‹ค๋ฉด, concurrency=2~4 ์ •๋„๊ฐ€ ์ ์ ˆํ•˜๋‹ค.

 

4๏ธโƒฃ Celery ์‹คํ–‰ ๋ชจ๋“œ (Prefork vs Threaded)

Celery๋Š” --pool=prefork(๊ธฐ๋ณธ๊ฐ’) ๋˜๋Š” --pool=threads ๋ชจ๋“œ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

โœ” CPU ์‚ฌ์šฉ์ด ๋งŽ๋‹ค๋ฉด prefork (๊ธฐ๋ณธ)

celery -A celery_tasks.celery_app worker --loglevel=info --concurrency=4 --pool=prefork

โ†’ ๊ฐ ์ž‘์—…์ด ๋ณ„๋„์˜ ํ”„๋กœ์„ธ์Šค์—์„œ ์‹คํ–‰๋˜๋ฏ€๋กœ CPU ์‚ฌ์šฉ์ด ๋งŽ์„ ๋•Œ ์œ ๋ฆฌํ•จ

 

โœ” I/O ์ž‘์—…์ด ๋งŽ๋‹ค๋ฉด threads

celery -A celery_tasks.celery_app worker --loglevel=info --concurrency=10 --pool=threads

โ†’ ์›น ํฌ๋กค๋ง, DB ์กฐํšŒ ๊ฐ™์€ I/O ์ž‘์—…์ด ๋งŽ๋‹ค๋ฉด threads ๋ชจ๋“œ๊ฐ€ ๋” ํšจ์œจ์ 

 

์ •๋ฆฌ

Celery ์ž‘์—…์ด ํฌ๋กค๋ง ์ค‘์‹ฌ์ด๋ผ๋ฉด, I/O-bound์— ํ•ด๋‹นํ•˜๋ฏ€๋กœ concurrency = (CPU ์ฝ”์–ด ์ˆ˜ * 4) ์œผ๋กœ ํ•˜๋Š”๊ฒŒ ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

celery -A celery_tasks.celery_app worker --concurrency=$(( $(nproc) * 4 )) --pool=threads