• **ETL(Extract, Transform, Load)**๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์†Œ์Šค์—์„œ ์ถ”์ถœ โ†’ ๊ฐ€๊ณต โ†’ ๋ชฉ์ ์ง€์— ์ ์žฌํ•˜๋Š” 3๋‹จ๊ณ„ ์ฒ˜๋ฆฌ ๊ณผ์ •
  • ํฉ์–ด์ง„ ์›๋ณธ์„ ๋ถ„์„ ๊ฐ€๋Šฅํ•œ ํ˜•ํƒœ๋กœ ์ •์ œํ•ด ๋ฐ์ดํ„ฐ ์›จ์–ดํ•˜์šฐ์Šค/๋งˆํŠธ์— ์ฑ„์›Œ ๋„ฃ๋Š” ์ž‘์—…
  • Airflow๋Š” ์ด ETL ๊ณผ์ •์„ ์ฝ”๋“œ(Python)๋กœ ์ •์˜ํ•˜๊ณ  ์ฃผ๊ธฐ์ ์œผ๋กœ ์ž๋™ ์‹คํ–‰ํ•˜๋Š” ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ๋„๊ตฌ

ํ•ด๋‹น ๊ฐœ๋…์ด ํ•„์š”ํ•œ ์ด์œ 

  • ์šด์˜ DB ์›๋ณธ์€ ๋ถ„์„์— ๋ฐ”๋กœ ์“ฐ๊ธฐ ์–ด๋ ต๋‹ค(์ค‘์ฒฉ ๊ตฌ์กฐ, ์ •๊ทœํ™”, ์ฝ”๋“œ๊ฐ’ ๋“ฑ) โ†’ ๊ฐ€๊ณต ๋‹จ๊ณ„๊ฐ€ ํ•„์š”
  • ๋ถ„์„ ์ˆซ์ž๋ฅผ ๋งค๋ฒˆ ์†์œผ๋กœ ๋งŒ๋“ค๋ฉด ์ •์˜๊ฐ€ ํ”๋“ค๋ฆฐ๋‹ค โ†’ ETL๋กœ ๊ณ ์ •ยท์ž๋™ํ™”ํ•˜๋ฉด ๊ฐ™์€ ๋กœ์ง์ด ๋งค์ผ ๋ฐ˜๋ณต๋œ๋‹ค
  • ๋ฐ์ดํ„ฐ ๋งˆํŠธ์˜ โ€œ1๊ฐœ์˜ ์ •์ œ๋œ ํ…Œ์ด๋ธ”โ€์€ ๊ฒฐ๊ตญ ETL ์žก์˜ ์‚ฐ์ถœ๋ฌผ์ด๋‹ค

3๋‹จ๊ณ„๊ฐ€ ํ•˜๋Š” ์ผ

  • Extract(์ถ”์ถœ): ๊ด€๊ณ„ํ˜• DBยทMongoDBยทํŒŒ์ผยทAPIยท์›น ๋“ฑ ํ•˜๋‚˜ ์ด์ƒ์˜ ์†Œ์Šค์—์„œ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘, ๊ธฐ๋Œ€ํ•œ ๋„๋ฉ”์ธ ๊ฐ’์ธ์ง€ ๊ฒ€์ฆ
  • Transform(๊ฐ€๊ณต): ์ปฌ๋Ÿผ ์„ ํƒ/ํ•„ํ„ฐ, ์ฝ”๋“œ๊ฐ’ ๋ณ€ํ™˜(1โ†’M), ํŒŒ์ƒ ์ปฌ๋Ÿผ ๊ณ„์‚ฐ, ์—ฌ๋Ÿฌ ์†Œ์Šค ์กฐ์ธ, ์ค‘๋ณต ์ œ๊ฑฐ, ์ง‘๊ณ„(roll-up/summary)
  • Load(์ ์žฌ): ์ตœ์ข… ๋ชฉ์ ์ง€(์›จ์–ดํ•˜์šฐ์Šค/๋งˆํŠธ)์— ์ €์žฅ. ๊ธฐ์กด์„ ๋ฎ์–ด์“ฐ๊ฑฐ๋‚˜(overwrite) ์ด๋ ฅ์„ ๋ˆ„์ (append)

