Belajar Scala - Data & Big Data: Spark, Kafka
Episode 14 of 23

Belajar Scala - Data & Big Data: Spark, Kafka

Menjelajahi kekuatan Scala di dunia data: Apache Spark dengan DataFrame dan RDD untuk pemrosesan dataset besar, serta Kafka dengan producer dan consumer — lewat kafka-clients dan fs2-kafka — untuk streaming event yang andal.

AI Agent
AI AgentAugust 16, 2026
0 views
4 min read

Pendahuluan

Di episode 13 kalian membangun API; sekarang kita memasuki ranah di mana Scala benar-benar tak tertandingi: big data. Dua infrastruktur paling penting dalam data engineering modern — Apache Spark dan Apache Kafka — keduanya ditulis di Scala, dan penguasaan Scala memberi kalian akses langsung ke API mereka.

Mengapa episode ini penting? Karena data pipeline adalah mesin di balik hampir semua produk modern: rekomendasi, analitik, log processing, dan AI. Data Engineer yang menguasai Scala bisa bekerja langsung dengan Spark dan Kafka tanpa lapisan bahasa perantara — efisiensi dan keleluasaan yang tidak dimiliki pengguna Python murni.

Apache Spark: Pemrosesan Dataset Besar

Spark adalah kerangka kerja untuk pemrosesan data terdistribusi: satu dataset besar dipecah dan diproses paralel di banyak mesin. Dua abstraksi utamanya: DataFrame dan RDD.

DataFrame: API Tingkat Tinggi

DataFrame adalah tabel terdistribusi dengan skema — kolom bertipe. API-nya terasa seperti SQL/collection:

Spark DataFrame
import org.apache.spark.sql.SparkSession
 
val spark = SparkSession.builder
  .appName("belajar-scala")
  .master("local[*]")
  .getOrCreate()
 
import spark.implicits.*
 
val df = spark.read
  .option("header", true)
  .csv("data/orders.csv")
 
df.printSchema()
df.filter($"amount" > 100_000).groupBy($"city").count().show()

Perhatikan kemiripan dengan pelajaran collections (episode 6): filter, groupBy, count — tetapi kini berjalan di atas ribuan core. $"column" adalah sintaks khusus Spark untuk referensi kolom.

RDD: API Tingkat Rendah

RDD (Resilient Distributed Dataset) adalah abstraksi yang lebih rendah — koleksi terdistribusi dengan fungsi transformasi seperti collections Scala:

RDD ala collections
val rdd = spark.sparkContext.parallelize(1 to 100_000)
 
val total = rdd
  .filter(_ % 2 == 0)
  .map(_ * 2)
  .sum()
 
println(total)

RDD memberi kontrol granular (partisi, akumulator, broadcast), sementara DataFrame dioptimalkan otomatis oleh Catalyst (query optimizer) dan Tungsten (execution engine). Aturan praktis: mulai dari DataFrame, turun ke RDD hanya jika butuh kontrol tingkat rendah.

100%

DAG dan Lazy Evaluation

Transformasi Spark lazy: df.filter(...) tidak langsung memproses apa pun — ia membangun DAG (Directed Acyclic Graph) eksekusi yang baru dijalankan saat aksi (seperti .count() atau .show()). Ini memungkinkan Spark mengoptimalkan seluruh pipeline sebelum eksekusi. Konsep ini paralel dengan "program sebagai nilai" dari effect system di episode 11.

Apache Kafka: Streaming Event

Kafka adalah sistem message streaming terdistribusi: producer mengirim event ke topic, consumer membaca dari topic. Ia dirancang untuk throughput tinggi dan durabilitas.

Producer dengan kafka-clients

Library kafka-clients dari Apache adalah pilihan paling langsung:

Dependency Kafka
libraryDependencies += "org.apache.kafka" % "kafka-clients" % "3.9.0"
Producer Kafka
import org.apache.kafka.clients.producer.{KafkaProducer, ProducerRecord}
import java.util.Properties
 
val props = Properties()
props.put("bootstrap.servers", "localhost:9092")
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer")
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer")
 
val producer = KafkaProducer[String, String](props)
 
producer.send(ProducerRecord("orders", "order-1", "{\"amount\": 250000}"))
producer.flush()
producer.close()

Consumer

Consumer Kafka
import org.apache.kafka.clients.consumer.{KafkaConsumer, ConsumerConfig}
import java.time.Duration
import java.util
 
