Aplikasi web sekarang banyak digunakan, dan HTTP adalah bagian terbesar dari semua protokol transportasi. Mempelajari nuansa mengembangkan aplikasi web, kebanyakan dari mereka sangat sedikit memperhatikan sistem operasi di mana aplikasi ini benar-benar dijalankan. Pemisahan pengembangan (Dev) dan operasi (Ops) hanya memperburuk keadaan. Tetapi dengan penyebaran budaya DevOps, pengembang mulai mengambil tanggung jawab untuk meluncurkan aplikasi mereka di cloud, sehingga sangat berguna bagi mereka untuk benar-benar berkenalan dengan sistem operasi backend. Ini sangat berguna jika Anda mencoba menggunakan sistem untuk ribuan atau puluhan ribu koneksi bersamaan.
Keterbatasan dalam layanan web sangat mirip dengan keterbatasan dalam aplikasi lain. Baik itu memuat penyeimbang atau server basis data, semua aplikasi ini memiliki masalah serupa di lingkungan berkinerja tinggi. Memahami batasan mendasar ini dan cara mengatasinya secara umum akan membantu Anda mengevaluasi kinerja dan skalabilitas aplikasi web Anda.
Saya menulis seri artikel ini sebagai jawaban atas pertanyaan dari pengembang muda yang ingin menjadi arsitek sistem informasi. Tidak mungkin untuk secara jelas memahami metode mengoptimalkan aplikasi Linux tanpa masuk ke dasar-dasar bagaimana mereka bekerja di tingkat sistem operasi. Meskipun ada banyak jenis aplikasi, dalam seri ini saya ingin menjelajahi aplikasi jaringan, bukan yang desktop seperti browser atau editor teks. Materi ini ditujukan untuk pengembang dan arsitek yang ingin memahami cara kerja program Linux atau Unix dan bagaimana menyusunnya untuk kinerja tinggi.
Linux adalah sistem operasi
server , dan paling sering aplikasi Anda berjalan pada OS khusus ini. Meskipun saya mengatakan "Linux," sebagian besar waktu Anda dapat dengan aman mengasumsikan bahwa semua sistem operasi mirip Unix secara umum dimaksudkan. Namun, saya belum menguji kode yang menyertainya pada sistem lain. Jadi, jika Anda tertarik dengan FreeBSD atau OpenBSD, hasilnya dapat bervariasi. Ketika saya mencoba sesuatu yang spesifik untuk Linux, saya menunjukkannya.
Meskipun Anda dapat menggunakan pengetahuan ini untuk membuat aplikasi dari awal, dan itu akan dioptimalkan dengan sempurna, lebih baik tidak melakukannya. Jika Anda menulis server web baru dalam C atau C ++ untuk aplikasi bisnis organisasi Anda, ini mungkin hari terakhir Anda di kantor. Namun, pengetahuan tentang struktur aplikasi ini akan membantu dalam pemilihan program yang ada. Anda dapat membandingkan sistem berbasis proses dengan sistem berbasis thread dan sistem berbasis acara. Anda akan memahami dan menghargai mengapa Nginx bekerja lebih baik daripada Apache httpd, mengapa aplikasi Python berbasis Tornado dapat melayani lebih banyak pengguna daripada aplikasi Python berbasis Django.
ZeroHTTPd: Alat Belajar
ZeroHTTPd adalah server web yang saya tulis dari awal di C sebagai alat pelatihan. Ia tidak memiliki dependensi eksternal, termasuk akses ke Redis. Kami menjalankan rutinitas Redis kami sendiri. Lihat di bawah untuk detail lebih lanjut.
Meskipun kita dapat mendiskusikan teori ini untuk waktu yang lama, tidak ada yang lebih baik daripada menulis kode, menjalankannya, dan membandingkan semua arsitektur server secara bersamaan. Ini adalah metode yang paling jelas. Oleh karena itu, kami akan menulis server web ZeroHTTPd sederhana menggunakan masing-masing model: berdasarkan pada proses, utas dan acara. Mari kita periksa masing-masing server ini dan melihat bagaimana mereka bekerja dibandingkan satu sama lain. ZeroHTTPd diimplementasikan dalam satu file C. Server berbasis peristiwa mencakup
uthash , implementasi tabel hash yang sangat baik yang dikirimkan dalam file header tunggal. Dalam kasus lain, tidak ada ketergantungan, sehingga tidak menyulitkan proyek.
Ada banyak komentar dalam kode untuk membantu mengatasinya. Menjadi server web sederhana dalam beberapa baris kode, ZeroHTTPd juga kerangka kerja pengembangan web minimal. Ini memiliki fungsi terbatas, tetapi mampu menghasilkan file statis dan halaman "dinamis" yang sangat sederhana. Saya harus mengatakan bahwa ZeroHTTPd sangat cocok untuk mempelajari cara membuat aplikasi Linux berkinerja tinggi. Pada umumnya, sebagian besar layanan web menunggu permintaan, memeriksa dan memprosesnya. Inilah yang akan dilakukan ZeroHTTPd. Ini adalah alat belajar, bukan alat produksi. Dia tidak pandai menangani kesalahan dan tidak mungkin membanggakan praktik-praktik keamanan terbaik (oh ya, saya menggunakan
strcpy
) atau trik-trik muslihat C. Tapi saya harap dia melakukan tugasnya dengan baik.
Beranda ZeroHTTPd. Itu dapat menghasilkan berbagai jenis file, termasuk gambarAplikasi Buku Tamu
Aplikasi web modern biasanya tidak terbatas pada file statis. Mereka memiliki interaksi yang kompleks dengan berbagai database, cache, dll. Oleh karena itu, kami akan membuat aplikasi web sederhana yang disebut "Buku Tamu", di mana pengunjung meninggalkan entri dengan nama mereka. Buku tamu menyimpan entri yang tersisa sebelumnya. Ada juga penghitung pengunjung di bagian bawah halaman.
Aplikasi Web Buku Tamu ZeroHTTPdKonter pengunjung dan entri buku tamu disimpan di Redis. Untuk komunikasi dengan Redis, prosedur sendiri diterapkan, mereka independen dari perpustakaan eksternal. Saya bukan penggemar berat kode yang dikembangkan di rumah ketika ada solusi yang tersedia untuk umum dan teruji. Tetapi tujuan ZeroHTTPd adalah untuk mempelajari kinerja Linux dan akses ke layanan eksternal, sementara melayani permintaan HTTP secara serius mempengaruhi kinerja. Kami harus sepenuhnya mengendalikan komunikasi dengan Redis di setiap arsitektur server kami. Dalam satu arsitektur, kami menggunakan panggilan pemblokiran, di arsitektur lain kami menggunakan prosedur berbasis acara. Menggunakan pustaka klien Redis eksternal tidak akan memberikan kontrol seperti itu. Selain itu, klien Redis kecil kami hanya melakukan beberapa fungsi (mendapatkan, mengatur, dan meningkatkan kunci; mendapatkan dan menambah array). Selain itu, protokol Redis sangat elegan dan sederhana. Dia bahkan tidak perlu diajar secara khusus. Fakta bahwa protokol melakukan semua pekerjaan dalam sekitar seratus baris kode menunjukkan seberapa baik dipikirkan.
Gambar berikut menunjukkan aplikasi ketika klien (browser) meminta
/guestbookURL
.
Mekanisme aplikasi buku tamuSaat Anda perlu menerbitkan halaman buku tamu, ada satu panggilan ke sistem file untuk membaca templat ke dalam memori dan tiga panggilan jaringan ke Redis. File template berisi sebagian besar konten HTML untuk halaman dalam screenshot di atas. Ada juga tempat penampung khusus untuk bagian dinamis dari konten: catatan dan konter pengunjung. Kami mendapatkannya dari Redis, menyisipkannya di halaman dan memberikan konten yang sepenuhnya dibentuk klien. Panggilan ketiga ke Redis dapat dihindari karena Redis mengembalikan nilai kunci baru ketika ditambahkan. Namun, untuk server kami dengan arsitektur berbasis peristiwa yang tidak sinkron, banyak panggilan jaringan merupakan ujian yang baik untuk tujuan pelatihan. Dengan demikian, kami membuang nilai pengembalian Redis tentang jumlah pengunjung dan memintanya dalam panggilan terpisah.
Arsitektur Server ZeroHTTPd
Kami sedang membangun tujuh versi ZeroHTTPd dengan fungsi yang sama tetapi arsitektur yang berbeda:
- Berulang
- Server garpu (proses satu anak per permintaan)
- Server pre-fork (proses pre-fork)
- Server dengan utas (satu utas per permintaan)
- Server dengan pra-threading
- Arsitektur berbasis
poll()
- Arsitektur epoll
Kami mengukur kinerja setiap arsitektur dengan memuat server dengan permintaan HTTP. Tetapi ketika membandingkan arsitektur dengan tingkat paralelisme yang tinggi, jumlah permintaan meningkat. Kami menguji tiga kali dan mempertimbangkan rata-rata.
Metodologi uji
Instalasi untuk pengujian stres ZeroHTTPdPenting bahwa ketika melakukan pengujian semua komponen tidak bekerja pada mesin yang sama. Dalam hal ini, OS membawa overhead perencanaan tambahan, karena komponen bersaing untuk CPU. Mengukur overhead sistem operasi dari masing-masing arsitektur server yang dipilih adalah salah satu tujuan paling penting dari latihan ini. Menambahkan lebih banyak variabel akan merusak proses. Oleh karena itu, pengaturan pada gambar di atas berfungsi paling baik.
Apa yang dilakukan masing-masing server ini
- load.unixism.net: di sini kita menjalankan
ab
, utilitas Apache Benchmark. Ini menghasilkan beban yang diperlukan untuk menguji arsitektur server kami.
- nginx.unixism.net: kadang-kadang kita ingin menjalankan lebih dari satu contoh program server. Untuk ini, server Nginx dengan pengaturan yang sesuai berfungsi sebagai penyeimbang beban yang berasal dari ab ke proses server kami.
- zerohttpd.unixism.net: di sini kita menjalankan program server kami pada tujuh arsitektur yang berbeda, satu per satu.
- redis.unixism.net: daemon Redis berjalan di server ini, tempat entri disimpan di buku tamu dan konter pengunjung.
Semua server berjalan pada satu inti prosesor. Idenya adalah untuk mengevaluasi kinerja maksimum setiap arsitektur. Karena semua program server diuji pada perangkat keras yang sama, ini adalah tingkat dasar untuk membandingkannya. Setup pengujian saya terdiri dari server virtual yang disewa dari Digital Ocean.
Apa yang kita ukur?
Anda dapat mengukur berbagai indikator. Kami mengevaluasi kinerja setiap arsitektur dalam konfigurasi ini, memuat server dengan permintaan pada berbagai tingkat konkurensi: beban bertambah dari 20 menjadi 15.000 pengguna secara bersamaan.
Hasil tes
Diagram berikut menunjukkan kinerja server pada arsitektur yang berbeda di berbagai tingkat concurrency. Sumbu y adalah jumlah permintaan per detik, sumbu x adalah koneksi paralel.



