Topik wawancara representatif

Wawancara Data Engineering: Bagaimana Cara Mendiagnosis dan Memperbaiki Spark Data Skew?

DataSulit
Tim Redaksi Offer.ccDipublikasikan Diperbarui

Pertanyaan

Sebuah Spark SQL job harian melakukan left-join tabel fakta event berukuran 4.8 TB ke dimensi produk berukuran 180 GB. Setelah sebuah rilis di upstream, 32% event terpetakan ke product_id='UNKNOWN'. Di antara 2.000 shuffle partition, median task shuffle read adalah 1.1 GiB, tetapi satu task membaca 720 GiB, berulang kali spill ke disk, dan gagal karena OOM; waktu eksekusi (runtime) melonjak dari 24 menjadi 96 menit. Bagaimana Anda membuktikan penyebabnya, memperbaikinya tanpa membuang data atau mengubah hasil join, serta memvalidasi solusinya?

Prompt dan Kapan Ini Berlaku

Sebuah Spark SQL job harian melakukan left-join tabel fakta event berukuran 4.8 TB ke dimensi produk berukuran 180 GB pada product_id. Setelah sebuah rilis di upstream, 32% event dinormalisasi ke product_id='UNKNOWN'. Job tersebut menggunakan 2.000 shuffle partition. Pada tahap (stage) join, Spark UI menunjukkan median task shuffle read sebesar 1.1 GiB, sementara satu task membaca 720 GiB, berulang kali spill ke disk, dan akhirnya gagal karena OOM setelah retries. Runtime telah melonjak dari 24 menjadi 96 menit. Bisnis menuntut job selesai dalam 45 menit, tanpa membuang event unknown-product atau mengubah hasil left-join.

Ukuran tabel, proporsi key, metrik partisi, runtime, dan SLA adalah asumsi wawancara. Tugas utamanya adalah membedakan data skew dari ketidakcukupan sumber daya dan join-output explosion menggunakan bukti tingkat partisi, kemudian memilih solusi yang mempertahankan kontrak data. Hal ini termasuk dalam kategori data karena menguji rencana eksekusi (execution plan) Spark, shuffle partition, distribusi data, dan kebenaran batch. Pertanyaan Kafka hot-partition yang sudah ada berfokus pada message keys, pengurutan, dan consumer offsets. Pertanyaan ini berfokus pada runtime SQL partition, strategi join, AQE, dan konservasi hasil, sehingga lapisan kegagalan dan metode validasinya berbeda.

Penalaran yang sama berlaku untuk groupBy, distinct, fungsi window, dan wide dependencies lainnya. Ketika banyak record untuk satu key bertumpu pada beberapa post-shuffle task, hal tersebut dapat menciptakan stragglers, spill, tekanan GC, atau OOM. Jawaban yang baik tidak dimulai dengan menambah memori. Jawaban tersebut pertama-tama membuktikan apakah task yang paling lambat memproses jumlah data dan komputasi yang tidak proporsional.

Apa yang Dinilai Pewawancara

Mulailah dengan granularitas bukti. Jawaban yang kuat bergerak dari job ke kueri SQL, lalu ke stage spesifik dan task individualnya. Jawaban tersebut membandingkan durasi, shuffle-read records dan bytes, spill, peak execution memory, dan waktu GC. Task yang membaca ratusan kali lipat dari median dan tetap lambat ketika dicoba ulang (retry) pada executor lain mengindikasikan deterministic data skew. Memori agregat executor dan total runtime saja tidak dapat membuktikan penyebab tersebut.

Kemampuan membaca rencana eksekusi juga sama pentingnya. EXPLAIN FORMATTED mengonfirmasi Exchange, tipe join, dan physical join. EXPLAIN COST dan statistik runtime di SQL UI mengekspos estimasi dan ukuran data yang diamati. Spark AQE menggunakan statistik runtime untuk menyesuaikan rencana. Di Spark 4.2.0, optimasi skew-join dapat membagi partisi sort-merge-join yang mengalami skew dan mereplikasi sisi yang lebih kecil jika diperlukan. Nilai default yang terdokumentasi hanya menandai partisi sebagai skew ketika melebihi lima kali median dan berukuran lebih dari 256 MiB. Kandidat harus memeriksa konfigurasi lingkungan yang efektif karena default dokumentasi bukanlah fakta klaster yang tidak dapat diubah.

