Mengapa orkestrasi

Masalah yang diselesaikan orkestrasi, yaitu penjadwalan, dependensi, dan observabilitas pipeline.

Daftar isi

Topik ini membahas masalah yang diselesaikan orkestrasi pipeline, yaitu penjadwalan, dependensi antar pekerjaan, dan observabilitas. Pembahasan dimulai dari batas penjadwal berbasis cron, dilanjutkan dengan tiga kebutuhan yang dijawab orkestrator, lalu ditutup dengan simulasi resolusi dependensi menggunakan Python murni. Setelah membaca, alasan memindahkan skrip terjadwal ke dalam orkestrator dapat dirumuskan secara konkret, bukan sekadar mengikuti kebiasaan.

Batas cron pada pipeline nyata#

Cron, yakni penjadwal bawaan sistem Unix yang menjalankan perintah pada pola waktu tertentu, sudah memadai untuk satu skrip yang berdiri sendiri. Masalah muncul ketika pekerjaan bertambah dan saling bergantung. Daftar cron berikut memuat tiga pekerjaan yang pada praktiknya harus berjalan berurutan.

text Contoh: daftar cron tiga pekerjaan
# ekstraksi data dari sumber, pukul 01.30
30 1 * * * /opt/pipeline/ekstraksi.sh
# pembersihan hasil ekstraksi, pukul 02.00
0 2 * * * /opt/pipeline/pembersihan.sh
# muat hasil pembersihan ke gudang data, pukul 02.45
45 2 * * * /opt/pipeline/muat.sh

Jadwal semacam itu menyatakan urutan lewat jeda waktu, bukan lewat dependensi. Apabila ekstraksi selesai lebih lambat karena sumbernya lambat merespons, pembersihan tetap berjalan pada pukul 02.00 dan membaca berkas yang belum lengkap. Tidak ada mekanisme pada cron yang menahan pekerjaan berikutnya sampai pekerjaan sebelumnya benar-benar selesai. Jeda antar jadwal perlu diperlebar untuk mengantisipasi kemacetan, sehingga total waktu pipeline memanjang tanpa alasan.

Dua keterbatasan lain menyertai masalah urutan. Pertama, tidak ada percobaan ulang terpusat, sehingga setiap skrip mengatur sendiri kebijakan mencoba ulang dan kebijakannya mudah berbeda-beda antar skrip. Kedua, tidak ada antarmuka pemantauan seperti UI, yakni tampilan web bawaan orkestrator untuk melihat status pekerjaan, sehingga pemeriksaan hanya dapat dilakukan dengan membaca berkas log yang tersebar satu per satu.

Tiga kebutuhan yang dijawab orkestrasi#

Orkestrasi, yakni pengaturan jadwal, urutan, dan pemulihan pekerjaan oleh satu alat terpusat, menjawab ketiga kebutuhan di atas. Orkestrator seperti Apache Airflow menyimpan pipeline sebagai kode Python yang menyatakan dependensi secara eksplisit. Setiap task, yakni satu unit pekerjaan di dalam pipeline, dijalankan hanya setelah syaratnya terpenuhi. Urutan tidak lagi diperkirakan dari jeda waktu, tetapi dinyatakan dan dievaluasi oleh sistem.

KebutuhanCron dan skrip terpisahOrkestrator
Urutan antar pekerjaandiperkirakan dari jeda waktudinyatakan sebagai dependensi dan dievaluasi otomatis
Percobaan ulangdiatur sendiri di setiap skripdikonfigurasi sekali per task di satu tempat
Pemantauanberkas log yang tersebarUI dengan status per task, log, dan riwayat eksekusi

Kolom orkestrator pada tabel bukan kemewahan tambahan, melainkan syarat pipeline dapat diandalkan. Status setiap task beserta lognya tampil pada satu layar, sehingga pekerjaan yang gagal semalam terlihat dalam hitungan detik. Riwayat eksekusi juga terekam per tanggal, sehingga perilaku pipeline pada hari tertentu dapat ditinjau ulang tanpa menyusuri log dari awal.

Resolusi dependensi yang disimulasikan#

Resolusi dependensi, yakni proses menentukan urutan eksekusi dari daftar dependensi, dapat disimulasikan dengan Python murni. Graf berikut memperlihatkan pipeline rekap nilai ujian yang dipakai sebagai contoh, dengan dua task pembacaan yang boleh berjalan bersamaan.

Graf dependensi pipeline rekap nilai ujianbaca_nilaibaca_absensigabungkanhitung_rata_ratasimpan_rekap
Graf dependensi pipeline rekap nilai ujian

