ML/MLOps Engineer
2๋…„ ๋™์•ˆ Kubernetes์—์„œ Airflow๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๋ฐฐ์šด ๊ฒƒ (๋ฒˆ์—ญ)

medium์—์„œ What we learned after running Airflow on Kubernetes for 2 year ์„ ์ฝ์œผ๋ฉฐ ์š”์•ฝํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.
 
์ด ๊ฒŒ์‹œ๊ธ€์—์„œ๋Š” Apache Airflow๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ํ”Œ๋žซํผ์„ ๊ตฌ์ถ•ํ•˜๋Š” ๊ณผ์ •์—์„œ ๊ฒฝํ—˜ํ•œ ๋‚ด์šฉ๋“ค์„ ๊ณต์œ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ €์ž๋Š” Airflow๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜, ์‚ฌ๊ธฐ ํƒ์ง€, ๋ฐ์ดํ„ฐ ๊ณผํ•™ ์ด๋‹ˆ์…”ํ‹ฐ๋ธŒ, ๋‚ด๋ถ€ ์ž‘์—… ๋“ฑ์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ 300๊ฐœ ์ด์ƒ์˜ DAG๊ฐ€ production์— ์กด์žฌํ•˜๋ฉฐ, ํ•˜๋ฃจ์— ํ‰๊ท  5,000๊ฐœ ์ด์ƒ์˜ ์ž‘์—…์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ทœ๋ชจ์˜ ์ž‘์—…์—๋„ 8๊ฐœ์›”๊ฐ„ ์‹คํŒจ ์—†์ด ์ง„ํ–‰๋˜์—ˆ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. 
 
production level์—์„œ Airflow๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ ์–ป๊ฒŒ ๋œ ์•„์ด๋””์–ด๋“ค์„ ๊ณต์œ ํ•˜๊ณ  ์žˆ๊ณ  ์š”์•ฝํ•˜์ž๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค. 

1. Executor ์„ ํƒ: ์ฒ˜์Œ์—๋Š” Kubernetes Executor๋ฅผ ์„ ํƒํ–ˆ์ง€๋งŒ ์ž‘์€ ์ž‘์—…์— ๋Œ€ํ•œ ์˜ค๋ฒ„ํ—ค๋“œ์™€ Pod ๊ฐ•์ œ ์ดํƒˆ๋กœ ์ธํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ดํ›„ Celery Executor๋กœ ์ „ํ™˜ํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œ์ผฐ์Šต๋‹ˆ๋‹ค.

2. DAG ๋™์  ์ƒ์„ฑ๊ณผ ๋””์ปคํ”Œ๋ง: ์—ฌ๋Ÿฌ ํŒ€์ด ์ž์ฒด DAG๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์ด๋ฅผ ํ†ตํ•ฉํ•˜๊ธฐ ์œ„ํ•ด DAG์˜ ๋ฉ€ํ‹ฐ-์ €์žฅ์†Œ ์ ‘๊ทผ ๋ฐฉ์‹์„ ๋„์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค. DAG๋Š” ๊ฐœ๋ณ„ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์—์„œ ๊ฐœ๋ฐœ๋˜๋ฉฐ, CI/CD ๊ฐ€์ด๋“œ๋ผ์ธ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

3. ์„ธ๋ถ€ ์„ค์ • ์กฐ์ •: CeleryExecutor๋กœ ์ „ํ™˜ํ•œ ํ›„ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜์™€ ๊ฐ™์€ ์ƒˆ๋กœ์šด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด worker_max_tasks_per_child ๋ฐ worker_max_memory_per_child์™€ ๊ฐ™์€ Celery ๊ตฌ์„ฑ์„ ์กฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

4. ์•Œ๋ฆผ, ๊ฒฝ๊ณ  ๋ฐ ๊ด€์ธก์„ฑ: Airflow์˜ ์•Œ๋ฆผ ๋ฐ ๊ฒฝ๊ณ  ์‹œ์Šคํ…œ์„ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด Slack ๋ฉ”์‹œ์ง€ ๋ฐ Prometheus ๊ทœ์น™์„ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ์—์–ดํ”Œ๋กœ์šฐ ๋ฐ ์ธํ”„๋ผ ๋ชจ๋‹ˆํ„ฐ๋ง์„ ์œ„ํ•ด ๋ฉ”ํŠธ๋ฆญ ๋ฐ ๋กœ๊ทธ๋ฅผ ์ˆ˜์ง‘ํ•˜๊ณ  ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