Semantik data menjadi garis pemisah. UNKNOWN bisa jadi merupakan event "unattributed" yang valid atau sebuah kecacatan di upstream. Menghapus, mendistribusikan secara acak, atau menulis ulang baris-baris tersebut dapat mengubah hasil. Salted join harus hanya mereplikasi baris hot-key dari dimensi dan memberikan salt yang deterministik pada baris fakta yang panas (hot fact rows). Mereplikasi seluruh dimensi akan melipatgandakan volume data, sementara melakukan pengacakan secara independen pada kedua sisi akan menghilangkan kecocokan (matches).

Pemilihan solusi menunjukkan tingkat kedalaman pemahaman lainnya. Menaikkan spark.sql.shuffle.partitions membuat lebih banyak hash bucket, tetapi setiap baris untuk satu hot key tetap akan masuk ke dalam satu bucket yang sama. Broadcast hanya cocok jika proyeksi, pemfilteran, dan statistik yang andal membuktikan bahwa satu sisi muat dengan aman di setiap executor; memaksakan dimensi 180 GB untuk di-broadcast tidaklah aman. AQE adalah pilihan pertama yang minim intrusi. Explicit salting cocok untuk hot key yang stabil ketika AQE tidak terpicu atau masih belum memenuhi SLA. Agregasi sering kali menggunakan agregasi parsial dengan salt yang diikuti oleh merge kedua.

Validasi lengkap menutup jawaban. Perbaikan performa juga harus membuktikan bahwa jumlah baris, nominal bisnis, unknown keys, unmatched rates, dan duplicate rates tidak berubah. Mengurangi runtime dari 96 menjadi 40 menit tidak membuktikan kebenaran atau menunjukkan apakah solusi tersebut dapat bertahan terhadap distribusi key yang berbeda besok.

Pertanyaan untuk Diklarifikasi Sebelum Menjawab

  • Apakah bottleneck berada pada scan, shuffle write, atau setelah shuffle read? Task scan yang tidak merata dapat berasal dari file yang sangat besar atau tidak dapat dipecah (unsplittable). Prompt ini mengarah ke jalur key-skew karena outlier muncul setelah proses join shuffle.
  • Apakah 32% mengacu pada jumlah record, compressed bytes, atau biaya pemrosesan? Baris yang lebar, UDF yang berat, dan output fan-out dapat menciptakan cost skew meskipun jumlah baris terlihat moderat. Bandingkan records, bytes, waktu, dan output rows.
  • Apa arti UNKNOWN bagi bisnis? Jika produk unknown tidak memerlukan atribut dimensi, pisahkan dari join utama dan isi atribut bernilai null sesuai kontrak awal. Jika harus cocok dengan baris dimensi sentinel, pertahankan join dan pecah hotspot-nya.
  • Apakah product_id unik di dalam dimensi produk? Beberapa baris dimensi UNKNOWN akan mengubah hot fact key menjadi ledakan output many-to-many. Pisahkan kardinalitas yang buruk dari partition skew sebelum melakukan tuning.
  • Versi Spark dan pengaturan AQE mana yang sedang aktif? Periksa halaman Environment dan adaptive plan akhir untuk melihat switch, ambang batas (thresholds), tipe join, dan bukti bahwa pemecahan skew benar-benar dijalankan.
  • Apakah 180 GB merupakan dimensi asli atau input join yang telah diproyeksikan? Jika pemfilteran ke key dan dua atribut membuatnya aman untuk di-broadcast, broadcast bisa mengalahkan two-sided shuffle. Statistik runtime dan alokasi memori executor harus membuktikan kasus tersebut.
  • Invarian mana yang mendefinisikan hasil yang ekuivalen? Minimal, tentukan total baris, unique events, ukuran bisnis aditif, baris unknown-key, baris unmatched, dan semantik duplikasi yang diizinkan.
  • Apakah hot key stabil dan dapat dienumerasi? Beberapa key yang stabil cocok untuk targeted salting. Long tail yang berubah-ubah lebih memilih AQE, deteksi hot-key dinamis, atau koreksi semantik di upstream.

