Kapan tidak memakai Spark

Kejujuran tentang skala, yaitu kapan DuckDB dan pandas sudah cukup dan Spark justru membebani.

Daftar isi

Spark memecahkan masalah skala, tetapi pemakaiannya membawa biaya yang tidak selalu sepadan dengan masalah yang dihadapi. Banyak pekerjaan data yang ukurannya masih berada dalam jangkauan satu mesin, dan alat yang lebih sederhana menyelesaikannya lebih cepat dari sisi pengembangan maupun operasional. Topik ini merangkum pertimbangan memilih antara satu mesin dan Spark, menampilkan tabel keputusannya, serta mendemonstrasikan agregasi CSV dengan DuckDB pada skala di mana satu mesin sudah cukup.

Biaya yang menyertai Spark#

Spark menyelesaikan distribusi data, penjadwalan, dan ketahanan terhadap kegagalan, tetapi kemampuan itu dibayar dengan kompleksitas yang hadir sejak pekerjaan paling kecil. Kode PySpark berjalan di atas JVM, sehingga setiap pekerjaan menanggung waktu startup yang tidak dimiliki alat proses tunggal. Penyetelan performa menuntut pemahaman atas partisi, shuffle, dan konfigurasi memori executor, dan seluruh pengetahuan itu tidak relevan bagi pekerjaan yang muat di satu mesin.

Biaya terbesar berada di sisi operasional. Cluster perlu dipasang, dipantau, dan ditingkatkan versinya, baik yang dikelola sendiri maupun yang memakai layanan terkelola yang menagih per pemakaian. Tim yang menjalankan pipeline mingguan pada puluhan megabyte data akan menghabiskan lebih banyak waktu untuk mengurus infrastruktur daripada mengurus datanya. Pilihan yang rasional adalah menunda Spark sampai ukuran masalah menuntutnya, bukan mengadopsinya lebih awal karena memilih yang populer.

Tabel keputusan memilih alat#

Keputusan antara satu mesin dan Spark dapat diturunkan dari empat pertimbangan, yaitu ukuran data, latensi yang dituntut, kemampuan tim, dan biaya operasional. Tabel berikut menyusun keempatnya dalam bentuk yang dapat dibandingkan langsung.

PertimbanganSatu mesin sudah cukupSpark layak dipertimbangkan
Ukuran dataPuluhan megabyte sampai beberapa gigabyteRatusan gigabyte sampai terabyte, atau data yang terus bertambah
LatensiPemrosesan batch berkala dengan toleransi menit sampai jamBanyak kueri serentak dari banyak pengguna atau pemrosesan berkelanjutan
Kemampuan timSatu sampai beberapa orang tanpa pengalaman operasi clusterTim yang terbiasa mengoperasikan dan memantau cluster
Biaya operasionalAnggaran terbatas dan kebutuhan pemeliharaan minimalAnggaran infrastruktur tersedia, termasuk untuk layanan terkelola

Ukuran data menjadi pertimbangan pertama karena batasnya paling mudah diamati. Puluhan megabyte sampai beberapa gigabyte masih nyaman dikerjakan satu mesin dengan memori standar, sedangkan ratusan gigabyte ke atas sudah menuntut pembagian pekerjaan ke beberapa mesin. Dua pertimbangan lain bersifat organisatoris, yaitu kemampuan tim yang mengurus alat tersebut dan biaya yang menyertainya, karena keduanya menentukan apakah Spark dapat dirawat setelah dipasang.

Demonstrasi DuckDB pada skala satu mesin#

DuckDB adalah basis data analitik yang berjalan di dalam proses aplikasi (in-process), tanpa server dan tanpa cluster, sehingga menjadi contoh alat satu mesin yang paling ringkas. Skrip berikut membuat berkas CSV kecil berisi 120 baris catatan peminjaman perpustakaan, lalu menjalankan satu query agregasi per genre langsung ke berkasnya.

python agregasi-duckdb.py
import duckdb

