Kinerja aplikasi jaringan Linux. Perkenalan

Aplikasi web sekarang digunakan di mana-mana, dan di antara semua protokol transport, HTTP menempati bagian terbesar. Saat mempelajari nuansa pengembangan aplikasi web, kebanyakan orang kurang memperhatikan sistem operasi tempat aplikasi tersebut dijalankan. Pemisahan antara pengembangan (Dev) dan operasi (Ops) hanya memperburuk situasi. Namun dengan bangkitnya budaya DevOps, pengembang menjadi bertanggung jawab untuk menjalankan aplikasi mereka di cloud, sehingga sangat berguna bagi mereka untuk mengenal backend sistem operasi secara menyeluruh. Hal ini sangat berguna jika Anda mencoba menerapkan sistem untuk ribuan atau puluhan ribu koneksi simultan.

Batasan dalam layanan web sangat mirip dengan aplikasi lain. Baik itu penyeimbang beban atau server database, semua aplikasi ini memiliki masalah serupa di lingkungan berkinerja tinggi. Memahami keterbatasan mendasar ini dan cara mengatasinya secara umum akan membantu Anda mengevaluasi kinerja dan skalabilitas aplikasi web Anda.

Saya menulis rangkaian artikel ini sebagai jawaban atas pertanyaan dari pengembang muda yang ingin menjadi arsitek sistem yang berpengetahuan luas. Tidak mungkin memahami dengan jelas teknik pengoptimalan aplikasi Linux tanpa mendalami dasar-dasar cara kerjanya di tingkat sistem operasi. Walaupun jenis aplikasinya banyak, namun pada seri ini saya ingin mendalami aplikasi berbasis web dibandingkan aplikasi desktop seperti browser atau editor teks. Materi ini ditujukan bagi pengembang dan arsitek yang ingin memahami cara kerja program Linux atau Unix dan cara menyusunnya untuk kinerja tinggi.

Linux adalah ruang server sistem operasi, dan paling sering aplikasi Anda berjalan di OS ini. Meskipun saya mengatakan "Linux", sering kali Anda dapat berasumsi bahwa yang saya maksud adalah semua sistem operasi mirip Unix secara umum. Namun, saya belum menguji kode yang menyertainya pada sistem lain. Jadi, jika Anda tertarik dengan FreeBSD atau OpenBSD, hasil Anda mungkin berbeda. Ketika saya mencoba sesuatu yang spesifik untuk Linux, saya menunjukkannya.

Meskipun Anda dapat menggunakan pengetahuan ini untuk membuat aplikasi dari awal dan aplikasi tersebut akan dioptimalkan dengan sempurna, sebaiknya jangan lakukan itu. Jika Anda menulis server web baru dalam C atau C++ untuk aplikasi bisnis organisasi Anda, ini mungkin hari terakhir Anda bekerja. Namun mengetahui struktur aplikasi ini akan membantu dalam memilih program yang ada. Anda akan dapat membandingkan sistem berbasis proses dengan sistem berbasis thread serta sistem berbasis peristiwa. Anda akan memahami dan menghargai mengapa Nginx berkinerja lebih baik daripada Apache httpd, mengapa aplikasi Python berbasis Tornado dapat melayani lebih banyak pengguna dibandingkan dengan aplikasi Python berbasis Django.

ZeroHTTPd: Alat Pembelajaran

NolHTTPd adalah server web yang saya tulis dari awal di C sebagai alat pengajaran. Ia tidak memiliki ketergantungan eksternal, termasuk akses ke Redis. Kami menjalankan prosedur Redis kami sendiri. Lihat di bawah untuk lebih jelasnya.

Meskipun kita dapat mendiskusikan teori secara panjang lebar, tidak ada yang lebih baik daripada menulis kode, menjalankannya, dan membandingkan semua arsitektur server satu sama lain. Ini adalah metode yang paling jelas. Oleh karena itu, kami akan menulis server web ZeroHTTPd sederhana menggunakan masing-masing model: berbasis proses, berbasis thread, dan berbasis peristiwa. Mari kita periksa masing-masing server ini dan lihat bagaimana kinerjanya dibandingkan satu sama lain. ZeroHTTPd diimplementasikan dalam satu file C. Termasuk server berbasis acara uthash, implementasi tabel hash hebat yang hadir dalam satu file header. Dalam kasus lain, tidak ada ketergantungan, sehingga tidak mempersulit proyek.