5. ๋น„์šฉ ์ตœ์ ํ™”: ์ž‘์—…์˜ ๋™์‹œ์„ฑ ๋ฐ ๋ฆฌ์†Œ์Šค ๊ตฌ์„ฑ์„ ์กฐ์ •ํ•˜์—ฌ ๋น„์šฉ์„ ์ตœ์ ํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค.

 
๊ฐ๊ฐ์˜ ๋‹จ๊ณ„๋ณ„๋กœ ์‚ดํŽด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

1. Executor ์„ ํƒ

์ฒ˜์Œ์— ์ €์ž๋Š” Kubernetes ํ™˜๊ฒฝ์—์„œ ๊ตฌ์ถ•ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— Kubernetes Executor ๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์šด์˜๋˜๋Š” task ๋“ค์€ ๊ฒฝ๋Ÿ‰์˜ DBT ๋ณ€ํ™˜ ์ž‘์—…์ด๊ณ  ์ ์€ ์ˆ˜์˜ ๋ชจ๋ธ๋งŒ์ด ๊ธด ์‹œ๊ฐ„(+/- 1 ์‹œ๊ฐ„)์„ ์†Œ์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋“ค์€ ๋‘๊ฐ€์ง€ ๋ฌธ์ œ์— ์ง๋ฉดํ–ˆ๋Š”๋ฐ์š”.
- Kubernetes Excutor๋ฅผ ์‚ฌ์šฉ์‹œ ์ž‘์—… ์‹œ์ž‘ ์˜ค๋ฒ„ํ—ค๋“œ ์กด์žฌ. pod ์‹œ์ž‘ ๋Œ€๊ธฐ ์‹œ๊ฐ„์ด ์ž‘์—… ์ž์ฒด ์‹œ๊ฐ„๋ณด๋‹ค ๊ธธ ๋•Œ๊ฐ€ ์žˆ์Œ.
- pod ์ œ๊ฑฐ๋กœ ์ผ๋ถ€ ์ž‘์—…(ํŠนํžˆ ์žฅ๊ธฐ ์‹คํ–‰ ์ž‘์—…)์ด ์˜ˆ๊ธฐ์น˜ ์•Š๊ฒŒ ์‹คํŒจํ•จ.
 

์‹ ์†ํ•˜๊ฒŒ ์Šค์ผ€์ผ์ด ์กฐ์ ˆ๋˜๋Š” k8s์˜ ํŠน์„ฑ์œผ๋กœ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ

 
 
๊ฒฐ๊ตญ ์ €์ž๋Š” Celery Executor๋กœ ๋Œ์•„๊ฐ€๋Š” ๊ฒฐ์ •์„ ํ–ˆ์Šต๋‹ˆ๋‹ค. worker nodes๋ฅผ ๊ณ ์ •ํ•˜์—ฌ ์ž‘๊ณ  ๊ทœ๋ชจ์˜ ์ž‘์—…์ด ๋งŽ์€ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ์ ํ•ฉํ•˜๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. 
 

2. ๋ถ„๋ฆฌ ๋ฐ ๋™์  DAG ์ƒ์„ฑ

๋ถ„์‚ฐ๋œ DAG ์ €์žฅ์†Œ

๋ชจ๋“  DAG๋Š” DAG๋ฅผ ์†Œ์œ ํ•˜๋Š” ํŒ€์— ๋”ฐ๋ผ ํŠน์ • ๊ฒฝ๋กœ์—์„œ ๋™๊ธฐํ™” ํ”„๋กœ์„ธ์Šค๋ฅผ ํ†ตํ•ด ๋ฒ„ํ‚ท์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

->  CI/CD๊ฐ€ ๋งค์šฐ ์ค‘์š”ํ•˜๋ฉฐ ๊ฐ DAG ์ด๋ฆ„์€ DAG ID๊ฐ€ ์ถฉ๋Œํ•˜์ง€ ์•Š๋„๋ก ๋ฏธ๋ฆฌ ์ง€์ •๋œ ์ ‘๋‘์–ด๋กœ ์‹œ์ž‘
-> ์ •์  ๊ฒ€์‚ฌ(์˜ฌ๋ฐ”๋ฅธ ์†Œ์œ ์ž๋ฅผ ํ• ๋‹นํ•˜๊ณ  ํƒœ๊ทธ์˜ ์กด์žฌ์—ฌ๋ถ€ ํ™•์ธ)
-> ๋ชจ๋“  DAG๋Š” ์ปค๋ฐ‹๋˜๊ธฐ ์ „ ์ตœ์†Œํ•œ์˜ ์ฒดํฌ๋ฆฌ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.


