μμ΄νλ‘μ° μμ΄, λ겨λ μλμΌλ‘ μ΄μ΄λ°λ μ λ’°μ± λμ ETLμ μ€κ³ν μ΄μΌκΈ°
1. λ§λ€κ² λ μ΄μ
κ΅λ¦½μ€μλμκ΄(NLK) μ μμ§μ 보APIλ₯Ό ν΅ν΄ νκ΅μ λ±λ‘λ λͺ¨λ λμμ μμ§ λ°μ΄ν°λ₯Ό 곡κ°νκ³ μλ€.
λλ 2000λ 1μλΆν° 2024λ 12μκΉμ§, μ¦ 25λ μΉ μ 체 λ°μ΄ν°λ₯Ό PostgreSQL(Supabase) μ μ μ₯ν΄ λ³΄κ³ μΆμλ€.
μ²μμ λ¨μν βAPIλ₯Ό 루ν λ리면 λκ² μ§β μΆμλ€. νμ§λ§ μ€μ λ‘λ μλ λ¬Έμ λ€μ ν΄κ²°ν΄μΌ νλ€.
- νΈμΆ μ ν(rate limit)κ³Ό μ°κ²° λκΉ(timeout)
- 25λ Γ 12κ°μ = 300κ°μ λΆλμ λ°μ΄ν°
- EC2 μ°κ²°μ΄ μ€κ°μ λκΈ°λ λ¬Έμ
- μλ°±λ§ κ±΄ JSONμ μ€λ³΅ μ½μ λ°©μ§
2. NLK API μ΄ν΄νκΈ°
μ°Έκ³ : κ΅λ¦½μ€μλμκ΄ μμ§μ 보 API λ¬Έμ
- μΈμ¦ν€(
cert_key) νμ - μμ²λ³μ:
PUBLISH_PREDATE - μΌμ μμ
page_size = 100μμ² κ°λ₯
μ¦, μ 체 λ°μ΄ν°λ₯Ό ν λ²μ κ°μ Έμ¬ μ μμλ€. κ·Έλμ βμ λ¨μ νν°μ λβ μ λ΅μ μΈμ λ€ β ν λ¬μ© λͺ νν κΈ°κ°μΌλ‘ λλ μμ§νκΈ°.
3. 첫 λ²μ§Έ νλ‘ν νμ β λ¨μν Fetcher
fetch_pages.pyλ μ΄λ κ² λμνλ€.
- νμ΄μ§λ₯Ό μμλλ‘ μμ²
- JSONμ
raw_nl_booksν μ΄λΈμ μ½μ - μ½μμ μ§ν λ‘κ·Έ μΆλ ₯
μλμ λμ§λ§, μλμ κ°μ λ¬Έμ κ° μμλ€.
- μ€κ°μ μλ¬ λλ©΄ μ²μλΆν° λ€μ ν΄μΌ ν¨
- EC2 μ¬λΆν μ μ§νμν© μ¬λΌμ§
- λ§€λ¬ μ€ν¬λ¦½νΈλ₯Ό μλμΌλ‘ μμ ν΄μΌ ν¨
4. μλμμ μλμΌλ‘
μνλ μμ€ν μ λ€μκ³Ό κ°μλ€.
- 2000λ λΆν° 2024λ κΉμ§ λͺ¨λ λ¬ μλ μμ§
- λ€νΈμν¬ λκΉμλ μ¬μμ
- μ€λ³΅ μλ μμ ν μ½μ
- λ©°μΉ κ° λ¬΄μΈμΌλ‘ μμ μλ
μ€μΌμ€νΈλ μ΄μ λꡬλ₯Ό κ³ λ €ν΄λ³΄μλ€. κ°λ³κ³ λ¨λ¨ν κ΅¬μ‘°κ° νμνλ€.
5. κ³ λ €ν μ€μΌμ€νΈλ μ΄μ μ΅μ
| μ΅μ | μ₯μ | λ¨μ | μ ν |
|---|---|---|---|
| Cron | μ€μ κ°λ¨ | μ¬μλΒ·λ°±μ€ν μμ, λͺ¨λν°λ§ λΆνΈ | β |
| Airflow / Kestra | UI, μμ ν μν¬νλ‘ κ΄λ¦¬ | λ¨μΌ μμ μ κ³Όν¨ | β |
| systemd | μλ μ¬μμ, λ‘κ·Έ κ΄λ¦¬, μΈλΆ μμ‘΄λ μμ | Linux νμ | β μ ν |
systemd λ₯Ό μ νν΄λ€. 리λ μ€μ κΈ°λ³Έ λ΄μ₯λμ΄ μκ³ , λ€μμ λͺ¨λ μ§μνλ€.
- μ€ν¨ μ μλ μ¬μμ
journalctlλ‘κ·Έ μ‘°ν- μλΉμ€ μμΒ·μ€μ§ κ°λ¨
- μΆκ° μ€μΉλ DB μ€μ λΆνμ
6. 체ν¬ν¬μΈνΈ μ€κ³
κ°λ¨ν μν μ μ₯ ν΄λ νλλ₯Ό λ§λ€μλ€.
~/nlk-state/
κ° λ¬λ§λ€ λ κ°μ νμΌμ΄ μκΈ΄λ€.
2000-01.page # λ§μ§λ§μΌλ‘ μ²λ¦¬ν νμ΄μ§
2000-01.done # ν΄λΉ λ¬ μλ£ νμ
μμ€ν
μ΄ μ€κ°μ λ©μΆλλΌλ λ€μ μ€ν μ .pageλ₯Ό μ½μ΄ λ°λ‘ μ΄μ΄μ μμνλ€.
νμΌ κΈ°λ°μΌλ‘ ν μ΄μ :
- DB λ½(lock) λ¬Έμ μμ
- λμΌλ‘ λ°λ‘ νμΈ κ°λ₯
- DB μ°κ²°μ΄ μ λΌλ μ§ν μν μ μ§
7. μλ³ λ¬λ μ€κ³
fetch_pages_month.pyλ₯Ό νμ₯ν΄ λ€μ κΈ°λ₯μ λ£μλ€.
- μ§μ ν μ λ²μ(
start_publish_dateβend_publish_date) μμ² - μ±κ³΅ μ
.pageκ°±μ - νμμμ μ λΉμ μ μ’ λ£ (systemdκ° μ¬μμ)
rec_hash = md5(source_record::text)λ‘ μ€λ³΅ λ°©μ§
μ΄μ κ° λ¬μ΄ κΉλν μ’ λ£λλ©°, κ²°κ³Όκ° μμΌλ©΄ μλμΌλ‘ λ€μ λ¬λ‘ λμ΄κ°λ€.
8. μ 체 κ΄λ¦¬μ: run_all_months.py
μ΄ μ€ν¬λ¦½νΈκ° μ 체 25λ 루νλ₯Ό λλ¦°λ€.
2000-01 β 2000-02 β β¦ β 2024-12
κ° λ¬μ λν΄:
.doneμμΌλ©΄ μ€ν΅- μμΌλ©΄
fetch_pages_month.pyμ€ν - μ±κ³΅ μ
.doneμμ± - μ€ν¨ μ μ’ λ£ (systemdκ° μ¬μμνμ¬ κ°μ λ¬λΆν° μ¬κ°)
μ ν νμΌμ λ€ λ£μ§ μκ³ βλ§€λμ + λ¬λβλ‘ λλ΄λ? β μ± μ λΆλ¦¬κ° λͺ νν΄μ§λ€. μλ³ μ€ν¬λ¦½νΈλ APIΒ·DBμ μ§μ€νκ³ , λ§€λμ λ νλ¦ μ μ΄μ 체ν¬ν¬μΈνΈλ§ λ§‘λλ€.
9. μνΌλ°μ΄μ : systemd
nlk-history.service νμΌμ μ΄λ κ² κ΅¬μ±νλ€.
[Service]
User=ec2-user
WorkingDirectory=/home/ec2-user/kbook-data-pipeline
ExecStart=/home/ec2-user/kbook-data-pipeline/venv/bin/python /home/ec2-user/kbook-data-pipeline/scripts/run_all_months.py
Restart=on-failure
RestartSec=30s
μ systemdλ₯Ό μ ννλ?
- λΉμ μ μ’ λ£ μ μλ μ¬μμ
- UIλ λ°μ΄ν°λ² μ΄μ€ νμ μμ
journalctlλ‘ λ‘κ·Έ νμΈ μ©μ΄- μ₯μκ° EC2 μμ μ μ΅μ
λ§μ§λ§ λ¬μ΄ λλλ©΄ μ μ μ’ λ£ μ½λ(0)λ‘ μ’ λ£λκ³ , systemdλ κΉλν μ μ§νλ€.
10. νμ΄νλΌμΈ κ²μ¦
μ μ μλ νμΈλ²:
.pageνμΌμ΄ μ£ΌκΈ°μ μΌλ‘ κ°±μ λ¨- λ¬μ΄ λλλ©΄
.doneμμ± - EC2 μ¬λΆν νμλ κ°μ μμΉμμ μ¬κ°
rec_hashλ‘ μ€λ³΅ μ½μ μμ νμΈ
μ 체 μ€ν μκ°: μ½ 30λΆ Γ 300κ°μ = μ½ 6μΌ μ°μ μμ§
11. ν΄κ²°ν λ¬Έμ λ€
| λ¬Έμ | ν΄κ²°μ± |
|---|---|
| ID μ€λ³΅ | ALTER SEQUENCE β¦ RESTARTλ‘ identity 리μ
|
| ν μ€λ³΅ | rec_hash κ³ μ μ»¬λΌ μΆκ° |
| νμμμ | λ°±μ€ν(backoff)μ κΈ΄ read timeout |
| EC2 λκΉ | systemdλ‘ κ΄λ¦¬ |
12. κ²°κ³Ό
μΌμ£ΌμΌ λ¬΄μΈ μ€ν ν:
- β 2000β2024λ μ 체 λ°μ΄ν° Postgres μ μ₯
- β μ€λ³΅ μλ μ½μ
- β λ€νΈμν¬ μ€λ₯μλ μλ 볡ꡬ
- β μμ ν λ¬΄μΈ νμ΄νλΌμΈ
μ΄ μ½ 600λ§ κ±΄μ λμ κΈ°λ‘μ μμ μ μΌλ‘ μμ§ μλ£νλ€.
13. λ°°μ΄ μ
- λ¨μν¨μ΄ νμ₯μ±μ΄λ€. β ν λ°©ν₯μΌλ‘λ§ νλ¬κ°λ μμ μ κ°λ²Όμ΄ μ€ν¬λ¦½νΈκ° λν νλ μμν¬λ³΄λ€ λ«λ€.
- λͺ μμ 체ν¬ν¬μΈνΈ > 무ν μ¬μλ.
- systemdλ κ³Όμνκ°λ μ΄μ μλν λꡬλ€.
- μ²μλΆν° β볡ꡬ κ°λ₯μ±(resumability)β μ μΌλμ λ¬λΌ. μ΅μ νλ κ·Έλ€μμ΄λ€.