Ada banyak komentar dalam kode untuk membantu Anda memahami. Menjadi server web sederhana dalam beberapa baris kode, ZeroHTTPd juga merupakan kerangka kerja minimal untuk pengembangan web. Ini memiliki fungsionalitas terbatas, tetapi mampu menyajikan file statis dan halaman "dinamis" yang sangat sederhana. Saya harus mengatakan bahwa ZeroHTTPd bagus untuk mempelajari cara membuat aplikasi Linux berkinerja tinggi. Pada umumnya, sebagian besar layanan web menunggu permintaan, memeriksanya, dan memprosesnya. Inilah yang akan dilakukan ZeroHTTPd. Ini adalah alat untuk belajar, bukan produksi. Ini tidak bagus dalam penanganan kesalahan dan tidak mungkin membanggakan praktik keamanan terbaik (oh ya, saya dulu strcpy) atau trik pintar bahasa C. Tapi saya harap ini berfungsi dengan baik.

Kinerja aplikasi jaringan Linux. Perkenalan
Halaman beranda ZeroHTTPd. Itu dapat menampilkan berbagai jenis file termasuk gambar

Aplikasi Buku Tamu

Aplikasi web modern biasanya tidak terbatas pada file statis. Mereka memiliki interaksi yang kompleks dengan berbagai database, cache, dll. Jadi kita akan membuat aplikasi web sederhana bernama "Buku Tamu" di mana pengunjung meninggalkan entri di bawah nama mereka. Buku tamu menyimpan entri yang ditinggalkan sebelumnya. Ada juga penghitung pengunjung di bagian bawah halaman.

Kinerja aplikasi jaringan Linux. Perkenalan
Aplikasi web "Buku Tamu" ZeroHTTPd

Konter pengunjung dan entri buku tamu disimpan di Redis. Untuk komunikasi dengan Redis, prosedurnya sendiri diterapkan; prosedur tersebut tidak bergantung pada perpustakaan eksternal. Saya bukan penggemar peluncuran kode homebrew ketika ada solusi yang tersedia untuk umum dan telah teruji dengan baik. Namun tujuan ZeroHTTPd adalah untuk mempelajari kinerja Linux dan akses ke layanan eksternal, sementara melayani permintaan HTTP memiliki dampak kinerja yang serius. Kami harus sepenuhnya mengontrol komunikasi dengan Redis di setiap arsitektur server kami. Di beberapa arsitektur kami menggunakan pemblokiran panggilan, di arsitektur lain kami menggunakan prosedur berbasis peristiwa. Menggunakan pustaka klien Redis eksternal tidak akan memberikan kontrol ini. Selain itu, klien Redis kecil kami hanya menjalankan beberapa fungsi (mendapatkan, mengatur, dan menambah kunci; mendapatkan dan menambahkan ke array). Selain itu, protokol Redis sangat elegan dan sederhana. Anda bahkan tidak perlu mengajarkannya secara khusus. Fakta bahwa protokol melakukan semua pekerjaan dalam sekitar seratus baris kode menunjukkan betapa baiknya protokol tersebut dipikirkan.

Gambar berikut menunjukkan apa yang dilakukan aplikasi ketika klien (browser) memintanya /guestbookURL.

Kinerja aplikasi jaringan Linux. Perkenalan
Cara kerja aplikasi buku tamu

Ketika halaman buku tamu perlu diterbitkan, 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 pada gambar di atas. Ada juga placeholder khusus untuk bagian dinamis konten: postingan dan penghitung pengunjung. Kami menerimanya dari Redis, memasukkannya ke dalam halaman dan menyediakan konten lengkap kepada klien. Panggilan ketiga ke Redis dapat dihindari karena Redis mengembalikan nilai kunci baru ketika bertambah. Namun, untuk server kami, yang memiliki arsitektur berbasis peristiwa asinkron, banyak panggilan jaringan merupakan ujian yang baik untuk tujuan pembelajaran. Jadi kami membuang nilai pengembalian Redis dari jumlah pengunjung dan menanyakannya dengan panggilan terpisah.

Arsitektur server ZeroHTTPd

Kami sedang membangun tujuh versi ZeroHTTPd dengan fungsi yang sama tetapi arsitektur berbeda:

  • Iteratif
  • Server fork (satu proses anak per permintaan)
  • Server pra-fork (proses pra-forking)
  • Server dengan thread eksekusi (satu thread per permintaan)
  • Server dengan pembuatan pra-utas
  • Berbasis arsitektur poll()
  • Berbasis arsitektur epoll