Di bawah ini adalah tabel dengan hasilnya.
Dapat dilihat dari grafik dan tabel bahwa di atas 8000 permintaan simultan, kita hanya memiliki dua pemain tersisa: pre-fork dan epoll. Ketika beban bertambah, server berbasis polling berkinerja lebih buruk daripada streaming. Arsitektur pra-threading bersaing dengan epoll: ini adalah bukti seberapa baik kernel Linux merencanakan sejumlah besar utas.
Kode Sumber ZeroHTTPd
Kode sumber untuk ZeroHTTPd ada di
sini . Setiap arsitektur memiliki direktori terpisah.
ZeroHTTPd
β
βββ 01_iterative
β βββ main.c
βββ 02_pekerjaan
β βββ main.c
βββ 03_preforking
β βββ main.c
βββ 04_threading
β βββ main.c
βββ 05_ interprethreading
β βββ main.c
βββ 06_poll
β βββ main.c
βββ 07_epoll
β βββ main.c
βββ Makefile
βββ publik
β βββ index.html
β βββ tux.png
βββ templat
βββ buku tamu
βββ index.html
Selain tujuh direktori untuk semua arsitektur, ada dua lagi di direktori tingkat atas: publik dan template. Yang pertama berisi file index.html dan gambar dari screenshot pertama. File dan folder lain dapat ditempatkan di sana, dan ZeroHTTPd harus mengeluarkan file statis ini tanpa masalah. Jika path di browser cocok dengan path di folder publik, maka ZeroHTTPd mencari file index.html di direktori ini. Konten buku tamu dibuat secara dinamis. Ini hanya memiliki halaman utama, dan isinya didasarkan pada file 'templates / guestbook / index.html'. ZeroHTTPd dengan mudah menambahkan halaman dinamis untuk ekspansi. Idenya adalah bahwa pengguna dapat menambahkan template ke direktori ini dan memperluas ZeroHTTPd sesuai kebutuhan.
Untuk membangun ketujuh server, jalankan
make all
dari direktori tingkat atas - dan semua build akan muncul di direktori ini. Yang dapat dieksekusi mencari publik dan template direktori dalam direktori dari mana mereka dijalankan.
API Linux
Untuk memahami informasi dalam seri artikel ini, tidak perlu berpengalaman dalam Linux API. Namun, saya sarankan membaca lebih lanjut tentang topik ini, ada banyak sumber referensi di Web. Meskipun kami akan membahas beberapa kategori API Linux, fokus kami terutama pada proses, utas, acara, dan tumpukan jaringan. Selain buku dan artikel tentang Linux API, saya juga merekomendasikan membaca mana untuk panggilan sistem dan fungsi perpustakaan yang digunakan.
Performa dan skalabilitas
Satu catatan tentang kinerja dan skalabilitas. Secara teoritis, tidak ada hubungan di antara mereka. Anda mungkin memiliki layanan web yang bekerja dengan sangat baik, dengan waktu respons beberapa milidetik, tetapi tidak berskala sama sekali. Demikian pula, mungkin ada aplikasi web yang berjalan kurang baik yang membutuhkan waktu beberapa detik untuk merespons, tetapi ia menskala hingga puluhan untuk menangani puluhan ribu pengguna secara bersamaan. Namun, kombinasi kinerja tinggi dan skalabilitas adalah kombinasi yang sangat kuat. Aplikasi berkinerja tinggi umumnya menggunakan sumber daya secara ekonomis dan karenanya secara efektif melayani lebih banyak pengguna secara bersamaan di server, mengurangi biaya.
CPU dan I / O Tasks
Akhirnya, selalu ada dua jenis tugas yang mungkin dalam komputasi: untuk I / O dan CPU. Menerima permintaan melalui Internet (I / O jaringan), pemeliharaan file (I / O jaringan dan disk), komunikasi dengan basis data (I / O jaringan dan disk) adalah semua tindakan I / O. Beberapa permintaan basis data dapat memuat CPU sedikit (menyortir, menghitung rata-rata satu juta hasil, dll.). Sebagian besar aplikasi web dibatasi oleh I / O maksimum yang mungkin, dan prosesor jarang digunakan pada kapasitas penuh. Ketika Anda melihat bahwa beberapa CPU menggunakan banyak CPU, ini kemungkinan besar merupakan tanda arsitektur aplikasi yang buruk. Ini mungkin berarti bahwa sumber daya CPU dihabiskan untuk kontrol proses dan pengalihan konteks - dan ini tidak sepenuhnya berguna. Jika Anda melakukan sesuatu seperti pemrosesan gambar, konversi audio atau pembelajaran mesin, maka aplikasi tersebut membutuhkan sumber daya CPU yang kuat. Tetapi untuk sebagian besar aplikasi ini tidak demikian.
Lebih lanjut tentang arsitektur server
- Bagian I. Arsitektur Iteratif
- Bagian II Server garpu
- Bagian III. Server pre-fork
- Bagian IV Server dengan Utas
- Bagian V. Server dengan pra-pembuatan utas
- Bagian VI. Arsitektur berbasis jajak pendapat
- Bagian VII. Arsitektur epoll