Kerangka Jawaban 30 Detik

"Saya akan membandingkan shuffle read, spill, GC, dan lokasi retry dari join-task di SQL UI. Task berukuran 720 GiB berbanding median 1.1 GiB, ditambah 32% UNKNOWN, mendukung terjadinya key skew; saya juga akan memverifikasi keunikan dimensi untuk menyingkirkan output explosion. Pertama, saya akan memastikan bahwa AQE skew join memecah partisi besar tersebut. Jika runtime masih melebihi 45 menit, saya akan memberi salt pada UNKNOWN secara deterministik menggunakan event_id yang stabil dan hanya mereplikasi baris sentinel-nya. Terakhir, saya akan merekonsiliasi baris dan nominal dengan baseline, lalu membandingkan input task maks-ke-median, waktu stage, dan biaya."

Jawaban Mendalam Langkah demi Langkah

Langkah 1: Atribusikan 96 menit tersebut ke stage dan task tertentu

Simpan event log dan gunakan Spark History Server untuk membandingkan eksekusi normal dan regresi untuk tanggal data yang sama. Telusuri kueri SQL hingga ke rincian stage-nya. Catat persentil dan durasi task maksimum, diselaraskan dengan shuffle-read records dan bytes, shuffle spill, peak execution memory, waktu GC, alasan kegagalan, dan executor. Pada rencana SQL, periksa keberadaan Exchange hashpartitioning(product_id, 2000) sebelum left join, identifikasi physical join akhir, dan tentukan apakah adaptive plan berhasil diselesaikan.

Di sini, task yang sama tetap membaca sekitar 720 GiB setelah dicoba ulang pada executor lain, sementara sebagian besar task membaca sekitar 1.1 GiB. Hal itu mengarah langsung pada partisi input itu sendiri. Jika task yang lambat memiliki input biasa namun mengalami GC tinggi atau antrean disk pada satu executor, periksa nodenya terlebih dahulu. Jika setiap task mengalami spill secara seragam, fokuslah pada ukuran partisi secara keseluruhan dan alokasi sumber daya. Jika baris output berlipat ganda secara tiba-tiba, periksa duplikasi dimensi dan kondisi join.

Langkah 2: Buktikan penyebabnya dengan distribusi key dan kardinalitas join

Ukur hot key setelah menerapkan filter dan normalisasi key yang sama persis dengan yang digunakan di lingkungan produksi. Memeriksa kolom mentah saja tidak cukup karena trim, normalisasi huruf besar/kecil, coalesce, atau sebuah UDF dapat menyatukan beberapa nilai menjadi satu key. Pada tabel yang sangat besar, gunakan statistik yang ada, sampel terkontrol, atau agregasi terbatas agar proses diagnostik tidak menjadi job baru yang tidak terkendali. Kueri di bawah mengasumsikan bahwa tabel fakta telah berisi atau menghitung payload_bytes sebelumnya, memungkinkan pengukuran skew baris dan byte secara bersamaan. Tanpa kolom tersebut, gunakan statistik penyimpanan atau estimasi serialisasi terkontrol. Kueri ini mengekspresikan kalkulasi yang diperlukan:

sql
SELECT
  COALESCE(product_id, '<NULL>') AS join_key,
  COUNT(*) AS row_count,
  SUM(payload_bytes) AS payload_bytes
FROM fact_events
WHERE event_date = DATE '2026-07-17'
GROUP BY COALESCE(product_id, '<NULL>')
ORDER BY row_count DESC
LIMIT 20;

