Back to IF4031 Arsitektur Aplikasi Terdistribusi
Topic
Questions/Cues
Apa itu ‘C10K Problem’?
Strategi awal menangani banyak klien?
Kenapa 1 proses/thread per klien itu buruk?
Apa itu aplikasi ‘I/O Bound’?
Apa 5 model I/O?
Apa 2 fase dalam operasi I/O?
Bagaimana cara kerja Blocking I/O?
Apa beda Non-blocking dengan Blocking I/O?
Apa itu I/O Multiplexing?
Beda Signal-driven dan Asynchronous I/O?
Reference Points
Slides IF4031 Hal 3-17
C10K Problem
Ini adalah tantangan klasik dalam desain server: Bagaimana merancang sebuah server yang mampu menangani 10.000 koneksi klien secara bersamaan (concurrent)?
Masalah utamanya bukan pada hardware, melainkan pada bagaimana OS dan arsitektur software menangani konkurensi. Beberapa kendala utamanya adalah:
Data copies: Penyalinan data antara kernel dan aplikasi.
Context switches: Biaya peralihan CPU dari satu proses/thread ke proses/thread lain.
Memory allocation: Alokasi memori untuk setiap koneksi.
Lock contention: Perebutan akses ke sumber daya bersama.
Strategi Awal: 1 Proses/Thread per Klien
Pendekatan paling intuitif adalah membuat satu unit eksekusi untuk setiap klien yang terhubung:
Satu Proses per Klien: Menggunakan
fork()untuk membuat proses anak baru setiap kali ada koneksi masuk.Satu Thread per Klien: Menggunakan
pthread_create()untuk membuat thread baru.Masalahnya: Pendekatan ini tidak scalable. Proses dan thread memakan sumber daya yang signifikan (misalnya, alokasi memori untuk stack). Dengan 10.000 koneksi, server bisa kehabisan memori. Selain itu, sebagian besar waktu, proses/thread ini tidak melakukan apa-apa selain menunggu data dari jaringan.
Karakteristik Aplikasi Jaringan: I/O Bound
Sebagian besar aplikasi server bersifat I/O Bound. Artinya, waktu eksekusi lebih banyak dihabiskan untuk menunggu operasi I/O (Input/Output) selesai (misalnya, membaca data dari socket, menulis ke disk) daripada melakukan komputasi di CPU. Karena itu, memblokir satu thread hanya untuk menunggu I/O adalah pemborosan sumber daya.
Lima Model I/O
Operasi input pada jaringan umumnya memiliki dua fase:
Waiting for data: Menunggu data siap di buffer kernel.
Copying data: Menyalin data dari buffer kernel ke buffer aplikasi.
Kelima model I/O ini menangani dua fase tersebut dengan cara yang berbeda.
1. Blocking I/O
Proses/thread terblokir (berhenti total) sejak pemanggilan
recvfromhingga data selesai disalin ke buffer aplikasi. Ini adalah model paling sederhana namun paling tidak efisien untuk konkurensi.2. Non-blocking I/O
Proses melakukan polling (bertanya berulang kali) pada kernel. Jika data belum siap, kernel langsung kembali dengan error
EWOULDBLOCK. Ini mencegah proses terblokir pada fase 1, tetapi fase 2 (penyalinan data) masih bersifat blocking. Polling terus-menerus ini memboroskan CPU.3. I/O Multiplexing
Proses menggunakan satu panggilan sistem (seperti
selectataupoll) untuk memonitor banyak socket sekaligus. Proses akan terblokir pada panggilanselectini sampai setidaknya salah satu socket siap untuk I/O (fase 1 selesai). Setelah itu, proses memanggilrecvfrompada socket yang siap, di mana ia akan terblokir sebentar selama data disalin (fase 2). Ini memungkinkan satu thread menangani banyak koneksi.4. Signal-driven I/O
Proses memberitahu kernel untuk mengirimkan sinyal (SIGIO) ketika data sudah siap. Proses tidak terblokir dan bisa melakukan pekerjaan lain. Ketika sinyal diterima, signal handler akan dieksekusi untuk membaca data (dengan
recvfromyang bersifat blocking pada fase 2).5. Asynchronous I/O (AIO)
Ini adalah satu-satunya model yang benar-benar non-blocking. Proses memulai operasi I/O dan langsung melanjutkan pekerjaannya. Kernel akan menangani kedua fase di latar belakang. Setelah data selesai disalin ke buffer aplikasi, kernel akan memberikan notifikasi (misalnya, melalui sinyal atau callback) kepada proses.
Perbandingan Kelima Model:
Untuk mengatasi C10K Problem, arsitektur server naif yang menggunakan satu proses atau thread per klien tidaklah efisien karena borosnya sumber daya dan sifat aplikasi jaringan yang I/O bound. Solusinya terletak pada penggunaan model I/O yang lebih canggih. Model seperti I/O Multiplexing memungkinkan satu thread menangani banyak koneksi dengan cara menunggu event dari beberapa socket sekaligus, sementara Asynchronous I/O memberikan efisiensi tertinggi dengan mendelegasikan seluruh operasi I/O kepada kernel dan hanya menerima notifikasi saat operasi tersebut tuntas.
Additional Information
Pendalaman Teknis: Mahalnya Biaya Context Switch
Context Switch adalah proses yang dilakukan sistem operasi untuk mengalihkan CPU dari satu thread/proses ke yang lain. OS harus menyimpan seluruh konteks eksekusi (nilai register CPU, program counter, dll.) dari thread saat ini dan memuat konteks dari thread berikutnya. Proses ini, meskipun cepat, menjadi sangat signifikan jika terjadi ribuan kali per detik. Dengan 10.000 thread, server bisa menghabiskan sebagian besar waktunya hanya untuk context switching daripada melakukan pekerjaan yang produktif.
Perbedaan Kunci: Signal-driven vs. Asynchronous I/O
Perbedaan paling fundamental antara keduanya adalah kapan notifikasi diberikan:
Signal-driven I/O: Kernel memberitahu, “Hei, sekarang kamu sudah bisa memulai operasi baca, datanya sudah siap.”
Asynchronous I/O: Kernel memberitahu, “Hei, operasi baca yang kamu minta sudah selesai, datanya sudah ada di buffermu.”
Sumber & Referensi Lanjutan:
Buku: “UNIX Network Programming, Volume 1: The Sockets Networking API” oleh W. Richard Stevens. Buku ini adalah referensi definitif untuk pemrograman jaringan di lingkungan UNIX dan merupakan sumber asli dari diagram-diagram kelima model I/O.
Artikel Asli C10K: Baca tulisan Dan Kegel tentang “The C10K problem” untuk melihat perspektif historis dan berbagai solusi yang diusulkan pada masanya.
Proses/thread terblokir (berhenti total) sejak pemanggilan
Proses melakukan polling (bertanya berulang kali) pada kernel. Jika data belum siap, kernel langsung kembali dengan error
Proses menggunakan satu panggilan sistem (seperti
Proses memberitahu kernel untuk mengirimkan sinyal (SIGIO) ketika data sudah siap. Proses tidak terblokir dan bisa melakukan pekerjaan lain. Ketika sinyal diterima, signal handler akan dieksekusi untuk membaca data (dengan
Ini adalah satu-satunya model yang benar-benar non-blocking. Proses memulai operasi I/O dan langsung melanjutkan pekerjaannya. Kernel akan menangani kedua fase di latar belakang. Setelah data selesai disalin ke buffer aplikasi, kernel akan memberikan notifikasi (misalnya, melalui sinyal atau callback) kepada proses.