Bagaimana server web "mendengarkan" alamat IP, interupsi, atau polling?

87

Saya mencoba memahami detail server web yang lebih rendah. Saya bertanya-tanya apakah server, katakanlah Apache, terus-menerus mengumpulkan suara untuk permintaan baru atau Jika itu bekerja dengan semacam sistem interupsi. Jika interupsi, apa yang memicu interupsi, apakah itu driver kartu jaringan?

pengguna2202911
sumber
1
Kata kunci yang harus dipahami adalah "server" . Dalam model server-klien (dibandingkan model master-slave) server menunggu permintaan dari klien. Permintaan ini adalah acara yang perlu dilayani. Server web adalah program aplikasi. Pertanyaan Anda menggabungkan aplikasi SW dengan terminologi HW (mis. Interrupt dan NIC), alih-alih menyimpan konsep terkait pada lapisan abstraksi yang sama. Driver NIC kadang-kadang mungkin menggunakan polling, misal driver Linux NAPI mundur ke polling ketika ada banyak paket. Tapi itu tidak relevan dengan aplikasi pemrosesan acara SW.
serbuk kayu
1
@sawdust Sangat menarik. Pertanyaan ini benar-benar dimaksudkan untuk memahami hubungan antara proses SW dan HW
user2202911
1
Ini sangat mirip dengan program command-line cara (dan GUI lainnya) mendengarkan keyboard. Terutama di sistem jendela, di mana Anda memiliki langkah kernel menerima data dari perangkat keyboard dan menyerahkannya ke manajer jendela, yang mengidentifikasi jendela yang memiliki fokus dan memberikan data ke jendela itu.
G-Man
@ G-Man: Saya teori, ya. Pada kenyataannya sebagian besar juru ketik tidak mengetik pada 1 Gbit / s, yang membenarkan memiliki dua arsitektur yang berbeda. Satu bersih, fleksibel dan lambat, satu kikuk tetapi berkecepatan tinggi.
MSalters

Jawaban:

181

Jawaban singkatnya adalah: semacam sistem interupsi. Intinya, mereka menggunakan pemblokiran I / O, artinya mereka tidur (block) sambil menunggu data baru.

  1. Server membuat soket pendengaran dan kemudian memblokir sambil menunggu koneksi baru. Selama waktu ini, kernel menempatkan proses ke dalam status sleep yang interruptible dan menjalankan proses lainnya. Ini adalah poin penting: memiliki proses jajak pendapat yang terus menerus akan membuang-buang CPU. Kernel dapat menggunakan sumber daya sistem dengan lebih efisien dengan memblokir proses sampai ada pekerjaan yang harus dilakukan.

  2. Ketika data baru tiba di jaringan, kartu jaringan mengeluarkan interupsi.

  3. Melihat ada gangguan dari kartu jaringan, kernel, melalui driver kartu jaringan, membaca data baru dari kartu jaringan dan menyimpannya ke dalam memori. (Ini harus dilakukan dengan cepat dan umumnya ditangani di dalam interrupt handler.)

  4. Kernel memproses data yang baru tiba dan mengaitkannya dengan soket. Suatu proses yang memblokir pada soket itu akan ditandai runnable, artinya sekarang layak untuk dijalankan. Itu tidak harus langsung berjalan (kernel mungkin memutuskan untuk menjalankan proses lainnya).

  5. Pada waktu senggang, kernel akan membangunkan proses server web yang diblokir. (Karena sekarang bisa dijalankan.)

  6. Proses server web terus mengeksekusi seolah-olah tidak ada waktu berlalu. Panggilan sistem pemblokirannya kembali dan memproses data baru. Lalu ... lanjutkan ke langkah 1.

Greg Bowser
sumber
18
+1 untuk penggambaran yang jelas dari kernel vs proses server web.
Russell Borogove
13
Saya tidak dapat mempercayai sesuatu yang rumit seperti ini dapat diringkas dengan begitu jelas dan sederhana, tetapi Anda melakukannya. +1
Brandon
8
+1 Jawaban bagus. Juga, langkah-langkah antara 2 dan 3 bisa menjadi sedikit lebih kompleks dengan NIC, OS, dan driver modern. Misalnya, dengan NAPI di Linux, paket-paket tersebut tidak benar-benar diterima dalam konteks interupsi. Alih-alih, kernel mengatakan "Oke NIC, saya mengerti Anda punya data. Berhentilah mengganggu saya (nonaktifkan sumber interupsi), dan saya akan segera kembali untuk mengambil paket ini dan setiap paket berikutnya yang mungkin tiba sebelum saya melakukannya."
Jonathon Reinhart
8
Nitpick ringan: Tidak perlu diblokir. Segera setelah proses server membuat soket pendengaran, kernel akan menerima SYN pada port itu, bahkan saat Anda tidak diblokir di dalamnya accept. Mereka (untungnya, atau itu akan benar-benar menyedot!) Mandiri, menjalankan tugas yang tidak sinkron. Saat koneksi masuk, mereka ditempatkan ke dalam antrian tempat acceptmenariknya. Hanya jika tidak ada, itu menghalangi.
Damon
3
"Membaca data baru dari kartu jaringan dan menyimpannya ke dalam memori. (Ini harus dilakukan dengan cepat dan umumnya ditangani di dalam interrupt handler.)" Bukankah itu dilakukan dengan akses memori langsung?
Siyuan Ren
9