Buktikan juga bahwa setiap product_id muncul paling banyak satu kali di dimensi dan bandingkan jumlah fact-event sebelum dan sesudah join. Untuk left join ini, dimensi key yang unik berarti setiap fact event menghasilkan tepat satu baris, termasuk event yang unmatched. Jika UNKNOWN memegang 32% dari baris fakta, dimensi memiliki satu baris sentinel, dan output tidak berlipat ganda, hash partitioning menjelaskan keberadaan partisi tunggal berukuran 720 GiB tersebut.

Langkah 3: Tangani penyebab semantik sebelum memilih teknik eksekusi

Selidiki mengapa rilis upstream memetakan 32% event ke UNKNOWN. Jika itu adalah regresi, lakukan rollback atau perbaiki pemetaan tersebut dan jalankan ulang partisi yang terdampak. Langkah ini memulihkan kualitas data sekaligus performa. Jika itu adalah nilai bisnis yang valid, lapisan eksekusi harus mendukung distribusinya.

Event unknown yang valid dan tidak memerlukan atribut produk dapat mengambil jalur terpisah: join cold key secara normal, isi atribut dimensi dengan null untuk jalur unknown sesuai kontrak yang ada, lalu gabungkan dengan unionByName. Cara ini menghilangkan shuffle tanpa kehilangan informasi. Jika UNKNOWN harus cocok dengan atribut sentinel, pertahankan join dan bagi bebannya menggunakan AQE atau targeted salting. Semantik hasil menentukan percabangan; partisi yang seragam bukanlah alasan untuk membuang data.

Langkah 4: Pilih solusi berbiaya terendah yang berhasil

Periksa AQE terlebih dahulu. Di Spark 4.2.0, spark.sql.adaptive.enabled dan spark.sql.adaptive.skewJoin.enabled aktif secara default, tetapi klaster, job, atau managed platform dapat menimpanya (override). Faktor skew-join dan ambang batas byte absolut harus sama-sama terpenuhi. Periksa adaptive plan akhir untuk penanganan skew dan pastikan metrik stage menunjukkan bahwa partisi besar telah dipecah. Untuk sort-merge join yang kompatibel, AQE dapat membagi sisi yang besar dan mereplikasi sisi yang lebih kecil. AQE beradaptasi dengan perubahan distribusi harian, namun dapat menambah biaya shuffle dan replikasi, serta tidak dapat memperbaiki join many-to-many yang salah secara logika.

Jika dimensi yang diproyeksikan memiliki statistik yang andal dan ukurannya benar-benar kecil, evaluasi broadcast hash join sehingga sisi fakta tidak perlu melakukan shuffle pada join key. Ukuran asli 180 GB berada jauh di luar batas alokasi broadcast normal. Hint yang dipaksakan dapat menghabiskan memori setiap executor. Nilai projected bytes, concurrent tasks, executor heap, dan broadcast timeout secara bersamaan.

Ketika AQE tidak terpicu atau tetap tidak memenuhi SLA, lakukan salting secara manual pada hot key yang stabil. Kode berikut mengasumsikan bahwa event_id bersifat stabil dan unik, product_id unik di dimensi, dan hanya UNKNOWN yang perlu dipecah. Baris fakta yang panas dipetakan secara deterministik ke 32 salt. Hanya baris dimensi sentinel yang cocok yang direplikasi sebanyak 32 kali. Cold key tetap menggunakan salt 0, sehingga seluruh dimensi tidak pernah dilipatgandakan.

python
from pyspark.sql import functions as F

SALT_BUCKETS = 32
HOT_KEYS = ["UNKNOWN"]

events_salted = events.withColumn(
    "salt",
    F.when(
        F.col("product_id").isin(*HOT_KEYS),
        F.pmod(F.xxhash64("event_id"), F.lit(SALT_BUCKETS)).cast("int"),
    ).otherwise(F.lit(0)),
)

salt_values = spark.range(SALT_BUCKETS).select(
    F.col("id").cast("int").alias("salt")
)

