Berkenalan Dengan Libuv, Inti Dalam Node
Masa Sebelum Node
Jika kalian mengingat masa-masa sebelum Node mulai populer dan dipakai dimana-mana, maka pasti kalian tidak asing dengan Apache dan Nginx. Keduanya merupakan server HTTP yang populer dengan kelebihannya masing-masing.
Apache bekerja dengan menjalankan proses utama yang nantinya bisa membuat subproses lagi. Setiap subproses ini bisa membuat thread yang akan menangani permintaan yang masuk.
Pembuatan subproses dan thread ini bukanlah sesuatu yang ringan secara sumber daya. Jika setiap subproses dan thread ini memuat sesuatu yang besar seperti call stack, heap allocation, dan sebagainya. Maka penggunaan subproses dan thread sangat terbatas dengan software dan hardware yang mendukungnya.
Karena keterbatasan ini, ada istilah masalah C10k — masalah yang terjadi ketika suatu sistem harus menangani 10.000 koneksi secara simultan. Karena masalah inilah, Nginx dibuat.
Nginx mempunyai cara kerja yang berbeda dengan Apache. Nginx didesain dengan fokus kepada penggunaan memori yang rendah dan kemampuan konkurensi yang tinggi.
Nginx bekerja dengan konsep Reaktor. Pada dasarnya, Nginx bekerja di satu thread, tetapi bisa membuat beberapa proses untuk memanfaatkan hardware multicore. Thread utama bekerja sebagai event loop, yang menunggu sinyal dari OS untuk event seperti adanya data yang masuk ke sebuah socket.
Karena Nginx hanya memanfaatkan satu thread, maka Nginx bisa menghindari masalah yang terjadi ketika sebuah thread harus menggunakan sumber daya yang besar.
Konsep event loop inilah yang nantinya juga ada di Node.
Node dan Event Loop
Node menerapkan konsep event loop seperti yang digunakan di Nginx. Di dalam, Node juga menggunakan V8; JavaScript Engine yang digunakan Google Chrome. V8 sendiri menggunakan konsep event loop. Sehingga bisa dikatakan Node mempunyai dua event loop, di V8 untuk runtime JavaScript; di Node sendiri untuk kebutuhan memanggil fungsi internal node.
Tetapi, bagaimana bentuk event loop dan seperti apa cara kerjanya? Event loop, dalam bentuk paling simple, adalah sebuah proses looping terus menerus.
Bentuk sederhana dari sebuah event loop.Tapi event loop se-sederhana ini tidak akan berguna untuk apa-apa. Dinamakan event loop karena di dalamnya, dia akan memproses event yang ada.
Event loop bekerja selama ada event untuk diproses.Di Node, event loop yang ada lebih kompleks. Seperti dijelaskan di dokumentasi resmi mereka — Event loop di Node kurang lebih terlihat seperti berikut.
Proses yang dilakukan di dalam event loop Node.
Jika kalian ingin mencoba simulasi event loop, kalian bisa mencobanya di http://latentflip.com/loupe yang dibuat oleh Philip Roberts. Kalian juga bisa melihat video penjelasan event loop di sini.
Karena desain arsitektur seperti ini lah, Node menyebut dirinya sebagai “asynchronous event driven JavaScript runtime”. Dengan desain seperti ini, Node bisa bebas dari deadlock karena tidak ada mekanisme locking yang sering dilakukan di arsitektur multithreading.
Dan event loop yang digunakan Node ini, disediakan oleh library yang bernama Libuv.
Mengenal Libuv
Logo LibuvUntuk mengutip dari situs resmi Libuv. Libuv adalah library multi-platform yang di desain untuk I/O asinkronus. Pertama kali dikembangkan untuk digunakan oleh Node, tapi sekarang juga digunakan oleh Luvit, Julia, pyuv, dan lain-lain.
Jika kalian penasaran kenapa namanya Libuv, UV dari Libuv adalah Unicorn Velociraptor — sesuai logonya.
Libuv inilah yang menyediakan fungsionalitas event loop yang digunakan Node. Selain dasar dari event loop, Libuv juga menyediakan API untuk filesystem dan networking.
Dalam bentuk paling sederhana, code yang menggunakan Libuv terlihat seperti di bawah. Karena Libuv ditulis menggunakan C, maka kita akan menggunakan C juga di tulisan ini.
Node pada dasarnya adalah binding Libuv di atas JavaScript — seperti kutipan yang ada di situs Libuv; “Node is libuv with a very well known client language.”
Event loop sederhana menggunakan Libuv.Untuk belajar menggunakan Libuv, mari kita mencoba membuat sebuah aplikasi sederhana untuk melakukan request HTTP ke numbersapi.com.
HTTP Client Menggunakan Libuv
Jika kalian masih asing dengan C/C++, mungkin akan sedikit kesulitan ketika melakukan konfigurasi build system di C.
Langkah pertama adalah memasang Libuv, ikutan panduan yang ada di GitHub Libuv — untuk proses pemasangan sesuai dengan OS kalian. Dalam kasus ini saya menggunakan OSX, dan menjalankan perintah ini.
$ sh autogen.sh
$ ./configure
$ make
$ make check
$ make install
Setelah itu, maka Libuv akan terpasang di mesin saya. Langkah selanjutnya adalah membuat project C yang akan menggunakan Libuv. Konfigurasi CMake supaya memuat header Libuv dan juga menggunakan library Libuv.
CMake Konfigurasi Libuv.Proses dari aplikasi ini, sesuai dengan aturan Libuv:
- Inisialisasi event loop
- Buka koneksi TCP ke numbersapi.com
- Kirim HTTP request header di stream TCP
- Tunggu HTTP response di stream TCP
Berdasarkan proses di atas, kode yang kita hasilkan akan terlihat seperti ini.
Source code HTTP client menggunakan Libuv.Aplikasi akan menghasilkan angka acak yang akan dikirimkan ke numbersapi.com dan menampilkan balasan dari numbersapi.com.
Tampilan output aplikasi di CLion.Konsep event loop di Libuv sama seperti konsep event loop di Node, sehingga seharusnya kita tidak terlalu kesulitan untuk memahami konsep callback dan asinkroni yang ada.
Kesimpulan
Libuv merupakan library yang sangat membantu kita jika kita ingin asinkroni dalam bentuk event loop. Terutama jika kita ada di lingkungan terbatas dan tidak bisa menggunakan platform high level seperti Node.
Semoga dengan tulisan ini kalian lebih mengenal tentang event loop di Node, dan library Libuv yang menjadi inti dari event loop tersebut.
Jika kalian ingin mempelajari lebih lanjut tentang Libuv, buka situs resminya di https://libuv.org/.