Kami mengukur kinerja setiap arsitektur dengan memuat server dengan permintaan HTTP. Namun ketika membandingkan arsitektur yang sangat paralel, jumlah kueri meningkat. Kami menguji tiga kali dan menghitung rata-rata.

Metodologi pengujian

Kinerja aplikasi jaringan Linux. Perkenalan
Pengaturan pengujian beban ZeroHTTPd

Penting agar saat menjalankan pengujian, semua komponen tidak dijalankan di mesin yang sama. Dalam hal ini, OS menimbulkan overhead penjadwalan tambahan karena komponen bersaing untuk mendapatkan CPU. Mengukur overhead sistem operasi dari masing-masing arsitektur server yang dipilih adalah salah satu tujuan terpenting dari latihan ini. Menambahkan lebih banyak variabel akan merugikan proses. Oleh karena itu, pengaturan pada gambar di atas berfungsi paling baik.

Apa fungsi masing-masing server ini?

  • load.unixism.net: Di sinilah kita menjalankan ab, utilitas Tolok Ukur Apache. Ini menghasilkan beban yang diperlukan untuk menguji arsitektur server kami.
  • nginx.unixism.net: Terkadang kita ingin menjalankan lebih dari satu program server. Untuk melakukan ini, server Nginx dengan pengaturan yang sesuai berfungsi sebagai penyeimbang beban yang berasal ab ke proses server kami.
  • zerohttpd.unixism.net: Di sini kami menjalankan program server kami pada tujuh arsitektur berbeda, satu per satu.
  • redis.unixism.net: Server ini menjalankan daemon Redis, tempat entri buku tamu dan penghitung pengunjung disimpan.

Semua server berjalan pada inti prosesor yang sama. Idenya adalah untuk mengevaluasi kinerja maksimal setiap arsitektur. Karena semua program server diuji pada perangkat keras yang sama, ini adalah dasar perbandingan. Pengaturan 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 tertentu dengan memuat server dengan permintaan pada tingkat paralelisme yang berbeda: beban bertambah dari 20 menjadi 15 pengguna secara bersamaan.

Hasil tes

Bagan berikut menunjukkan kinerja server pada arsitektur berbeda pada tingkat paralelisme berbeda. Sumbu y adalah jumlah permintaan per detik, sumbu x adalah koneksi paralel.

Kinerja aplikasi jaringan Linux. Perkenalan

Kinerja aplikasi jaringan Linux. Perkenalan

Kinerja aplikasi jaringan Linux. Perkenalan

Di bawah ini adalah tabel beserta hasilnya.

permintaan per detik

paralelisme
berulang
garpu
pra-garpu
Streaming
pra-streaming
pemilihan
epolling

20
7
112
2100
1800
2250
1900
2050

50
7
190
2200
1700
2200
2000
2000

100
7
245
2200
1700
2200
2150
2100

200
7
330
2300
1750
2300
2200
2100

300
-
380
2200
1800
2400
2250
2150

400
-
410
2200
1750
2600
2000
2000

500
-
440
2300
1850
2700
1900
2212

600
-
460
2400
1800
2500
1700
2519

700
-
460
2400
1600
2490
1550
2607

800
-
460
2400
1600
2540
1400
2553

900
-
460
2300
1600
2472
1200
2567

1000
-
475
2300
1700
2485
1150
2439

1500
-
490
2400
1550
2620
900
2479

2000
-
350
2400
1400
2396
550
2200

2500
-
280
2100
1300
2453
490
2262

3000
-
280
1900
1250
2502
penyebaran besar
2138

5000
-
penyebaran besar
1600
1100
2519
-
2235

8000
-
-
1200
penyebaran besar
2451
-
2100

10
-
-
penyebaran besar
-
2200
-
2200

11
-
-
-
-
2200
-
2122

12
-
-
-
-
970
-
1958

13
-
-
-
-
730
-
1897

14
-
-
-
-
590
-
1466

15
-
-
-
-
532
-
1281

Dari grafik dan tabel terlihat bahwa di atas 8000 permintaan simultan kami hanya memiliki dua pemain tersisa: pre-fork dan epoll. Ketika beban meningkat, kinerja server berbasis polling lebih buruk daripada server streaming. Arsitektur pra-pembuatan thread adalah pesaing yang layak untuk epoll, sebuah bukti seberapa baik kernel Linux menjadwalkan thread dalam jumlah besar.

Kode Sumber ZeroHTTPd