products_hot = (
    products.filter(F.col("product_id").isin(*HOT_KEYS))
    .crossJoin(salt_values)
)
products_cold = (
    products.filter(~F.col("product_id").isin(*HOT_KEYS))
    .withColumn("salt", F.lit(0))
)
products_salted = products_cold.unionByName(products_hot)

result = (
    events_salted.join(products_salted, ["product_id", "salt"], "left")
    .drop("salt")
)

Tiga puluh dua adalah kandidat awal dalam skenario wawancara ini. Tentukan jumlah bucket dari ukuran byte hot-partition, target task size, paralelisme yang tersedia, dan biaya replikasi sisi kecil, lalu uji pada data representatif. Bucket yang terlalu sedikit akan menyisakan long tail. Terlalu banyak bucket menambah overhead penjadwalan, file, dan replikasi. Hanya menjalankan repartition(4000, "product_id") tetap menempatkan setiap baris UNKNOWN ke dalam satu partisi.

Untuk groupBy(product_id), biasanya tidak ada dimensi yang perlu direplikasi. Pertama, lakukan agregasi parsial berdasarkan (product_id, salt), lalu gabungkan (merge) hasil parsial tersebut berdasarkan product_id. Operasi yang dapat diuraikan secara aman dengan associative dan commutative merges, seperti sum, count, min, dan max, cocok dengan teknik ini. median yang presisi, agregasi yang bergantung pada urutan, dan state UDF yang tidak dapat di-merge memerlukan algoritma yang berbeda.

Langkah 5: Satukan kebenaran, performa, dan biaya dalam satu acceptance gate

Jalankan baseline dan kandidat solusi terhadap satu snapshot input yang tidak berubah (immutable). Kebenaran data adalah yang utama: bandingkan total output rows, unique event_id, UNKNOWN rows, baris unmatched, serta sum dan count bisnis berdasarkan dimensi yang bermakna. Ambil diff tingkat baris untuk hot keys, cold keys, nulls, dan duplicate dimension keys. Jaminan bahwa satu fact event menghasilkan satu baris left-join bergantung pada keunikan dimension-key, jadi pantau batasan tersebut secara terpisah.

Untuk performa, bandingkan p50, p95, dan durasi task maksimum pada stage join, shuffle read maks-ke-median, spill, GC, OOM, task retries, waktu stage, dan total runtime. Untuk biaya, catat executor-hours, shuffle bytes, dan jumlah output file. Selesai dalam 45 menit hanyalah salah satu kriteria. Eksekusi yang memenuhi SLA dengan melipatgandakan shuffle, mengubah hasil, atau gagal pada hotspot baru keesokan harinya tidak dapat diterima.

Lakukan rilis dengan memutar ulang (replay) satu tanggal historis, lalu lakukan shadowing pada data tanggal baru dan bandingkan hasilnya. Pantau kumpulan hot-key, rasio input task maks-ke-median, dan proporsi unknown-key. Lonjakan ke 32% UNKNOWN setelah rilis upstream juga harus memicu alert data-quality, mengekspos regresi semantik tersebut sebelum menunda jalannya job.

Contoh Jawaban Berkualitas Tinggi

"Pertama-tama, saya akan mengatribusikan regresi tersebut ke stage join tertentu di SQL UI. Bukti saat ini sangat mengindikasikan terjadinya skew: di antara 2.000 task, median shuffle read adalah 1.1 GiB, satu task membaca 720 GiB, dan task tersebut tetap lambat setelah berpindah ke executor lain. Saya akan memeriksa adaptive plan akhir, spill, dan GC, lalu memprofiling key setelah menerapkan normalisasi produksi yang tepat. Saya juga akan memastikan keunikan dimension-key. Adanya beberapa baris dimensi UNKNOWN berarti gejalanya mencakup join-output explosion.

