Berkenalan dengan Akka Stream

Apa itu Akka Stream

Harimurti Prasetio
Pujangga Teknologi
5 min readAug 25, 2019

--

Akka Stream adalah pustaka streaming processing yang dibangun di atas Akka, memungkinkan developer mengonsumsi atau memproduksi data secara streaming, dengan risiko out-of-memory sekecil mungkin menggunakan mekanisme backpressure. Akka Stream juga menawarkan API yang beragam, memungkinkan developer melakukan transformasi elemen, melakukan operasi yang bergantung dengan waktu, dan lain-lain namun tetap type-safe.

Melalui artikel ini penulis berusaha memperkenalkan Akka Stream sebagai salah satu alternatif pustaka streaming processing di Scala, maupun di JVM.

Akka Stream, layaknya memasang pipa air di rumah

Bicara mengenai Akka Stream developer akan menemui 3 komponen dasar pembangun stream: Source, Flow, dan Sink. Secara sederhana, 3 komponen tersebut adalah :

  • Source[T, M] berperan sebagai sumber elemen (operator dengan 1 jalur output tanpa input),
  • Sink[T, M] berperan sebagai tujuan akhir elemen (operator dengan 1 jalur input tanpa output),
  • dan Flow[T1, T2, M] berperan sebagai jalur antara Source dan Sink (operator dengan tepat 1 jalur input dan output).

Ketika Source, Flow, dan Sink sudah terangkai, rangkaian ini menjadi cetak biru pemrosesan data; ia belum melakukan sebuah proses atau mengonsumsi sumber daya tertentu yang disebut RunnableGraph[M]. Hanya dengan memanggil metode .run() pada RunnableGraph data mulai mengalir dan diproses. Penulis sering mengibaratkan barisan kode yang menyusun cetak biru ini sebagai proses merangkai pipa serta knop maupun keran di dalam rumah dan barisan kode yang memanggil .run() sebagai kegiatan mengaktifkan pompa air yang akan mengairi rangkaian pipa tersebut.

Di bawah ini adalah contoh RunnableGraph yang menerima input list integer 0 sampai 10, menambahkan tiap angka dengan 5, dan menjumlahkan semua angka tersebut sebagai hasil akhir.

Source(0 to 10).map(_ + 5).to(Sink.fold(0)(_ + _)).run()

Dalam terminologi Akka Stream, proses pengaktifan rangkaian ini disebut sebagai stream materialization. Proses materialisasi ini akan menyebabkan operator-operator di dalam RunnableGraph bekerja untuk setiap elemen yang lewat dan ketika operasi eksekusi elemen-elemen yang lewat teresebut sukses, sebuah nilai akhir yang type nya sama dengan type parameter RunnableGraph terkait dihasilkan jika stream sukses, atau exception jika stream mengalami kegagalan.

Penanganan kegagalan pada Akka Stream

Layaknya semua hal di dunia perangkat lunak, apa pun yang bisa gagal, maka akan gagal. Begitu pula dengan stream yang aktif. Secara terminologi, Akka Stream membagi 2 semantik kesalahan yang mungkin muncul selama keberlangsungan proses: error dan failure. Akka Stream menganut definisi failure berdasarkan yang tertera di Reactive Manifesto: kejadian di dalam sebuah layanan / aplikasi yang membuat layanan tersebut berjalan dengan normal. Di sisi lain, error adalah kondisi layanan di luar skenario bahagia yang bisa jadi ditemui oleh layanan tersebut dan memang sudah diekspektasi untuk terjadi. Contoh failure adalah habisnya sumber daya mesin, rusaknya hardware, dan lain-lain. Untuk error, salah satu contohnya adalah kesalahan input, ketiadaan file dengan nama tertentu, dan lain-lain. Kejadian munculnya failure bisa jadi mengurangi sebagian atau keseluruan kapabilitas layanan, akan tetapi kemunculan error tidak boleh mengurangi kemampuan layanan.

Berdasarkan hal ini, Akka Stream memberikan perlakukan yang berbeda antara error dan failure. Error dianggap sebagai layaknya elemen biasa pada stream, sedangkan failure akan menyebabkan stream berhenti dan dihancurkan oleh materializer tanpa menghasilkan nilai materialisasi. Berhentinya stream karena failure merupakan hal yang tidak diinginkan, oleh karena itu Akka Stream memiliki seperangkat API yang memungkinkan developer mengubah failure pada salah satu atau beberapa stage di stream menjadi elemen biasa atau mengabaikan failure tersebut agak stream tetap berjalan normal.

Jaminan penghantaran elemen pada Akka Stream