DAG๋ฅผ ์—์–ดํ”Œ๋กœ์šฐ์— ๋™๊ธฐํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•

๋ฒ„ํ‚ท์˜ ๋‚ด์šฉ์„ ์Šค์ผ€์ค„๋Ÿฌ, ์›Œ์ปค ๋“ฑ์˜ Pod์˜ ๋กœ์ปฌ ํŒŒ์ผ ์‹œ์Šคํ…œ์— ๋™๊ธฐํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์ €์ž๋Š” Objinsync ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์›๊ฒฉ ๊ฐ์ฒด ์ €์žฅ์†Œ๋ฅผ ๋กœ์ปฌ ํŒŒ์ผ ์‹œ์Šคํ…œ์œผ๋กœ ์ ์ง„์ ์œผ๋กœ ๋™๊ธฐํ™”ํ•˜๋Š” ๊ฐ€๋ฒผ์šด ๋ฐ๋ชฌ์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
 
๋ฉ”์ธ ์Šค์ผ€์ค„๋Ÿฌ๋‚˜ ์›Œ์ปค ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹œ์ž‘๋˜๊ธฐ ์ „์— objinsync๋ฅผ init ์ปจํ…Œ์ด๋„ˆ๋กœ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.(ํŠนํžˆ Celery ์›Œ์ปค์˜ ๊ฒฝ์šฐ์— ์ค‘์š”ํ•˜๊ฒŒ ์ž‘์šฉ)


๋™์ ์œผ๋กœ DAG ์ƒ์„ฑ ์‹œ ์ฃผ์˜์‚ฌํ•ญ

๋Œ€๊ทœ๋ชจ๋กœ DAG๋ฅผ ์ƒ์„ฑํ•˜๋ ค๋ฉด DAG ํ…œํ”Œ๋ฆฟํ™”์™€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์˜ ์ƒ์„ฑ์„ ํ™œ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋” ์ด์ƒ ๋ชจ๋“  DAG๋ฅผ ์ˆ˜๋™์œผ๋กœ ์ž‘์„ฑํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค ๐Ÿ˜‚

๋™์ ์œผ๋กœ DAG๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•์€ ๋‹จ์ผ ํŒŒ์ผ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. (๋™์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋ ค๋Š” ๊ฐ DAG์— ๋Œ€ํ•ด .py ํŒŒ์ผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.)
 
๋™์ ์œผ๋กœ ์ƒ์„ฑ๋œ ํŒŒ์ผ์„ DAG ๋ฒ„ํ‚ท์— ํ‘ธ์‹œํ•ฉ๋‹ˆ๋‹ค.
๋‹จ์ผํŒŒ์ผ / ๋‹ค์ค‘ํŒŒ์ผ์œผ๋กœ ๋™์ ์œผ๋กœ DAG ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”


3. ์„ค์ • ์„ธ๋ถ€ ์กฐ์ •

CeleryExecutor๋กœ ์ „ํ™˜ํ•˜์ž๋งˆ์ž ์ผ๋ถ€ Celery ์›Œ์ปค๊ฐ€ OOM(๋ฉ”๋ชจ๋ฆฌ ๋ถ€์กฑ) ๋ฌธ์ œ๋กœ ์ธํ•ด ๋‹ค์šด๋˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. 

Celery ์›Œ์ปค์˜ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐœ๊ฒฌ!


๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•˜๊ณ  ์ž‘์—…์˜ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•ด ๋‘ ๊ฐ€์ง€ ์ค‘์š”ํ•œ Celery ๊ตฌ์„ฑ์„ ์กฐ์ •ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค: `worker_max_tasks_per_child` ๋ฐ `worker_max_memory_per_child`.