Dengan asumsi dimensi yang unik dan 32% baris fakta UNKNOWN, satu hash-shuffle bucket menjelaskan adanya straggler tersebut. Menambah partisi akan membuat bucket tambahan tetapi tidak membagi key tersebut, dan menambah memori executor hanya menunda OOM. Pertama-tama saya akan menentukan apakah pemetaan upstream merupakan sebuah regresi. Jika baris unknown tidak memerlukan atribut dimensi, saya akan memisahkannya dari join dan mengisi atribut null dengan semantik left-join asli. Jika harus cocok dengan baris sentinel, saya akan memverifikasi bahwa AQE skew join benar-benar muncul dalam rencana akhir karena fitur tersebut dapat membagi partisi sort-merge-join yang skew menggunakan statistik runtime dan mereplikasi sisi yang kecil.

Jika AQE masih menyisakan runtime di atas 45 menit, saya akan menggunakan targeted salting. event_id yang stabil akan memetakan setiap baris fakta UNKNOWN secara deterministik ke, misalnya, salah satu dari 32 salt. Saya hanya akan mereplikasi baris UNKNOWN pada dimensi di 32 salt tersebut; setiap cold key akan menggunakan salt 0. Setiap event tetap cocok dengan satu baris dimensi, sementara beban kerja hot-key dibagi ke beberapa task. Saya akan menentukan jumlah bucket akhir dari ukuran byte hotspot dan target task size, alih-alih melakukan hard-coding angka 32 tanpa pengukuran.

Untuk validasi, saya akan membandingkan input immutable yang sama terhadap baseline. Total baris, unique events, record unknown dan unmatched, serta nominal bisnis harus sesuai. Kemudian saya akan membandingkan shuffle read maks-ke-median, tail durasi task, spill, OOM, waktu stage, executor-hours, dan output file. Terakhir, saya akan melakukan replay satu tanggal historis, shadowing satu tanggal baru, dan memasang alert untuk proporsi unknown-key serta hotspot baru. Hal ini membuktikan bahwa job memenuhi batas 45 menit, menjaga kebenaran hasil, dan tetap terpantau (observable) ketika distribusi upstream berubah lagi."

Kesalahan Umum

  • Langsung menaikkan shuffle partition dari 2.000 menjadi 8.000 → satu hot key tetap masuk ke satu partisi sementara task lain menjadi lebih kecil → ukur distribusi key, lalu pecah key tersebut menggunakan AQE, semantic branching, atau targeted salting.
  • Hanya menambah memori executor → ini meningkatkan toleransi satu task tetapi membiarkan beban kerja 720 GiB dan long tail tetap ada → kurangi beban kerja partisi maksimum terlebih dahulu, lalu sesuaikan alokasi sumber daya berdasarkan pengukuran task.
  • Menyimpulkan skew hanya karena melihat satu task yang lambat → node yang bermasalah, GC, remote fetch, atau UDF yang lambat juga dapat menciptakan straggler → bandingkan input task, lokasi retry, spill, GC, dan rencana eksekusi.
  • Melakukan salting acak pada fakta dan dimensi secara terpisah → salt gagal cocok dan menghilangkan hasil join, sementara retries bisa menjadi nondeterministik → buat salt fakta dari ID baris yang stabil dan enumerasikan salt yang sama pada dimensi.
  • Mereplikasi seluruh dimensi sebanyak 32 kali → dimensi 180 GB menciptakan beban jaringan dan memori yang sangat besar → replikasi hanya baris hot-key yang terkonfirmasi dan biarkan cold key pada salt 0.
  • Memaksa dimensi 180 GB untuk di-broadcast → setiap executor harus menampung data broadcast dan dapat gagal karena OOM → lakukan proyeksi dan pengukuran terlebih dahulu; broadcast hanya setelah alokasi memori dan konkurensi terbukti aman.
  • Memfilter UNKNOWN agar job berjalan cepat → semantik output dan metrik di downstream berubah → tetapkan kontrak unknown-event dan pertahankan hasil left-join meskipun melakukan branching.
  • Hanya membandingkan total runtime → peningkatan kecepatan yang terlihat bisa jadi disebabkan oleh data yang terbuang, terduplikasi, atau salah hitung → buktikan invarian baris dan bisnis sebelum membandingkan distribusi task, biaya, dan SLA.

Pertanyaan Lanjutan dan Cara Menjawabnya