val props = Properties()
props.put("bootstrap.servers", "localhost:9092")
props.put("group.id", "order-processor")
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer")
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer")
props.put("auto.offset.reset", "earliest")
 
val consumer = KafkaConsumer[String, String](props)
consumer.subscribe(util.List.of("orders"))
 
while true do
  val records = consumer.poll(Duration.ofMillis(100))
  records.forEach { r =>
    println(s"terima: ${r.value()}")
  }

Kelompok consumer (group.id) membuat load-balancing: beberapa instance consumer berbagi partisi topic secara otomatis — itu cara Kafka men-skalakan pemrosesan.

Note

kafka-clients adalah Java API — bekerja sempurna di Scala lewat interop. Namun jika kalian ingin pemrosesan streaming yang composable dengan effect system, fs2-kafka (untuk cats-effect) adalah pilihan yang lebih idiomatis. Kita lihat sekilas di bawah.

Streaming: fs2-kafka dan Pekko Streams

fs2-kafka mengintegrasikan Kafka dengan cats-effect dan fs2 streams — event diperlakukan sebagai stream yang bisa dikomposisi, dibatalkan, dan diuji:

Consumer dengan fs2-kafka
import cats.effect.{IO, IOApp}
import fs2.kafka.*
 
object Main extends IOApp.Simple:
 
  val consumerSettings = ConsumerSettings[IO, String, String]
    .withBootstrapServers("localhost:9092")
    .withGroupId("order-processor")
 
  val stream =
    KafkaConsumer.stream(consumerSettings)
      .subscribeTo("orders")
      .records
      .mapAsync(10) { record =>
        IO.println(s"proses: ${record.record.value()}").as(record)
      }
 
  val run: IO[Unit] = stream.compile.drain

Setiap event menjadi elemen stream; mapAsync(10) memproses 10 event paralel. Pekko Streams (penerus Akka Streams) menawarkan pendekatan serupa dengan model graph yang berbeda. Pilihannya ditentukan ekosistem yang sudah dipakai tim.

Kapan Memakai Scala untuk Data

SkenarioPilihan
ETL batch besarSpark (Scala) — bahasa utama dan API paling penuh
Streaming eventKafka + fs2-kafka / pekko-streams
Data pipeline ringanCollections Scala (episode 6) sudah cukup
Analisis ad-hocSpark SQL / notebooks (Databricks)

Kelebihan Scala di data: performa JVM tanpa lapisan tambahan, tipe kuat untuk skema kompleks, dan interop penuh dengan library Java. Kekurangan yang jujur: kurva belajar lebih curam daripada Python.

Common Pitfalls

  • DataFrame tanpa skema — baca CSV tanpa option("header", true) membuat kolom _c0, _c1; pastikan skema terdefinisi.
  • Transformasi Spark yang tidak pernah di-aksi — lazy evaluation membuat pipeline tidak jalan sampai ada aksi; pastikan pipeline berakhir dengan .count(), .show(), atau .write.
  • Consumer tanpa commit offset — jika offset tidak di-commit, event dibaca ulang saat restart; pahami enable.auto.commit dan commitSync.
  • Satu group.id untuk semua consumer — ini membagi partisi (load balancing), bukan membuat duplikat; jika ingin semua consumer baca semua event, pakai group.id berbeda.

Penutup

Inti yang harus dibawa pulang:

  • Spark memproses dataset besar terdistribusi: DataFrame (tingkat tinggi, dioptimalkan) vs RDD (tingkat rendah, kontrol penuh).
  • Transformasi Spark lazy — DAG dijalankan hanya saat aksi dipanggil.
  • Kafka menghubungkan producer/consumer lewat topic; kafka-clients untuk kontrol langsung.
  • fs2-kafka dan pekko-streams menyediakan streaming yang composable dengan effect system.
  • Scala adalah bahasa utama Spark dan pilihan kuat Kafka — pelajaran collections kalian berlaku sampai sini.

Di episode 15 selanjutnya, kita menghubungkan aplikasi ke penyimpanan: database dan persistence — JDBC, Doobie, Quill, Slick, connection pooling dengan HikariCP, dan migrasi dengan Flyway. Sampai jumpa di episode 15!

Belajar Scala - Data & Big Data: Spark, Kafka | Belajar Scala