`worker_max_tasks_per_child`: ์ฒซ ๋ฒˆ์งธ ๊ตฌ์„ฑ์€ ์›Œ์ปค ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ƒˆ ํ”„๋กœ์„ธ์Šค๋กœ ๊ต์ฒด๋˜๊ธฐ ์ „์— ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ๋Œ€ ์ž‘์—… ์ˆ˜๋ฅผ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค. ๋จผ์ € Celery ์›Œ์ปค์™€ ์›Œ์ปค ํ”„๋กœ์„ธ์Šค์˜ ์ฐจ์ด๋ฅผ ์ดํ•ดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ์›Œ์ปค ๋…ธ๋“œ๋Š” concurrency ์„ค์ •์— ์˜ํ•ด ์ œ์–ด๋˜๋Š” ์—ฌ๋Ÿฌ ์›Œ์ปค ํ”„๋กœ์„ธ์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, concurrency๋ฅผ 12๋กœ ์„ค์ •ํ•˜๊ณ  2๊ฐœ์˜ Celery ์›Œ์ปค๊ฐ€ ์žˆ๋‹ค๋ฉด 24๊ฐœ์˜ ์›Œ์ปค ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋™์ผํ•œ ์›Œ์ปค ํ”„๋กœ์„ธ์Šค ๋‚ด์—์„œ ์ž‘์—… ์‚ฌ์ด์˜ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ๋•Œ๋•Œ๋กœ ๋ฆฌ์‚ฌ์ดํดํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ด ๊ตฌ์„ฑ์ด ์„ค์ •๋˜์ง€ ์•Š์œผ๋ฉด ์›Œ์ปค ํ”„๋กœ์„ธ์Šค๋ฅผ ๋ฆฌ์‚ฌ์ดํดํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ๊ธฐ๋ณธ ์„ค์ •์ž…๋‹ˆ๋‹ค.

`worker_max_memory_per_child` ๋‘ ๋ฒˆ์งธ ๊ตฌ์„ฑ์€ ๋‹จ์ผ ์›Œ์ปค ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ƒˆ๋กœ์šด ํ”„๋กœ์„ธ์Šค๋กœ ๊ต์ฒด๋˜๊ธฐ ์ „์— ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ๋Œ€ ์ฃผ์š” ๋ฉ”๋ชจ๋ฆฌ ์–‘์„ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์‚ฌ์‹ค์ƒ ์ž‘์—…์˜ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’๋„ ์ œํ•œ์ด ์—†์œผ๋ฏ€๋กœ ํ•ญ์ƒ ์ด๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋‘ ๊ตฌ์„ฑ์„ ์กฐ์ •ํ•จ์œผ๋กœ์จ ์ตœ๋Œ€ ์ž‘์—… ์ˆ˜์— ๋„๋‹ฌํ•˜๊ฑฐ๋‚˜ ์ตœ๋Œ€ ์ฃผ์š” ๋ฉ”๋ชจ๋ฆฌ ์–‘์— ๋„๋‹ฌํ•œ ๊ฒฝ์šฐ ์›Œ์ปค ํ”„๋กœ์„ธ์Šค๋ฅผ ๋ฆฌ์‚ฌ์ดํดํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ตฌ์„ฑ์ด ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์€ prefork ํ’€์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ํ•ด๋‹น๋ฉ๋‹ˆ๋‹ค. ๊ณต์‹ ๋ฌธ์„œ์—์„œ ์ž์„ธํžˆ ์•Œ์•„๋ณด์‹ญ์‹œ์˜ค.

Airflow์—์„œ ์ด๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. Airflow์˜ config_templates ํด๋”์—์„œ ๊ธฐ๋ณธ Celery ๊ตฌ์„ฑ์„ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค
 

# config_templates/custom_celery.py

from airflow.config_templates.default_celery import DEFAULT_CELERY_CONFIG

CUSTOM_CELERY_CONFIG = DEFAULT_CELERY_CONFIG.copy()
CUSTOM_CELERY_CONFIG.update(
    {
        "worker_max_tasks_per_child": <int>,
        "worker_max_memory_per_child": <int>,
    }
)


๊ทธ๋Ÿฐ ๋‹ค์Œ `values.yaml`์—์„œ ์ด ์‚ฌ์šฉ์ž ์ง€์ • ๊ตฌ์„ฑ์„ ๊ฐ€๋ฆฌํ‚ค๋ฉด ๋ฉ๋‹ˆ๋‹ค.

airflow:
   config:
     celery:
       worker_concurrency: <int>
       celery_config_options: config_templates.custom_celery.CUSTOM_CELERY_CONFIG