Sebagai sebuah pustaka yang menawarkan solusi data bergerak, bagaimana Akka Stream menggerakkan data dari satu tempat ke tempat lain menjadi krusial. Akka Stream menjelaskan bahwa :

  • selama tidak ada penjelasan khusus, urutan elemen yang masuk pada sebuah operator menentukan urutan keluar.
  • elemen bisa jadi ‘menghilang’ dari stream karena semantik operator atau kegagalan. Misal, karena operator map() bisa jadi mengubah elemen A menjadi A’, operator filter() menghilangkan elemen B karena elemen B tidak memenuhi predikat, atau karena adanya failure di stream. Namun, secara teori jika sebuah stream hanya memproduksi elemen tanpa melakukan apa pun terhadap elemen yang dihasilkan, bisa dibilang tidak akan ada elemen yang hilang kecuali jika stream mengalami kegagalan atau pembatalan.
  • karena efek dari back-pressure, Source atau sumber elemen bisa jadi menghilangkan elemen yang ia produksi karena sisi hilirnya tidak memberikan sinyal siap untuk menerima elemen.

Karakteristik lain Akka Stream

Back-pressure

Mekanisme kontrol aliran elemen pada stream yang memungkinkan sisi hulu memperlambat laju produksi elemen ketika sisi hilir mengalami perlambatan dalam mengonsumsi elemen yang datang. Keberadaan mekanisme back-pressure ini yang memungkinkan Akka Stream ramah memori walaupun dengan cara mengorbankan througput sistem.

Non-blocking

Operator pada stream tidak menghalangi keberjalanan thread pemanggil.

Composable

Di bagian awal sempat disebutkan bahwa menyusun RunnableGraph bisa dianggap seperti menyusun pipa air. Ini dapat diterjemahkan bahwa Source, Sink, maupun Flow dapat disusun untuk membuat Source, Sink, dan Flow baru. Berikut merupakan contoh-contohnya.

Gambar 1. RunnableGraph dari Source, Flow, dan Sink biasa.

Gambar 1 menunjukkan skema rangkaian operator yang hanya menggunakan Source, Flow, dan Sink biasa. Contoh kode yang memiliki skema seperti ini:

val runnableGraph = Source(List(1,2,3))
.filter(_ > 1)
.to(Sink.foreach(println))
Gambar 2. RunnableGraph dari Source dan Sink biasa.

Gambar 2 menunjukkan skema rangkaian operator dengan Source dan Sink saja. Contoh kode:

val runnableGraph = 
Source(10 to 20)
.to(Sink.fold(0)(_ + _))
Gambar 3. RunnableGraph dari CompositeSource, CompositeFlow, dan Sink biasa.

Gambar 3 menunjukkan skema rangkaian operator yang menggunakan Source turunan, Flow turunan, serta Sink. Contoh kode:

val source = Source(0 to 50).map(_ * 2)
val flow = Flow[Int]
.throttle(3, 3.seconds)
.groupedWithin(5, 3.seconds)
val sink = Sink.ignore
val runnableGraph = source.via(flow).to(sink)
Gambar 4. RunnableGraph dari Source, Flow, dan CompositeSink.

Gambar 4 menunjukkan skema rangkaian operator yang menggunakan Source dan Flow biasa namun Sink gabungan. Contoh kode:

val pathToFile = Paths
.get("/Users/john/Downloads/file.txt")
val sink = Flow[String]
.map(ByteString)
.intersperse(ByteString("\\n"))
.to(FileIO.toFile(Paths.get()))
val runnableGraph = Source
.cycle(wordsIterator)
.map(str => str.toLowerCase)
.to(sink)

Contoh penggunaan Akka Stream

Ok, jadi Akka Stream bisa digunakan untuk apa saja?

Menurut penulis, selama permasalahan yang dihadapai (1) dapat dimodelkan dengan elemen bergerak,(2) memiliki variasi debit per satuan waktu di tingkat-tingkat pemrosesan tertentu, dan (3) memiliki batasan jumlah sumber daya memori yang diberikan, Akka Stream akan memberikan efek positif terhadap penyelesaian masalah tersebut. Contohnya adalah pemrosesan file csv bergiga-giga, menangani upload file ukuran besar, streaming http endpoint, penulisan periodik dari Kafka ke HDFS, dan lain-lain.

Berikut adalah halaman demo yang menunjukkan penggunaan Akka Stream: http://68.183.186.254:9873/. Atau jika ingin menggunakan shell, silahkan ketikkan perintah berikut: curl -vvv http://68.183.186.254:9873/json

Alternatif pustaka streaming processing

Selain Akka Stream, pustaka lain yang menawarkan kemampuan serupa antara lain fs2, vert.x, Spark Streaming, dan Apache Flink.

Sekian penjelasan singkat mengenai Akka Stream. Materi di artikel ini hanya menyarikan sebagian isi dari link ini yang penulis anggap awalan dalam mendalami Akka Stream. Jika ada saran atau kritik terhadap isi artikel, silahkan komentar langsung di bawah artikel ini.

--

--