Skrip berikut menerapkan pengurutan topologis, yakni algoritma yang mencetak task yang syaratnya sudah terpenuhi, menandainya selesai, lalu mengulangi langkah itu sampai semua task tercetak. Nama task dan dependensinya disimpan dalam kamus, sehingga urutan eksekusi dapat dihitung tanpa alat tambahan.

python urutan-tugas.py
"""Mensimulasikan resolusi dependensi DAG kecil dengan pengurutan topologis."""

dependensi = {
    "baca_nilai": set(),
    "baca_absensi": set(),
    "gabungkan": {"baca_nilai", "baca_absensi"},
    "hitung_rata_rata": {"gabungkan"},
    "simpan_rekap": {"hitung_rata_rata"},
}

selesai: set[str] = set()
tingkat = 0
while len(selesai) < len(dependensi):
    siap = sorted(
        nama
        for nama, syarat in dependensi.items()
        if nama not in selesai and syarat <= selesai
    )
    if not siap:
        raise SystemExit("terdapat dependensi melingkar, urutan tidak bisa diselesaikan")
    tingkat += 1
    print(f"tingkat {tingkat}: {', '.join(siap)}")
    selesai.update(siap)
text Keluaran
tingkat 1: baca_absensi, baca_nilai
tingkat 2: gabungkan
tingkat 3: hitung_rata_rata
tingkat 4: simpan_rekap

Keluaran menampilkan empat tingkat eksekusi. Task pada tingkat yang sama, yaitu baca_nilai dan baca_absensi pada tingkat pertama, bebas dijalankan berdampingan karena tidak saling menunggu. Struktur yang diperiksa skrip ini disebut DAG, yakni graf dependensi berarah yang tidak membentuk putaran tertutup, dan orkestrator melakukan perhitungan serupa setiap kali menjalankan pipeline. Perulangan pada skrip juga memperlihatkan alasan graf tidak boleh membentuk lingkar. Apabila sekelompok task saling menunggu, task-task itu tidak akan pernah tercetak, dan program berhenti dengan pesan bahwa dependensi melingkar tidak bisa diselesaikan.

Urutan tingkat tersebut juga memperlihatkan apa yang menunggu orkestrator ketika satu task lambat. Task hitung_rata_rata tidak boleh dimulai sebelum gabungkan selesai, sehingga kemacetan pada satu task menjalar ke seluruh task yang menunggunya. Dengan informasi semacam ini, keputusan operasional seperti menambah mesin pekerja atau memecah task yang berat dapat diambil berdasarkan graf, bukan berdasarkan perkiraan. Kegagalan pada satu tingkat pun tidak mematikan pipeline seketika, karena kelanjutannya ditentukan aturan trigger dan percobaan ulang yang diatur pada task masing-masing.

Kesalahan umum#

  1. Menggantikan dependensi dengan jeda waktu. Penyebabnya, kebiasaan dari daftar cron terbawa saat merancang pipeline, sehingga pekerjaan berikutnya dijadwalkan dengan asumsi pekerjaan sebelumnya sudah selesai. Perbaikannya, nyatakan dependensi secara eksplisit dan biarkan orkestrator mengevaluasinya.
  2. Membangun sistem pemantauan sendiri sebelum memakai orkestrator. Penyebabnya, skrip bertambah satu per satu sehingga pelacakan status terasa sederhana pada awalnya. Perbaikannya, pindahkan penjadwalan ke orkestrator dan gunakan UI serta log yang sudah tersedia.
  3. Menunda orkestrasi sampai pipeline membesar. Penyebabnya, beberapa skrip yang dijalankan manual masih terasa terkendali. Perbaikannya, pindahkan ke orkestrator sejak dependensi mulai terbentuk, karena memigrasikan skrip kecil jauh lebih mudah daripada membedah belasan pekerjaan yang saling bergantung.
  4. Menyatukan seluruh tahap dalam satu skrip besar. Penyebabnya, pekerjaan yang sudah jalan dianggap selesai menyusun, padahal kegagalan di tengah skrip memaksa seluruh tahap diulang dari awal. Perbaikannya, pecah pekerjaan menjadi task-task kecil seperti ekstraksi, pembersihan, dan muat, sehingga kegagalan hanya mengulang tahap yang gagal.

Ringkasan#

  • Cron menyatakan urutan lewat jeda waktu, sedangkan orkestrator menyatakannya sebagai dependensi yang dievaluasi otomatis sebelum task berikutnya dijalankan.
  • Orkestrasi mengumpulkan penjadwalan, percobaan ulang, dan pemantauan pada satu tempat, sehingga kegagalan terlihat cepat dan pemulihannya seragam.
  • Urutan eksekusi dihitung dari graf dependensi dengan pengurutan topologis, dan task yang syaratnya sudah terpenuhi boleh berjalan berdampingan.

Referensi#