์ด๋Ÿฌํ•œ ๊ตฌ์„ฑ์— ์‚ฌ์šฉํ•˜๋Š” ๊ฐ’์€ ์ž‘์—… ๋…ธ๋“œ ๊ตฌ์„ฑ, ๋ฉ”๋ชจ๋ฆฌ ์š”์ฒญ/์ œํ•œ ์–‘, concurrency ์ˆ˜์ค€ ๋ฐ ์ž‘์—…์˜ ๋ฉ”๋ชจ๋ฆฌ ์ง‘์ค‘๋„์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ฐœ๋ณ„ ์„ค์ •์— ๋งž๊ฒŒ ์กฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋…ธ๋“œ ๋กœํ…Œ์ด์…˜์— ๋Œ€๋น„ํ•˜๊ธฐ

๋…ธ๋“œ ๋กœํ…Œ์ด์…˜์œผ๋กœ Pod๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ Pod๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋˜์–ด ์‹คํŒจํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๊ฐœ๋ณ„์ ์ธ ์š”๊ตฌ ์‚ฌํ•ญ์— ๋”ฐ๋ผ Worker Termination Grace Period ๊ตฌ์„ฑ์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.
์ด ๊ตฌ์„ฑ์€ ๋ฆด๋ฆฌ์Šค ํ”„๋กœ์„ธ์Šค๋‚˜ ๋…ธ๋“œ ๋กœํ…Œ์ด์…˜์— ์˜ํ•ด ์ข…๋ฃŒ๋˜๊ธฐ ์ „์— celery worker๊ฐ€ ํ•ด๋‹น ์‹œ๊ฐ„ ๋™์•ˆ ๋Œ€๊ธฐํ•˜๋„๋ก ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ Airflow์˜ ์ฐจํŠธ values.yaml์—์„œ๋„ ์‰ฝ๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

airflow:
   workers:
      terminationGracePeriodSeconds: <int>

  
๊ถŒ์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๊ฐ€์žฅ ๊ธด ์‹คํ–‰ ์ž‘์—…์— ์†Œ์š”๋œ ์‹œ๊ฐ„์˜ 1.5๋ฐฐ๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ชจ๋“  ์ž‘์—…์ด ํ•ด๋‹น ๊ธฐ๊ฐ„ ๋‚ด์— ์™„๋ฃŒ๋  ์ˆ˜ ์žˆ๊ณ  ์›Œ์ปค๊ฐ€ ์›ํ™œํ•˜๊ฒŒ ์ข…๋ฃŒ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

4. ์•Œ๋ฆผ, ๊ฒฝ๊ณ  ๋ฐ ๊ด€์ธก์„ฑ

์กฐ์ง ๋‚ด ์•Œ๋ฆผ ํ†ตํ•ฉ

์—ฌ๋Ÿฌ ํŒ€์ด Airflow๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ™˜๊ฒฝ์—์„œ ์ž‘์—… ์ค‘์ธ ๊ฒฝ์šฐ, ์•Œ๋ฆผ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ํ†ตํ•ฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
Airflow 2.6๋ถ€ํ„ฐ๋Š” Notifiers๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์ „ ๊ตฌ์ถ•๋œ ์•Œ๋ฆผ์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค! (Slack, SQS, Jira ๋“ฑ)
BaseNotifier ํด๋ž˜์Šค๋ฅผ ์ด์šฉํ•˜๋ฉด ์‚ฌ์šฉ์ž ์ •์˜ Notifier๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

ํ•œ&amp;nbsp;๊ฐ€์ง€&amp;nbsp;์•Œ๋ฆผ,&amp;nbsp;์—ฌ๋Ÿฌ&amp;nbsp;๋Œ€์ƒ&amp;nbsp;๋ฐ&amp;nbsp;์‚ฌ์šฉ์ž&amp;nbsp;์ •์˜


์‚ฌ์šฉ์ž ์ง€์ • ์•Œ๋ฆผ๋„ ํ…œํ”Œ๋ฆฟํ™”๋˜์–ด ํŒ€์ด Slack์—์„œ ์ •๋ณด ๋ฉ”์‹œ์ง€๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ํ‘œ์ค€ ํ˜•์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ ‘๊ทผ ๋ฐฉ์‹์˜ ๋˜ ๋‹ค๋ฅธ ์žฅ์ ์€ ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐœ๋ณ„ ํŒ€์ด ๊ฐœ๋ณ„ ์•Œ๋ฆผ ๋Œ€์ƒ์˜ ๋น„๋ฐ€ ๊ด€๋ฆฌ์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์‹คํŒจ์— ๋Œ€ํ•œ ์ตœ์ดˆ์˜ ์•Œ๋ฆผ