AQE aktif. Mengapa skewed join tidak dipecah?

Periksa adaptive plan akhir dan pengaturan efektif untuk spark.sql.adaptive.enabled, switch skew-join, ambang batas faktor median, dan ambang batas byte absolut. Kedua ambang batas tersebut harus terpenuhi. Pastikan physical join mengikuti jalur AQE yang didukung, statistik runtime tersedia, serta tidak ada hint atau platform override yang membatasi rencana. Uji perubahan ambang batas atau optimasi skew yang dipaksakan pada data representatif sambil mengukur shuffle tambahan. Jika rencana tidak dapat memanfaatkannya, gunakan targeted salting. Nilai true dalam file konfigurasi tidak membuktikan bahwa rencana yang dieksekusi benar-benar memecah partisi.

Jika proyeksi mengurangi dimensi menjadi 6 GiB, bisakah Anda mem-broadcast-nya?

Ukuran 6 GiB masih memerlukan penilaian terhadap executor-heap, concurrent-task, serialized-size, broadcast-timeout, dan stabilitas klaster. Broadcast dapat menghilangkan join-key shuffle pada sisi besar sehingga menghindari hotspot, tetapi broadcast juga menyalin dimensi ke executor. Gunakan statistik untuk membuktikan ukuran byte sebenarnya, lalu amati peak memory dan GC dalam load test berskala produksi sebelum menambahkan hint. "Jauh lebih kecil dari tabel fakta" bukanlah kriteria broadcast yang cukup.

Bagaimana jika hot key berubah setiap hari dan HOT_KEYS tidak dapat dikelola secara manual?

Utamakan respons runtime AQE. Jika explicit salting tetap diperlukan, buat tabel hot-key terbatas sebelum job utama menggunakan ambang batas record, byte, atau biaya, lalu broadcast tabel kecil tersebut untuk memilih jalur salting. Beri versi pada daftar berdasarkan tanggal data dan terapkan ambang batas, batas jumlah, serta fallback. Pendekatan ini menambah tahap perencanaan dan operational state, sehingga peningkatan SLA yang stabil harus sebanding dengan kompleksitasnya.

Jika operasi yang lambat adalah groupBy, apakah Anda masih mereplikasi dimensi?

Tidak. Untuk agregasi yang dapat di-merge, beri salt pada baris yang panas, hitung partial aggregate berdasarkan (key, salt), lalu gabungkan hasil parsial tersebut berdasarkan key. Langkah ini mendistribusikan input dari satu hot key ke berbagai task, sementara stage kedua memproses sejumlah kecil hasil parsial. Jelaskan apakah agregasi tersebut dapat di-merge dengan aman. State yang diurutkan secara global atau tidak dapat di-merge tidak dapat menggunakan teknik ini tanpa algoritma yang berbeda.

Bagaimana Anda memilih 32 bucket salt?

Bagi byte hot-partition dengan target task input untuk mendapatkan batas bawah (lower bound), lalu pertimbangkan core yang tersedia, replikasi sisi kecil, overhead scheduler, dan batasan output file. Jika 720 GiB harus diturunkan menjadi sekitar 32 GiB per task, batas bawah teoretisnya adalah sekitar 23, sehingga 32 adalah eksperimen yang masuk akal dalam skenario ini. Bandingkan beberapa kandidat berdasarkan input task maksimum, waktu stage, dan executor-hours, serta sisakan sedikit ruang (headroom) untuk pertumbuhan hotspot.

Bisakah speculative execution menyelesaikan straggler ini?

Duplikat dari task yang mengalami skew deterministik tetap akan membaca partisi 720 GiB yang sama, yang biasanya mengulang pekerjaan berat pada dua executor. Spekulasi lebih berguna untuk node yang melambat sesekali atau transient jitter. Periksa apakah task yang sama tetap lambat setelah dicoba ulang di tempat lain. Jika inputnya tetap menjadi outlier, pecah beban kerja datanya, jangan menduplikasinya.

Sumber publik

Pertanyaan terkait