Efek samping dari kerfluffle freenode secara keseluruhan adalah saya telah melihat IRCD lagi. IRC, tentu saja merupakan tempat yang sangat aneh dan menarik, dan komunitas kecil yang menjalankan IRCD jauh lebih aneh dan bahkan lebih menarik.
Namun, dalam komunitas administrator IRCD tersebut terdapat beberapa opini pemrograman sistem yang salah yang telah dipuja selama bertahun-tahun. Blog khusus ini tentang salah satu bengkel sepeda tersebut, yaitu debat kqueue vs epoll.
Anda mungkin pernah mendengarnya sebelumnya. Bunyinya seperti ini, “BSD lebih bagus untuk networking, karena ada kqueue. Linux tidak memiliki kqueue, epoll tidak bisa menandinginya.” Meskipun saya setuju bahwa epoll tidak mendekati, menurut saya itu sebenarnya adalah fitur yang menghasilkan desain yang jauh lebih fleksibel dan dapat disusun.
Pada awalnya…
Awalnya, IRCD seperti kebanyakan daemon yang digunakan select
untuk kesiapan soket polling, karena ini adalah API polling pertama yang tersedia pada sistem dengan soket BSD. Itu select
syscall bekerja dengan mengambil satu set tiga bitmap, dengan masing-masing bit menggambarkan nomor deskriptor file: bit 1 mengacu pada deskriptor file 1 dan seterusnya. Bitmap adalah read_set
, write_set
Dan err_set
yang dipetakan ke soket yang dapat dibaca, ditulis, atau memiliki kesalahan yang sesuai. Karena cacat desain dengan select
syscalls, itu hanya dapat mendukung hingga FD_SETSIZE
deskriptor file di sebagian besar sistem. Hal ini dapat diatasi dengan membuat fd_set
bitmap yang sangat besar dan bergantung pada fdmax
menjadi batas atas, yang secara tradisional dilakukan WinSock di Windows.
Itu select
syscall jelas memiliki beberapa kekurangan desain yang berdampak negatif pada skalabilitas, jadi AT&T memperkenalkannya poll
panggilan sistem di Sistem V UNIX. Itu poll
syscall mengambil array struct pollfd
dengan panjang yang ditentukan pengguna, dan memperbarui bitmap flag di masing-masingnya struct pollfd
entri dengan status terkini setiap soket. Kemudian Anda mengulanginya struct pollfd
daftar. Ini tentu saja jauh lebih efisien dibandingkan select
di mana Anda harus mengulangi semua deskriptor file hingga fdmax
dan uji keanggotaan di masing-masing dari tiga bitmap untuk memastikan status masing-masing soket.
Dapat dikatakan demikian select
dibatasi oleh FD_SETSIZE
(yang biasanya 1024 soket), sedangkan poll
mulai memiliki masalah skalabilitas yang serius 10240
soket. Tolok ukur yang sewenang-wenang ini disebut sebagai masalah C1K dan C10K. Dan Kegel memiliki posting yang sangat panjang di situs webnya tentang pengalamannya memitigasi masalah C10K dalam rangka menjalankan situs FTP.
Lalu ada kqueue…
Pada bulan Juli 2000, Jonathan Lemon memperkenalkan kqueue ke FreeBSD, yang dengan cepat menyebar ke fork BSD lainnya juga. kqueue adalah sistem notifikasi kejadian yang dibantu kernel menggunakan dua syscall: kqueue
Dan kevent
. Itu kqueue
syscall membuat pegangan di kernel yang direpresentasikan sebagai deskriptor file, yang digunakan oleh pengembang kevent
untuk menambah dan menghapus filter acara. Filter peristiwa dapat dicocokkan dengan deskriptor file, proses, jalur sistem file, pengatur waktu, dan sebagainya.
Desain ini memungkinkan server single-thread untuk memproses ratusan ribu koneksi sekaligus, karena ia dapat mendaftarkan semua soket yang ingin dipantau dengan kernel dan kemudian dengan malas melakukan iterasi pada soket tersebut saat ada acara.
Sebagian besar IRCD telah mendukung kqueue
selama 15 hingga 20 tahun terakhir.
Dan kemudian jajak pendapat…
Pada bulan Oktober 2002, Davide Libenzi mendapatkannya miliknya epoll
tambalan digabungkan ke Linux 2.5.44. Seperti dengan kqueue, Anda menggunakan epoll_create
syscall untuk membuat pegangan kernel yang mewakili kumpulan deskriptor untuk dipantau. Anda menggunakan epoll_ctl
syscall untuk menambah atau menghapus deskriptor dari kumpulan itu. Dan akhirnya, Anda menggunakannya epoll_wait
untuk menunggu acara kernel.
Secara umum, aspek skalabilitas sama bagi pemrogram aplikasi: Anda punya soket, Anda menggunakannya epoll_ctl
untuk menambahkannya ke kernel epoll
tangani, lalu Anda menunggu acara, sama seperti yang Anda lakukan kevent
.
Menyukai kqueue
sebagian besar IRCD telah mendukungnya epoll
selama 15 tahun terakhir.
Apa itu deskriptor file?
Untuk memahami argumen yang akan saya sampaikan, kita perlu membicarakannya deskriptor file. UNIX menggunakan istilah tersebut deskriptor file banyak, bahkan ketika mengacu pada hal-hal yang jelas bukan file, seperti soket jaringan. Di luar dunia UNIX, deskriptor file biasanya disebut sebagai a pegangan kernel. Memang benar, di Windows, sumber daya yang dikelola kernel diberikan HANDLE
tipe, yang membuat hubungan ini lebih jelas. Pada dasarnya, pegangan kernel pada dasarnya adalah referensi buram ke suatu objek di ruang kernel, dan pembaca yang cerdik mungkin melihat beberapa kesamaan dengan model kemampuan objek sebagai akibat.
Sekarang kita memahami bahwa deskriptor file sebenarnya hanyalah pengendali kernel, sekarang kita dapat membicarakannya kqueue
Dan epoll
dan mengapa epoll
sebenarnya adalah desain yang benar.
Masalah dengan filter acara
Perbedaan utama antara epoll
Dan kqueue
apakah itu kqueue
beroperasi pada gagasan filter acara alih-alih pegangan kernel. Artinya kapan pun Anda mau kqueue
untuk melakukan sesuatu yang baru, Anda harus menambahkan tipe baru penyaring acara.
FreeBSD saat ini memiliki 10 tipe filter event yang berbeda: EVFILT_READ
, EVFILT_WRITE
, EVFILT_EMPTY
, EVFILT_AIO
, EVFILT_VNODE
, EVFILT_PROC
, EVFILT_PROCDESC
, EVFILT_SIGNAL
, EVFILT_TIMER
Dan EVFILT_USER
. Darwin memiliki filter peristiwa tambahan mengenai pemantauan port Mach.
Selain daripada EVFILT_READ
, EVFILT_WRITE
Dan EVFILT_EMPTY
semua jenis filter peristiwa yang berbeda ini terkait dengan masalah yang sama sekali berbeda di kernel: mereka tidak memonitor pengendali kernel, melainkan subsistem spesifik lainnya selain soket.
Hal ini menghasilkan API yang kuat, tetapi ada kekurangannya kemampuan komposisi.
epoll
lebih baik karena dapat disusun
Hampir semua hal dapat dilakukan kqueue
dapat dilakukan pada FreeBSD di Linux, tetapi alih-alih memiliki satu syscall monolitik untuk ditangani semuanyaLinux mengambil pendekatan dengan menyediakan syscall yang memungkinkan hampir semua hal direpresentasikan sebagai a pegangan kernel.
Sejak epoll
memantau secara ketat pegangan kernelAnda bisa mendaftar setiap pegangan kernel yang Anda miliki dan dapatkan kembali kejadian ketika statusnya berubah. Sebagai perbandingan dengan Windows, pada dasarnya ini berarti demikian epoll
adalah bentuk yang dipercepat kernel WaitForMultipleObjects
di API Win32.
Anda mungkin bertanya-tanya bagaimana cara kerjanya, jadi inilah tabel yang umum digunakan kqueue
filter acara dan syscall Linux yang digunakan untuk mendapatkan pegangan kernel untuk digunakan epoll
.
Filter acara BSD | Setara dengan Linux |
---|---|
EVFILT_READ , EVFILT_WRITE , EVFILT_EMPTY |
Lewati soket dengan EPOLLIN dll. |
EVFILT_VNODE |
inotify |
EVFILT_SIGNAL |
signalfd |
EVFILT_TIMER |
timerfd |
EVFILT_USER |
eventfd |
EVFILT_PROC , EVFILT_PROCDESC |
pidfd alternatifnya mengikat proses ke a cgroup dan memantau cgroup.events |
EVFILT_AIO |
aiocb.aio_fildes (perlakukan sebagai soket) |
Mudah-mudahan, seperti yang Anda lihat, epoll
dapat memantau secara otomatis setiap jenis sumber daya kernel tanpa harus dimodifikasi, karena desainnya yang dapat dikomposisi, menjadikannya lebih unggul kqueue
dari perspektif memiliki utang teknis yang lebih sedikit.
Menariknya, FreeBSD telah menambahkan dukungan untuk Linux eventfd
baru-baru inijadi tampaknya mereka mungkin akan menerimanya kqueue
ke arah ini juga. Antara itu dan FreeBSD deskriptor prosessepertinya mungkin.