๊ณ ๊ฐ€์šฉ์„ฑ์„ ๊ณ ๋ คํ•ด์„œ ๊ตฌํ˜„ํ•˜๋”๋ผ๋„ Airflow๋Š” ์—ฌ๋Ÿฌ ์ด์œ ๋กœ ์—ฌ์ „ํžˆ ์‹คํŒจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ธํ”„๋ผ ์ˆ˜์ค€์˜ ๊ด€์ธก์„ฑ, ๋ฉ”ํŠธ๋ฆญ ๋ฐ ๊ฒฝ๊ณ ๊ฐ€ ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

Kubernetes์—์„œ ์‹คํ–‰ ์ค‘์ผ ๋•Œ, ๊ด€์‹ฌ ์žˆ๋Š” ๊ฐ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ PrometheusRule์„ ์„ค์ •ํ•˜์—ฌ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์Šค์ผ€์ค„๋Ÿฌ ๋…ธ๋“œ์˜ ์ƒํƒœ, ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์›Œ์ปค ๋…ธ๋“œ์˜ ์ˆ˜ ๋˜๋Š” ์Šค์ผ€์ค„๋Ÿฌ ๋ฃจํ”„ ์‹œ๊ฐ„๊ณผ ๊ฐ™์€ ํŠน์ • Airflow ๋ฉ”ํŠธ๋ฆญ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ AlertManager๋ฅผ ์‹คํ–‰ํ•จ์œผ๋กœ์จ ์—ฌ๋Ÿฌ ๋Œ€์ƒ์— ๋Œ€ํ•œ ๊ฒฝ๊ณ ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(Slack, PagerDuty, Opsgenie ๋“ฑ).

ํ™˜๊ฒฝ์˜ ๊ด€์ธก์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ค๊ธฐ ์œ„ํ•ด Airflow ๋ฉ”ํŠธ๋ฆญ์„ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ Airflow๋Š” `StatsD`์™€ `OpenTelemetry`๋กœ ๋ฉ”ํŠธ๋ฆญ์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ํ›„์ž๊ฐ€ ์ „์ž๋ณด๋‹ค ์šฐ์„ ๋˜๋Š”๋ฐ, `OpenTelemetry`๋Š” ๋กœ๊ทธ ๋ฐ ํŠธ๋ ˆ์ด์Šค๋ฅผ ์ง€์›ํ•˜๋Š” ๋” ์™„๋ฒฝํ•œ ํ”„๋ ˆ์ž„์›Œํฌ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. 

๋˜ํ•œ, ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด Kubernetes์—์„œ OTEL Collector ๋ฐฐํฌ๋ฅผ ๊ด€๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(๊ณต์‹ helm ์ฐจํŠธ ์ฐธ๊ณ ). ๊ณต์‹ Airflow ์ฐจํŠธ๋Š” OTEL Collector๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Airflow&amp;nbsp;๋ชจ๋‹ˆํ„ฐ๋ง&amp;nbsp;์ฐจํŠธ&amp;nbsp;์˜ˆ์‹œ


ํ‘œ์ค€ ๋ฉ”ํŠธ๋ฆญ์„ ์‚ฌ์šฉํ•˜๋ฉด ์•Œ๋ฆผ์˜ ํ’ˆ์งˆ์„ ํ–ฅ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋Œ€๊ธฐ ์ค‘์ธ ์ž‘์—…์˜ ์ด ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋Œ€๊ธฐ์—ด์ด ํŠน์ • ์‹œ๊ฐ„ ๋™์•ˆ ๋„ˆ๋ฌด ๋งŽ์ด ์ฆ๊ฐ€ํ•  ๋•Œ ํŠธ๋ฆฌ๊ฑฐํ•  ๊ฒฝ๊ณ ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด SLA ์‹œ๊ฐ„๋ณด๋‹ค ๊ธด ๋Œ€๊ธฐ์—ด์€ ์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๋‹ค๋ฅธ ์œ ์šฉํ•œ ๋ฉ”ํŠธ๋ฆญ์—๋Š” DAG ๊ตฌ๋ฌธ ๋ถ„์„ ์‹œ๊ฐ„ ๋ฐ ์Šค์ผ€์ค„๋Ÿฌ ๋ฃจํ”„ ์‹œ๊ฐ„์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด Airflow์˜ ํ•ต์‹ฌ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ณ  ์ „์ฒด ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ๋Š๋ฆฌ๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฌธ์ œ๋ฅผ ๋น ๋ฅด๊ฒŒ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Airflow์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๊ด€๋ฆฌํ•˜๊ธฐ

๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ์„ฑ๊ณต์ ์ธ Airflow ๊ตฌํ˜„์˜ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์œผ๋กœ, ์„ฑ๋Šฅ์„ ์ €ํ•˜์‹œํ‚ค๊ฑฐ๋‚˜ Airflow๋ฅผ ์ค‘๋‹จ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„์—์„œ ์–ธ๊ธ‰ํ•œ Airflow ๋…ธ๋“œ ๋ฐ ์„ฑ๋Šฅ ๋ฉ”ํŠธ๋ฆญ์˜ ๋ชจ๋‹ˆํ„ฐ๋ง ์™ธ์—๋„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ƒํƒœ ๋ฉ”ํŠธ๋ฆญ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. PostgreSQL ๋˜๋Š” MySQL์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”์ง€์— ๋”ฐ๋ผ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์ง€๋งŒ(์ œ๋ฐœ SQLite๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค ๐Ÿ˜‚), ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๋ฉ”ํŠธ๋ฆญ์€ CPU ์‚ฌ์šฉ๋Ÿ‰, ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ €์žฅ์†Œ, ์—ฐ๊ฒฐ ์ˆ˜ ๋“ฑ์ž…๋‹ˆ๋‹ค.

๋˜ ๋‹ค๋ฅธ ์ข‹์€ ์‹ค์ฒœ ๋ฐฉ๋ฒ•์€ ์ฃผ๊ธฐ์ ์œผ๋กœ ์˜ค๋ž˜๋˜๊ณ  ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ •๋ฆฌํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด์—๋Š” ์ž‘์—…, `dag_run` , `task_instance`, `log`, `xcom, sla_miss`, `dags`, `task_reschedule`, `task_fail`๋“ฑ๊ณผ ๊ฐ™์€ ํ…Œ์ด๋ธ”์ด ํฌํ•จ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ชจ๋“  ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋Š” Airflow ๋‚ด์—์„œ ๊ณ„์†ํ•ด์„œ ์Œ“์ด๋ฉฐ, ์ž‘์—… ์ƒํƒœ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” ํ‰๊ท  ์ฟผ๋ฆฌ๊ฐ€ ๋” ๊ธธ์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Airflow๊ฐ€ ๋‹จ์ˆœํžˆ ๋กœ๋“œ๋˜๊ณ  ํƒ์ƒ‰ํ•˜๋Š” ๋ฐ ๋Š๋ฆฐ ๊ฒƒ์œผ๋กœ ๋Š๊ปด์ง„ ์ ์ด ์žˆ๋‹ค๋ฉด ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊ฐ€ ์Œ“์ด๋Š” ๊ฒƒ์ด ๊ทธ ์›์ธ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Airflow์—๋Š” ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ •๋ฆฌ๋ฅผ ์œ„ํ•œ ๋„ค์ดํ‹ฐ๋ธŒ ๋ช…๋ น์ธ airflow db clean์ด ์žˆ์œผ๋ฉฐ, ์ถ”๊ฐ€์ ์ธ ์˜ต์…˜์€ ์—ฌ๊ธฐ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

Kubernetes๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ์ด๋ฅผ ์œ„ํ•œ CronJob์„ Airflow ์ฐจํŠธ์— ์ถ”๊ฐ€ ๋ฆฌ์†Œ์Šค๋กœ ์„ค์ •ํ•˜์—ฌ ์ง€์ •ํ•œ ํ”Œ๋ž˜๊ทธ์™€ ํ•จ๊ป˜ ์ฃผ๊ธฐ์ ์œผ๋กœ airflow db clean ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์€ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ผ์ผ ๋˜๋Š” ์ฃผ๊ฐ„์œผ๋กœ ์‹คํ–‰ํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.