Kode Sumber ZeroHTTPd di sini. Ada direktori terpisah untuk setiap arsitektur.

ZeroHTTPd │ ├── 01_iterative │ ├── main.c ├── 02_forking │ ├── main.c ├── 03_preforking │ ├── main.c ├── 04_ threading │ ├── main.c ├── 05_prethreading │ ├── main.c ├── 06_poll │ ├── main.c ├── 07_epoll │ └── main.c ├── Makefile ├── public │ ├── indeks .html │ └── tux .png └── template └── buku tamu └── index.html

Selain tujuh direktori untuk semua arsitektur, ada dua lagi di direktori tingkat atas: publik dan templat. Yang pertama berisi file index.html dan gambar dari tangkapan layar pertama. Anda dapat meletakkan file dan folder lain di sana, dan ZeroHTTPd akan menyajikan file statis tersebut tanpa masalah. Jika jalur di browser cocok dengan jalur di folder publik, maka ZeroHTTPd mencari file index.html di direktori ini. Konten buku tamu dihasilkan secara dinamis. Ia hanya memiliki halaman beranda, dan isinya didasarkan pada file 'templates/guestbook/index.html'. ZeroHTTPd dengan mudah menambahkan halaman dinamis untuk ekstensi. Idenya adalah pengguna dapat menambahkan templat 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. File yang dapat dieksekusi mencari direktori publik dan templat di direktori tempat file tersebut diluncurkan.

API Linux

Anda tidak perlu menguasai API Linux untuk memahami informasi dalam seri artikel ini. Namun, saya sarankan membaca lebih lanjut tentang topik ini, ada banyak sumber referensi di Internet. Meskipun kami akan membahas beberapa kategori API Linux, fokus kami terutama pada proses, thread, peristiwa, dan tumpukan jaringan. Selain buku dan artikel tentang Linux API, saya juga merekomendasikan membaca mana untuk panggilan sistem dan fungsi perpustakaan yang digunakan.

Kinerja dan Skalabilitas

Satu catatan tentang kinerja dan skalabilitas. Secara teoritis, tidak ada hubungan di antara keduanya. Anda dapat memiliki layanan web yang bekerja dengan sangat baik, dengan waktu respons beberapa milidetik, namun tidak berskala sama sekali. Demikian pula, mungkin ada aplikasi web berperforma buruk yang memerlukan waktu beberapa detik untuk merespons, namun aplikasi tersebut berskala puluhan untuk menangani puluhan ribu pengguna secara bersamaan. Namun, kombinasi kinerja tinggi dan skalabilitas merupakan kombinasi yang sangat kuat. Aplikasi berkinerja tinggi umumnya menggunakan sumber daya dengan hemat dan dengan demikian secara efisien melayani lebih banyak pengguna secara bersamaan di server, sehingga mengurangi biaya.

tugas CPU dan I/O

Terakhir, dalam komputasi selalu ada dua kemungkinan jenis tugas: untuk I/O dan CPU. Menerima permintaan melalui Internet (I/O jaringan), melayani file (I/O jaringan dan disk), berkomunikasi dengan database (I/O jaringan dan disk) merupakan semua aktivitas I/O. Beberapa kueri basis data mungkin membutuhkan sedikit CPU (penyortiran, rata-rata satu juta hasil, dll.). Kebanyakan aplikasi web dibatasi oleh I/O semaksimal mungkin, dan prosesor jarang digunakan pada kapasitas penuh. Jika Anda melihat beberapa tugas I/O menggunakan banyak CPU, kemungkinan besar itu merupakan tanda arsitektur aplikasi yang buruk. Ini bisa berarti bahwa sumber daya CPU terbuang percuma untuk manajemen proses dan peralihan konteks - dan ini tidak sepenuhnya berguna. Jika Anda melakukan sesuatu seperti pemrosesan gambar, konversi file audio, atau pembelajaran mesin, maka aplikasi tersebut memerlukan sumber daya CPU yang kuat. Namun untuk sebagian besar aplikasi, hal ini tidak terjadi.

Pelajari lebih lanjut tentang arsitektur server

  1. Bagian I: Arsitektur Iteratif
  2. Bagian II. Server garpu
  3. Bagian III. Server pra-fork
  4. Bagian IV. Server dengan rangkaian eksekusi
  5. Bagian V. Server pra-utas
  6. Bagian VI. Arsitektur berbasis pol
  7. Bagian VII. arsitektur berbasis epoll

Sumber: www.habr.com

Tambah komentar