Ada cukup banyak detail "lebih rendah".

Pertama, pertimbangkan bahwa kernel memiliki daftar proses, dan pada waktu tertentu, beberapa proses ini sedang berjalan, dan beberapa tidak. Kernel memungkinkan setiap proses yang berjalan beberapa waktu CPU, kemudian menyela dan pindah ke yang berikutnya. Jika tidak ada proses yang dapat dijalankan, maka kernel mungkin akan mengeluarkan instruksi seperti HLT ke CPU yang menangguhkan CPU sampai ada gangguan perangkat keras.

Di suatu tempat di server adalah panggilan sistem yang mengatakan "beri aku sesuatu untuk dilakukan". Ada dua kategori luas cara ini bisa dilakukan. Dalam kasus Apache, ia memanggil acceptsoket yang sebelumnya telah dibuka oleh Apache, mungkin mendengarkan pada port 80. Kernel mempertahankan antrian upaya koneksi, dan menambahkan ke antrian itu setiap kali TCP SYN diterima. Bagaimana kernel mengetahui TCP SYN diterima tergantung pada driver perangkat; untuk banyak NIC mungkin ada interupsi perangkat keras ketika data jaringan diterima.

acceptmeminta kernel untuk kembali kepada saya inisiasi koneksi berikutnya. Jika antrian tidak kosong, maka acceptsegera kembali segera. Jika antrian kosong, maka proses (Apache) dihapus dari daftar proses yang berjalan. Ketika suatu koneksi kemudian dimulai, proses dilanjutkan. Ini disebut "blocking", karena untuk proses memanggilnya, accept()tampak seperti fungsi yang tidak kembali sampai hasilnya, yang mungkin beberapa waktu dari sekarang. Selama waktu itu proses tidak dapat melakukan hal lain.

Setelah acceptkembali, Apache tahu bahwa seseorang sedang mencoba untuk memulai koneksi. Itu kemudian memanggil garpu untuk membagi proses Apache dalam dua proses yang identik. Salah satu dari proses ini berlanjut untuk memproses permintaan HTTP, panggilan lain acceptlagi untuk mendapatkan koneksi berikutnya. Jadi, selalu ada proses utama yang tidak melakukan apa-apa selain memanggil acceptdan menelurkan sub-proses, dan kemudian ada satu sub-proses untuk setiap permintaan.

Ini adalah penyederhanaan: dimungkinkan untuk melakukan ini dengan utas alih-alih proses, dan juga mungkin untuk forksebelumnya sehingga ada proses pekerja siap untuk pergi ketika permintaan diterima, sehingga mengurangi overhead startup. Tergantung pada bagaimana Apache dikonfigurasikan, ia dapat melakukan hal-hal ini.

Itulah kategori luas pertama cara melakukannya, dan itu disebut memblokir IO karena sistem memanggil suka acceptdan readdan writeyang beroperasi pada soket akan menunda proses sampai mereka memiliki sesuatu untuk dikembalikan.

Cara lain yang luas untuk melakukannya disebut non-blocking atau event-based atau asynchronous IO . Ini diimplementasikan dengan panggilan sistem seperti selectatau epoll. Masing-masing melakukan hal yang sama: Anda memberi mereka daftar soket (atau secara umum, deskriptor file) dan apa yang ingin Anda lakukan dengan mereka, dan kernel memblokir hingga siap untuk melakukan salah satu dari hal-hal itu.

Dengan model ini, Anda dapat memberi tahu kernel (dengan epoll), "Beri tahu saya ketika ada koneksi baru pada port 80 atau data baru untuk membaca pada salah satu dari 9471 ini koneksi lain yang saya buka". epollmenghalangi sampai salah satu dari hal-hal itu siap, maka Anda melakukannya. Lalu kamu ulangi. Panggilan sistem seperti acceptdan readdan writetidak pernah memblokir, sebagian karena setiap kali Anda memanggil mereka, epollhanya mengatakan kepada Anda bahwa mereka siap sehingga tidak akan ada alasan untuk memblokir, dan juga karena ketika Anda membuka soket atau file yang Anda tentukan bahwa Anda menginginkannya dalam mode non-pemblokiran, sehingga panggilan tersebut akan gagal dengan EWOULDBLOCKalih - alih memblokir.

Keuntungan dari model ini adalah Anda hanya perlu satu proses. Ini berarti Anda tidak perlu mengalokasikan struktur stack dan kernel untuk setiap permintaan. Nginx dan HAProxy menggunakan model ini, dan itu adalah alasan besar mereka dapat menangani lebih banyak koneksi daripada Apache pada perangkat keras yang sama.

Phil Frost
sumber