ETL vs ELT

  • ETL: ์™ธ๋ถ€์—์„œ ๊ฐ€๊ณตํ•œ ๋’ค ์ ์žฌ (์ „ํ†ต์  ๋ฐฉ์‹)
  • ELT: ์ผ๋‹จ ์ ์žฌํ•˜๊ณ  DW ์•ˆ์—์„œ SQL๋กœ ๊ฐ€๊ณต โ€” RedshiftยทSnowflakeยทBigQuery ๊ฐ™์€ ํด๋ผ์šฐ๋“œ DW์—์„œ ์„ ํ˜ธ
  • ํ•ต์‹ฌ ์ฐจ์ด๋Š” โ€œ๊ฐ€๊ณต์„ ์–ด๋””์„œ ํ•˜๋А๋ƒโ€์ด๊ณ , ๊ฐ•๋ ฅํ•œ ๋ถ„์„ DW๊ฐ€ ์žˆ์œผ๋ฉด ELT๊ฐ€ ์œ ๋ฆฌํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค

Airflow๋กœ ETL ๊ตฌํ˜„ํ•˜๊ธฐ

  • DAG(Directed Acyclic Graph): ์›Œํฌํ”Œ๋กœ ์ „์ฒด๋ฅผ ๋…ธ๋“œ(task)์™€ ์˜์กด์„ฑ(edge)์œผ๋กœ ๊ทธ๋ฆฐ ํ๋ฆ„๋„. โ€œ๋ฌด์—‡์„, ์–ด๋–ค ์ˆœ์„œ๋กœโ€๋ฅผ ์ •์˜
  • Task: DAG ์•ˆ์˜ ๊ฐœ๋ณ„ ์ž‘์—… ๋‹จ์œ„
  • Operator: ๊ทธ ์ž‘์—…์„ ์–ด๋–ป๊ฒŒ ํ• ์ง€ (Python ์‹คํ–‰, SQL ์ฟผ๋ฆฌ, ์™ธ๋ถ€ ํŠธ๋ฆฌ๊ฑฐ ๋“ฑ)
  • Scheduler: ์ •ํ•ด์ง„ ์ฃผ๊ธฐ(๋งค์‹œ๊ฐ„/๋งค์ผ)๋‚˜ ์ด๋ฒคํŠธ๋กœ ์‹คํ–‰์„ ๊ด€๋ฆฌ
  • ์„ค์ •์„ XML์ด ์•„๋‹Œ โ€œ์ฝ”๋“œ๋กœ(configuration as code)โ€ ์ž‘์„ฑ โ†’ ์›Œํฌํ”Œ๋กœ ํ•˜๋‚˜๊ฐ€ Python ํŒŒ์ผ ํ•˜๋‚˜์— ๋‹ด๊ธด๋‹ค
# ๋งค์ผ 1๋ฒˆ, ์›๋ณธ ์ด๋ฒคํŠธ๋ฅผ ์ง‘๊ณ„ํ•ด ๋งˆํŠธ ํ…Œ์ด๋ธ”์„ ๊ฐฑ์‹ ํ•˜๋Š” DAG (๊ฐœ๋… ์˜ˆ์‹œ)
with DAG("daily_conversion_mart", schedule="@daily") as dag:
    extract = PythonOperator(task_id="extract", python_callable=pull_raw_events)
    transform = PythonOperator(task_id="transform", python_callable=aggregate_by_day)
    load = PostgresOperator(task_id="load", sql="INSERT INTO mart_daily_conversion ...")
 
    extract >> transform >> load   # ์˜์กด์„ฑ: ์ถ”์ถœ โ†’ ๊ฐ€๊ณต โ†’ ์ ์žฌ

๋ฐ์ดํ„ฐ ๋งˆํŠธ ๋งฅ๋ฝ์—์„œ์˜ ์—ญํ• 

  • ๊ณต๊ณต๋ฐ์ดํ„ฐยท์šด์˜ DB(์†Œ์Šค) โ†’ Airflow๊ฐ€ ETL์„ ์Šค์ผ€์ค„๋ง โ†’ Redshift์˜ ๋งˆํŠธ ํ…Œ์ด๋ธ” โ†’ Redash ๋Œ€์‹œ๋ณด๋“œ
  • ์ฆ‰ Airflow๋Š” ๋ฐ์ดํ„ฐ ๋งˆํŠธ๋ฅผ โ€œํ•ญ์ƒ ์ตœ์‹  ์ƒํƒœ๋กœ ์œ ์ง€ํ•ด ์ฃผ๋Š” ์—”์ง„โ€ ์—ญํ• ์ด๋‹ค

์ฐธ๊ณ  ๋ฌธ์„œ