Oleh Vishnu Ram V, LG#123. Bahasa Indonesia oleh Triyan W. Nugroho
Pengantar
Apache adalah implementasi server HTTP open-source. Ia adalah web server yang paling populer di Internet. Survey mengenai web server yang dilakukan oleh Netcraft menunjukkan bahwa sekitar 70% website yang ada di Internet saat ini menggunakan Apache.
Performa Apache dapat ditingkatkan dengan menambahkan resource hardware seperti RAM, CPU yang lebih cepat, dan sebagainya. Namun, seringkali hasil yang sama bisa dicapai dengan melakukan konfigurasi pada server. Artikel ini akan mengulas cara untuk memperoleh performa maksimal Apache tanpa harus mengubah resource hardware, khususnya pada sistem Linux. Tentunya kita mengasumsikan resource hardware yang digunakan telah mencukupi, terutama RAM sehingga server tidak terlalu sering melakukan swap. Dua bagian pertama akan membahas mengenai opsi-opsi konfigurasi saat compile-time dan saat run-time. Bagian run-time mengasumsikan bahwa Apache dikompilasi dengan prefork MPM. Kompresi dan caching HTTP akan didiskusikan kemudian. Terakhir, kita akan mendiskusikan penggunaan server yang terpisah untuk melayani konten yang berbeda. Diasumsikan Anda memiliki pengetahuan dasar mengenai kompilasi dan konfigurasi Apache.
Opsi Konfigurasi Saat Compile-Time
Memuat hanya modul-modul yang dibutuhkan
Apache adalah sebuah program modular dimana administrator dapat memilih fungsi-fungsi yang akan dimasukkan pada server dengan memilih sejumlah modul. Modul-modul tersebut bisa dikompilasi secara statis sebagai bagian dari binary ‘httpd’, atau sebagai Dynamic Shared Object (DSO). Modul DSO bisa dikompilasi saat server sedang dibangun, atau ditambahkan kemudian melalui utility apxs, yang mengijinkan kompilasi dilakukan kemudian. Modul mod_so harus dikompilasi secara statis ke dalam Apache untuk mengaktifkan dukungan DSO.
Jalankanlah Apache dengan memuat hanya modul-modul yang diperlukan saja. Hal ini akan mengurangi penggunaan memory, sehingga akan meningkatkan performa server. Mengkompilasi modul secara statis juga akan menghemat penggunaan RAM, namun untuk menambahkan dan membuang sebuah modul, Anda harus mengkompilasi ulang Apache. Di sinilah mekanisme DSO dibutuhkan. Sekali modul mod_so dikompilasi secara stasis, modul-modul yang lain dapat ditambahkan atau dibuang dengan menggunakan perintah LoadModule pada file httpd.conf. Tentunya Anda juga harus mengkompilasi modul menggunakan ‘apxs’ jika modul tersebut tidak dikompilasi saat server dibangun.
Memilih MPM yang tepat
Apache dilengkapi dengan beberapa pilihan Multi-Processing Module (MPM) yang bertanggungjawab dalam mengambil port-port jaringan pada suatu sistem, menerima request, dan membuka proses anak untuk melayani request (lihat http://httpd.apache.org/docs/2.2/mpm.html). Hanya satu MPM yang bisa dimuat ke dalam server.
Pemilihan sebuah MPM akan bergantung pada beberapa faktor, seperti apakah sistem operasi mendukung thread, berapa banyak memory yang tersedia, pertimbangan skalabilitas dan stabilitas, apakah digunakan modul third-party yang tidak thread-safe, dan sebagainya.
Sistem Linux dapat memilih untuk menggunakan threaded MPM seperti worker atau non-threaded MPM seperti prefork.
MPM worker menggunakan beberapa anak proses dengan multi-threaded pada setiap anak, dan setiap thread menangani satu koneksi. Worker cepat dan sangat scalable, dan penggunaan memory relatif rendah. Cocok digunakan untuk penggunaan multi-prosesor. Namun di sisi lain, worker kurang toleran terhadap kesalahan modul, dan sebuah kesalahan thread dapat mempengaruhi semua thread di dalam sebuah anak proses.
MPM prefork menggunakan beberapa anak proses, dimana setiap anak menangani satu koneksi. Prefork cocok digunakan untuk satu atau dua sistem CPU. Kecepatannya rata-rata sama dengan worker, dan sangat toleran terhadap kesalahan modul dan crash pada anak proses. Namun penggunaan memorinya lebih tinggi, dan setiap peningkatan trafik akan meningkatkan penggunaan memori.
Opsi Konfigurasi Saat Run-Time
DNS Lookup
Direktif HostnameLookups akan mengaktifkan lookup DNS sehingga akan dilakukan pencatatan hostname dan bukan alamat IP. Hal ini akan menambahkan jeda waktu pada setiap request sebab lookup DNS harus diselesaikan terlebih dahulu sebelum request selesai. Pada Apache 1.3 dan seterusnya, HostnameLookups secara default diset pada posisi Off. Biarkanlah diset pada Off dan gunakan program semacam logresolve untuk mengambil alamat IP pada file log Apache. Logresolve terdapat di dalam distribusi Apache.
Ketika kita menggunakan direktif ‘Allow from’ atau ‘Deny from’, gunakan alamat IP dan bukan domain name atau hostname. Jika tidak, maka lookup DNS akan dilakukan dua kali untuk meyakinkan bahwa nama domain atau nama host tidak dipalsukan.
AllowOverride:
Jika AllowOverride tidak diset pada ‘None’, maka Apache akan berusaha membuka file .htaccess (yang ditentukan oleh direktif AccessFileName) dalam setiap direktori yang dikunjungi. Sebagai contoh:
DocumentRoot /var/www/html <Directory /> AllowOverride all </Directory>
Jika ada sebuah request yang dibuat untuk URI /index.html, maka Apache akan berusaha membuka file /.htaccess, /var/.htaccess, /var/www/.htaccess, dan /var/www/html/.htaccess. Pencarian file tersebut akan menambahkan jeda waktu. Jika file .htaccess diperlukan untuk suatu direktori, maka aktifkanlah hanya untuk direktori tersebut saja.
FollowSymLinks dan SymLinksIfOwnerMatch:
Jika opsi FollowSymLinks diset, maka server akan mengikuti symbolic link yang ada pada direktori. Jika SymLinksIfOwnerMatch diset, maka server akan mengikuti symbolic link hanya jika file atau direktori tujuan dimiliki oleh user yang sama dengan link tersebut.Jika SymLinksIfOwnerMatch diset, maka Apache juga akan melakukan system call tambahan untuk memastikan apakah kepemilikan link dan file tujuan adalah sama. System call tambahan juga dibutuhkan jika FollowSymLinks TIDAK diset.
Sebagai contoh:
DocumentRoot /var/www/html <Directory /> Options SymLinksIfOwnerMatch </Directory>
Untuk melayani sebuah request yang dibuat untuk URI /index.html, Apache akan melakukan lstat() pada /var, /var/www, /var/www/html, dan /var/www/html/index.html. System call tambahan tersebut akan menambahkan jeda waktu. Hasil dari lstat tidak disimpan, sehingga system call tersebut akan selalu terjadi setiap kali ada request.
Untuk mendapatkan performa maksimal, aktifkan FollowSymLinks dimanapun dan jangan mengaktifkan SymLinksIfOwnerMatch. Jika SymLinksIfOwnerMatch dibutuhkan untuk sebuah direktori, aktifkan opsi ini hanya untuk direktori tersebut saja.
Content Negotiation:
Hindarilah content negotiation untuk mendapatkan respon yang cepat. Jika sebuah situs membutuhkan content negotiation, gunakan file type-map dan bukan direktif Options MultiViews. Dengan MultiViews, Apache harus menscan direktori atau file, yang akan menambah jeda waktu.
MaxClients:
MaxClients mengatur batas maksimal request secara simultan yang mampu dilayani oleh server. Pembuatan proses anak akan dibatasi hingga nilai tersebut. Jika MaxClients diset terlalu rendah, banyaknya jumlah koneksi akan diletakkan pada antrian dan kemungkinan akan terjadi time-out padahal resource server tidak digunakan. Namun jika diset terlalu tinggi, akan menyebabkan server melakukan swapping sehingga waktu respon akan menurun secara drastis. Nilai yang tepat untuk MaxClients dapat dihitung dengan persamaan:
MaxClients = Jumlah RAM pada webserver / Ukuran maksimal proses anak (lihat http://modperlbook.org/html/ch11_01.html)
Ukuran proses anak untuk melayani file statis adalah sekitar 2-3 MB. Untuk konten dinamis seperti PHP, kebutuhannya mungkin sekitar 15 MB. Kolom RSS pada “=ps -ylc httpd –sort:rss=” menunjukkan penggunaan memori fisik yang tidak di-swap pada Apache dalam satuan kiloByte.
Jika jumlah pengakses lebih besar daripada MaxClients, request akan diletakkan pada antrian hingga jumlahnya mencapai direktif ListenBacklog. Naikkan ServerLimit untuk mengeset MaxClients di atas 256.
MinSpareServers, MaxSpareServers, dan StartServers:
MinSpareServers dan MaxSpareServers menentukan berapa banyak proses anak yang akan selalu aktif saat menunggu request. Jika MinSpareServers diset terlalu rendah dan ada sejumlah request, Apache harus membuat proses anak tambahan untuk melayani request tersebut. Membuat proses anak adalah relatif mahal. Jika server terlalu sibuk membuat proses-proses anak, ia tidak akan mampu untuk melayani request dari klien secara cepat. MaxSpareServers tidak boleh diset terlalu tinggi, sebab terlalu banyak proses anak akan menghabiskan resource.
Aturlah MinSpareServers dan MaxSpareServers sehingga Apache tidak harus membuat lebih dari 4 proses anak per detik (Apache mampu membuat maksimal 32 proses anak per detik). Jika lebih dari 4 proses anak dibuat per detik, sebuah pesan akan dicatatkan ke dalam ErrorLog.
Direktif StartServers mengeset jumlah proses anak yang dibuat saat startup. Apace akan terus membuat proses anak hingga nilai MinSpareServers tercapai. Hal ini tidak terlalu berpengaruh pada performa jika server tidak terlalu sering direstart. Namun jika ada banyak request dan Apache seringkali direstart, Anda harus mengeset direktif ini pada nilai yang relatif besar.
MaxRequestsPerChild:
Direktif MaxRequestsPerChild menentukan batas jumlah request yang akan ditangani oleh sebuah proses anak. Setelah mencapai MaxRequestsPerChild, proses anak akan mati. Secara default, direktif ini diset pada nilai 0, proses anak tidak akan mati. Anda perlu mengeset direktif ini pada nilai beberapa ribu, sehingga akan mencegah terjadinya kebocoran memori, dikarenakan proses akan mati setelah melayani sejumlah request. Jangan mengeset terlalu rendah, sebab membuat sebuah proses anak juga akan menyebabkan overhead.
KeepAlive dan KeepAliveTimeout:
Direktif KeepAlive mengijinkan beberapa request dikirimkan melalui koneksi TCP yang sama. Hal ini berguna terutama ketika melayani halaman HTML dengan banyak gambar. Jika KeepAlive diset pada Off, maka untuk setiap gambar, sebuah koneksi TCP yang terpisah harus dibuat. Overhead yang disebabkan oleh pembuatan koneksi TCP bisa dieliminasi dengan mengeset KeepAlive pada posisi On.
KeepAliveTimeout menentukan berapa lama waktu yang digunakan untuk menunggu request berikutnya. Anda sebaiknya mengeset direktif ini pada nilai yang rendah, mungkin antara dua hingga lima detik. Jika diset terlalu tinggi, proses anak akan selalu menunggu klien, padahal mereka bisa digunakan untuk melayani klien baru.
Kompresi dan Caching HTTP
Kompresi HTTP telah ada pada HTTP/1.1. Server menggunakan metode encoding gzip atau deflate untuk sebelum data dikirimkan ke klien. Klien kemudian melakukan dekompresi data tersebut. Tidak dibutuhkan instalasi software tambahan di sisi klien sebab sebagian besar browser yang ada telah mendukung metode ini. Menggunakan kompresi akan menghemat bandwidth dan meningkatkan waktu respon. Penelitian menunjukkan perolehan sekitar %75.2 dengan menggunakan kompresi (lihat http://www.speedupyoursite.com/18/18-2t.html).
Kompresi HTTP dapat diaktifkan pada Apache dengan menggunakan modul mod_deflate. Data dikompresi hanya jika browser meminta kompresi. Jika browser tidak meminta kompresi, maka akan diberikan data yang tidak dikompresi. Sebuah browser yang compression-aware akan memberitahu server bahwa ia menginginkan konten yang terkompresi melalui header HTTP request - “Accept-Encoding: gzip,deflate“. Kemudian server merespon dengan mengirimkan data terkompresi dan header respon diset pada “Content-Encoding: gzip“.
Contoh berikut menggunakan telnet untuk melihat header request dan respon.
bash-3.00$ telnet www.webperformance.org 80 Trying 24.60.234.27... Connected to www.webperformance.org (24.60.234.27). Escape character is '^]'. HEAD / HTTP/1.1 Host: www.webperformance.org Accept-Encoding: gzip,deflate HTTP/1.1 200 OK Date: Sat, 31 Dec 2005 02:29:22 GMT Server: Apache/2.0 X-Powered-By: PHP/5.1.1 Cache-Control: max-age=0 Expires: Sat, 31 Dec 2005 02:29:22 GMT Vary: Accept-Encoding Content-Encoding: gzip Content-Length: 20 Content-Type: text/html; charset=ISO-8859-1
Dalam melakukan caching, sebuah salinan data disimpan di sisi klien atau pada sebuah proxy server sehingga tidak harus selalu diambil dari server. Hal ini akan menghemat bandwidth, mengurangi beban pada server, dan mengurangi jeda waktu. Konrol cache dilakukan melalui header-header HTTP. Pada Apache, hal ini bisa didapatkan melalui modul mod_expires dan mod_headers. Ada juga caching di sisi server, dimana konten yang paling sering diakses disimpan pada memory sehingga bisa disajikan dengan lebih cepat. Modul mod_cache dapat digunakan untuk caching di sisi server, modul ini telah dinyatakan stabil pada Apache versi 2.2.
Server yang terpisah untuk konten statis dan dinamis
Pelayanan konten dinamis pada Apache membutuhkan RAM 3MB hingga 20MB. Nilai ini akan naik untuk mengakomodasi konten yang disajikan dan tidak akan turun hingga proses mati. Sebagai contoh, katakanlah suatu proses Apache naik hingga 20MB ketika melayani konten dinamis. Setelah melayani request, ia bebas untuk melayani request lain. Jika datang sebuah request untuk gambar, maka proses 20MB ini akan melayani konten statis yang sebenarnya bisa dilayani oleh proses 1MB saja. Hasilnya, penggunaan memory tidak efisien.
Gunakan sebuah Apache kecil (dengan modul minimum yang dikompilasi secara statis) sebagai server front-end untuk melayani konten statis. Request konten dinamis diteruskan pada Apache yang besar (dikompilasi dengan semua modul yang dibutuhkan). Menggunakan server front-end yang kecil memberikan keuntungan bahwa konten statis disajikan dengan cepat tanpa penggunaan memory yang besar dan hanya konten dinais saja yang diteruskan menuju server yang besar.
Forwarding request bisa didapatkan dengan menggunakan mod_proxy dan mod_rewrite. Kita asumsikan bahwa server Apache kecil menggunakan port 80 dan Apache besar menggunakan port 8088. Konfigurasi di bawah ini dapat kita terapkan pada Apache kecil untuk memforward semua request (kecuali request untuk gambar) ke Apache besar.
ProxyPassReverse / http://%{HTTP_HOST}:8088/
RewriteEngine on
RewriteCond %{REQUEST_URI} !.*.(gif|png|jpg)$
RewriteRule ^/(.*) http://%{HTTP_HOST}:8088/$1 [P]
Semua request, kecuali untuk gambar, akan di-proxy-kan ke server back-end. Respon akan diterima oleh server front-end dan diteruskan ke klien. Klien akan mengira bahwa semua respon datang dari satu server.
Penutup
Mengkonfigurasi Apache untuk mendapatkan performa maksimal membutuhkan beberapa trik. Tidak ada aturan yang baku dan cepat. Kita perlu memahami kebutuhan web server dan bereksperimen dengan berbagai opsi yang tersedia. Gunakan tool seperti ab dan httperf untuk mengukur performa web server. Server ringan seperti tux atau thttpd juga dapat digunakan sebagai server front-end. Jika digunakan sebuah server database, pastikan ia dioptimiskan sehingga tidak akan mengakibatkan bottleneck. Jika Anda menggunakan MySQL, mtop dapat digunakan untuk memonitor query yang lambat. Performa dari skrip PHP dapat ditingkatkan dengan menggunakan produk caching PHP seperti Turck MMCache. Ia akan mengurangi overhead karena kompilasi, dengan melakukan cache skrip PHP dalam kondisi terkompilasi.