# CSV kecil yang deterministik: catatan peminjaman buku perpustakaan
baris = ["id_pinjam,genre,durasi_hari"]
for i in range(120):
    genre = ["sains", "sejarah", "sastra"][i % 3]
    durasi = 3 + (i * 7) % 11
    baris.append(f"P{i:04d},{genre},{durasi}")
with open("peminjaman.csv", "w", encoding="utf-8") as f:
    f.write("\n".join(baris) + "\n")

# agregasi langsung ke CSV, tanpa server dan tanpa cluster
kon = duckdb.connect()
hasil = kon.execute(
    """
    SELECT genre,
           count(*)                   AS jumlah,
           round(avg(durasi_hari), 1) AS rata_durasi
    FROM read_csv('peminjaman.csv')
    GROUP BY genre
    ORDER BY genre
    """
).fetchall()

for genre, jumlah, rata in hasil:
    print(f"{genre:<8} {jumlah:>4} {rata:>6}")
print(f"total baris: {sum(j for _, j, _ in hasil)}")
text Keluaran
sains      40    8.3
sastra     40    8.0
sejarah    40    7.8
total baris: 120

Seluruh proses berjalan di bawah satu detik pada sandbox jalur ini, tanpa JVM, tanpa konfigurasi, dan tanpa berkas lain selain CSV yang dibacanya. Query agregasi tersebut secara konsep sama dengan pekerjaan yang juga dikerjakan Spark, yaitu pengelompokan dan penghitungan, tetapi pada 120 baris perbedaan hasilnya nol sementara perbedaan kerumahtanggaannya besar. Kode yang ditulis pun hanya sekitar dua puluh baris dan tidak menuntut pengetahuan cluster apa pun.

DuckDB memakai SQL, sehingga kemampuannya berpindah antar alat, sedangkan pandas menyediakan alternatif berbasis Python untuk data yang masih lebih kecil lagi. Ketiga pilihan satu mesin ini, yaitu pandas, DuckDB, dan SQL biasa, menutup kebutuhan sampai titik di mana memori dan waktu satu mesin benar-benar habis. Titik tersebut terlihat dari metrik nyata, misalnya durasi pekerjaan yang terus naik atau dataset yang tidak lagi muat dibaca sekaligus.

Kesalahan umum#

Kesalahan berikut muncul ketika pemilihan alat didasarkan pada kebiasaan dan bukan pada ukuran masalah, dan setiap butir menyertakan perbaikannya.

  • Mengadopsi Spark karena berkas datanya terasa besar, padahal berkas yang sama terbaca utuh oleh DuckDB dalam hitungan detik. Perbaikannya adalah mengukur terlebih dahulu dengan alat satu mesin sebelum menambah infrastruktur.
  • Menganggap migrasi dari pandas ke Spark sebagai perubahan kecil. Pola evaluasi malas, partisi, dan shuffle membuat perilaku keduanya berbeda meski API-nya mirip. Perbaikannya adalah menguji ulang seluruh logika transformasi setelah migrasi.
  • Membiarkan cluster menyala setiap saat untuk pekerjaan yang jarang dieksekusi. Infrastruktur yang berjalan terus tetap menimbulkan biaya meskipun pipeline hanya berjalan mingguan. Perbaikannya adalah menyetel jadwal dan skala cluster sesuai frekuensi pekerjaan yang benar-benar berjalan.

Ringkasan#

  • Spark membawa biaya startup JVM, penyetelan partisi dan shuffle, serta operasi cluster yang tidak sepadan untuk data dalam jangkauan satu mesin.
  • Keputusan pemilihan alat dibaca dari ukuran data, latensi, kemampuan tim, dan biaya operasional, dengan puluhan megabyte sampai beberapa gigabyte sebagai wilayah nyaman satu mesin.
  • DuckDB menyelesaikan agregasi analitik pada skala kecil dalam satu proses, tanpa server dan tanpa konfigurasi.
  • Migrasi ke Spark dibenarkan oleh metrik nyata, bukan oleh ukuran berkas yang terasa besar.

Referensi#