Merancang Arsitektur Aplikasi Web untuk Trafik Tinggi: Apache HTTP Server, Java, dan Tomcat
Ketika sebuah aplikasi web baru diluncurkan, mungkin hanya puluhan pengguna yang mengaksesnya secara bersamaan. Pada kondisi tersebut, satu server Java dan satu database sering kali sudah mencukupi.
Namun, apa yang terjadi ketika jumlah pengguna meningkat menjadi ribuan atau puluhan ribu?
Aplikasi mulai lambat, koneksi database penuh, CPU meningkat, request mengalami timeout, bahkan server bisa berhenti merespons.
Masalah seperti ini tidak selalu disebabkan oleh spesifikasi server yang kurang tinggi. Sering kali penyebabnya adalah arsitektur aplikasi yang belum dirancang untuk menangani beban tinggi.
Dalam artikel ini, kita akan membahas cara membangun arsitektur aplikasi Java menggunakan Apache HTTP Server sebagai reverse proxy dan load balancer, Apache Tomcat sebagai application server, serta PostgreSQL sebagai database.
Kita juga akan mempelajari konfigurasi server, connection pooling, JVM tuning, load testing, dan strategi scaling.
Tutorial menggunakan contoh lingkungan AlmaLinux atau Linux keluarga RHEL, tetapi prinsip arsitekturnya dapat diterapkan pada distribusi Linux lainnya.
1. Memahami Masalah Aplikasi dengan Banyak Pengguna
Sebelum melakukan konfigurasi server, kita perlu memahami perbedaan beberapa istilah yang sering digunakan.
1.1 Jumlah Pengguna Bukan Jumlah Request
Misalnya sebuah aplikasi memiliki 10.000 pengguna aktif.
Apakah berarti server harus memproses 10.000 request secara bersamaan?
Tidak selalu.
Pengguna mungkin sedang membaca halaman, mengisi formulir, atau tidak melakukan aktivitas jaringan sama sekali.
Yang lebih penting untuk perencanaan kapasitas adalah jumlah request per detik, durasi pemrosesan, pola akses, dan puncak trafik.
Istilah yang perlu dipahami:
| Istilah | Penjelasan |
|---|---|
| Concurrent Users | Pengguna yang aktif dalam periode bersamaan |
| RPS | Requests per second |
| Throughput | Jumlah pekerjaan yang diselesaikan per satuan waktu |
| Latency | Waktu yang diperlukan untuk menyelesaikan request |
| P95 Latency | Waktu respons yang tidak dilampaui oleh sekitar 95% request |
| Error Rate | Persentase request yang gagal |
| Saturation | Kondisi ketika sumber daya mendekati batas kapasitas |
1.2 Contoh Perhitungan Sederhana
Bayangkan terdapat 10.000 pengguna aktif.
Setiap pengguna rata-rata melakukan satu request setiap 20 detik.
Perkiraan trafik:
10.000 / 20 = 500 RPS
Artinya aplikasi menerima rata-rata sekitar 500 request per detik.
Jika rata-rata waktu respons adalah 200 milidetik, berdasarkan Little's Law, perkiraan jumlah request yang sedang diproses secara bersamaan adalah:
Concurrent Requests = RPS × Response Time
= 500 × 0,2
= 100 request
Ini merupakan perhitungan pendekatan untuk sistem dalam kondisi stabil.
Hasilnya bukan berarti 100 thread pasti cukup. Jumlah thread yang dibutuhkan juga bergantung pada apakah request menggunakan I/O blocking, operasi asynchronous, database, atau layanan eksternal.
Selain itu, trafik nyata biasanya tidak merata.
Ketika jam sibuk, 500 RPS dapat meningkat beberapa kali lipat.
Karena itu, kapasitas harus direncanakan berdasarkan beban puncak dan diuji, bukan hanya berdasarkan rata-rata.
2. Mengapa Satu Tomcat Tidak Selalu Cukup?
Arsitektur sederhana biasanya seperti berikut:
Internet
|
v
Apache HTTP Server
|
v
Tomcat
|
v
PostgreSQL
Arsitektur ini tidak salah.
Untuk aplikasi dengan trafik rendah sampai menengah, satu Tomcat yang dikonfigurasi dengan baik dapat melayani banyak request.
Namun, terdapat beberapa keterbatasan:
- Seluruh request backend diproses oleh satu instance aplikasi.
- Jika Tomcat berhenti, aplikasi menjadi tidak tersedia.
- Deployment dapat menyebabkan downtime.
- Kapasitas dibatasi sumber daya satu server.
- Gangguan pada JVM dapat memengaruhi seluruh pengguna.
Solusi yang umum digunakan adalah menjalankan beberapa instance Tomcat.
Pendekatan ini disebut horizontal scaling.
3. Arsitektur yang Direkomendasikan
Untuk aplikasi Java dengan banyak pengguna, kita dapat menggunakan arsitektur berikut:
INTERNET
|
v
DNS / CDN
|
v
APACHE HTTP SERVER
Reverse Proxy
Load Balancer
|
+----------+----------+
| | |
v v v
TOMCAT 1 TOMCAT 2 TOMCAT 3
Java App Java App Java App
| | |
+----------+----------+
|
v
DATABASE POOL
|
v
POSTGRESQL
Apache HTTP Server bertugas menerima request pengguna dan meneruskannya ke Tomcat.
Tomcat menjalankan aplikasi Java.
PostgreSQL menyimpan data aplikasi.
Dalam arsitektur yang lebih lengkap, kita juga dapat menambahkan Redis, message broker, monitoring, dan database replica.
3.1 Fungsi Apache HTTP Server
Apache HTTP Server berperan sebagai pintu masuk aplikasi.
Tugasnya antara lain:
- Menerima koneksi HTTP dan HTTPS.
- Melakukan TLS termination.
- Menjalankan reverse proxy.
- Mendistribusikan request ke beberapa Tomcat.
- Menyajikan file statis.
- Menambahkan security headers.
- Mencatat access log.
- Menerapkan pembatasan request tertentu.
Dengan pendekatan ini, pengguna tidak perlu mengetahui alamat atau port Tomcat.
3.2 Fungsi Apache Tomcat
Tomcat menjalankan aplikasi Java berbasis Servlet.
Tomcat menangani:
- HTTP request yang diteruskan Apache.
- Eksekusi kode Java.
- Servlet dan aplikasi web.
- Business logic.
- Komunikasi database.
- Pembuatan HTTP response.
Tomcat bukan database dan bukan pengganti Apache HTTP Server.
Keduanya dapat digunakan bersama dengan peran berbeda.
3.3 Fungsi PostgreSQL
PostgreSQL menyimpan data aplikasi secara persisten.
Namun, database sering menjadi bottleneck ketika trafik meningkat.
Menambahkan Tomcat tidak otomatis meningkatkan kapasitas database.
Bahkan, jika setiap Tomcat membuka terlalu banyak koneksi, masalah justru dapat menjadi lebih buruk.
Karena itu, connection pooling dan optimasi query merupakan bagian penting dalam arsitektur.
4. Contoh Infrastruktur Server
Untuk tutorial ini, kita akan menggunakan rancangan berikut.
| Server | IP Internal | Fungsi |
|---|---|---|
| WEB-01 | 10.10.10.10 | Apache HTTP Server |
| APP-01 | 10.10.10.21 | Tomcat |
| APP-02 | 10.10.10.22 | Tomcat |
| APP-03 | 10.10.10.23 | Tomcat |
| DB-01 | 10.10.10.30 | PostgreSQL |
Semua alamat IP merupakan contoh jaringan internal.
Contoh domain:
app.example.com
Gunakan domain dan alamat IP sebenarnya pada implementasi.
4.1 Spesifikasi Awal Server
Sebagai titik awal untuk pengujian, bukan jaminan kapasitas:
| Komponen | CPU | RAM |
|---|---|---|
| Apache | 4 vCPU | 8 GB |
| Tomcat 1 | 8 vCPU | 16 GB |
| Tomcat 2 | 8 vCPU | 16 GB |
| Tomcat 3 | 8 vCPU | 16 GB |
| PostgreSQL | 16 vCPU | 64 GB |
Spesifikasi ini hanya contoh baseline.
Aplikasi yang banyak melakukan query kompleks mungkin membutuhkan database lebih besar.
Sebaliknya, aplikasi yang sebagian besar melayani respons cache dapat menggunakan sumber daya lebih kecil.
Penentuan spesifikasi final harus dilakukan melalui profiling dan load testing.
5. Instalasi Apache HTTP Server
Pada server WEB-01, gunakan AlmaLinux.
Jalankan:
sudo dnf update -y
Instal Apache HTTP Server:
sudo dnf install httpd mod_ssl -y
Periksa versi:
httpd -v
Jalankan service:
sudo systemctl enable --now httpd
Periksa status:
sudo systemctl status httpd
Jika berhasil, Apache akan berjalan sebagai service httpd.
5.1 Membuka Firewall
Jika menggunakan firewalld:
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
Port 80 dan 443 digunakan untuk menerima request pengguna.
Port Tomcat tidak perlu dibuka ke internet.
5.2 Memeriksa Modul Apache
Jalankan:
sudo httpd -M
Periksa keberadaan modul:
proxy_module
proxy_http_module
proxy_balancer_module
lbmethod_byrequests_module
headers_module
ssl_module
mpm_event_module
Untuk menampilkan modul tertentu:
sudo httpd -M | grep -E 'proxy|balancer|headers|ssl|mpm'
Modul-modul ini digunakan untuk reverse proxy, load balancing, dan konfigurasi koneksi.
Jika ada modul yang belum tersedia, periksa paket dan konfigurasi modul pada distribusi Linux yang digunakan.
6. Memahami Apache MPM
Apache HTTP Server menggunakan Multi-Processing Module atau MPM untuk mengelola proses dan thread.
Terdapat beberapa jenis MPM, di antaranya:
- Prefork.
- Worker.
- Event.
Untuk reverse proxy modern, MPM Event umumnya menjadi pilihan yang baik karena dapat menangani koneksi keep-alive secara lebih efisien dibanding pendekatan yang menahan satu worker selama seluruh waktu idle koneksi.
Namun, MPM Event bukan jaminan aplikasi akan lebih cepat. Kinerja tetap bergantung pada modul yang digunakan, kapasitas server, dan karakteristik request.
6.1 Konfigurasi MPM Event
Pada AlmaLinux, lokasi konfigurasi biasanya berada di:
/etc/httpd/conf.modules.d/
Pastikan hanya satu MPM aktif.
Periksa:
sudo httpd -M | grep mpm
Hasil yang diharapkan:
mpm_event_module (shared)
Kemudian buat konfigurasi:
sudo nano /etc/httpd/conf.d/mpm-tuning.conf
Isi:
<IfModule mpm_event_module>
ServerLimit 8
StartServers 2
ThreadsPerChild 25
MinSpareThreads 50
MaxSpareThreads 150
MaxRequestWorkers 200
MaxConnectionsPerChild 10000
</IfModule>
Penjelasan
ServerLimit menentukan batas proses server yang relevan untuk konfigurasi MPM.
StartServers menentukan jumlah proses yang dibuat ketika Apache dimulai.
ThreadsPerChild menentukan jumlah worker thread per proses.
MaxRequestWorkers membatasi jumlah worker yang dapat memproses request secara bersamaan.
MaxConnectionsPerChild menentukan berapa banyak koneksi yang ditangani suatu child process sebelum didaur ulang.
Dengan konfigurasi ini:
8 proses × 25 thread = 200 worker
Namun, angka 200 bukan berarti Apache hanya mampu mempertahankan 200 koneksi TCP. MPM Event dapat menangani koneksi idle keep-alive secara berbeda dari koneksi yang sedang menggunakan worker.
Konfigurasi ini merupakan titik awal konservatif untuk pengujian.
Jangan langsung mengubah MaxRequestWorkers menjadi ribuan tanpa mengukur penggunaan memori dan perilaku aplikasi.
7. Mengonfigurasi Reverse Proxy dan Load Balancer
Apache HTTP Server menyediakan mod_proxy dan mod_proxy_balancer untuk mendistribusikan request ke beberapa backend.
Kita akan menggunakan HTTP reverse proxy, bukan AJP.
Untuk sebagian besar kebutuhan aplikasi web biasa, HTTP reverse proxy lebih sederhana untuk dikonfigurasi dan dioperasikan.
7.1 Membuat Konfigurasi VirtualHost
Buat file:
sudo nano /etc/httpd/conf.d/app.conf
Isi konfigurasi awal:
<Proxy "balancer://java-cluster">
BalancerMember "http://10.10.10.21:8080" \
route=app1 retry=5
BalancerMember "http://10.10.10.22:8080" \
route=app2 retry=5
BalancerMember "http://10.10.10.23:8080" \
route=app3 retry=5
ProxySet lbmethod=byrequests
</Proxy>
<VirtualHost *:80>
ServerName app.example.com
ProxyRequests Off
ProxyPreserveHost On
ProxyTimeout 30
ProxyPass "/" "balancer://java-cluster/" \
connectiontimeout=3 timeout=30
ProxyPassReverse "/" "balancer://java-cluster/"
ErrorLog /var/log/httpd/app-error.log
CustomLog /var/log/httpd/app-access.log combined
</VirtualHost>
Konfigurasi ini merupakan tahap awal untuk pengujian HTTP internal. Sebelum digunakan untuk trafik publik, kita akan menambahkan HTTPS.
Penjelasan
ProxyRequests Off memastikan Apache tidak dioperasikan sebagai forward proxy terbuka.
ProxyPreserveHost On mempertahankan informasi Host asli ketika request diteruskan.
BalancerMember mendefinisikan backend Tomcat.
lbmethod=byrequests menggunakan metode distribusi berdasarkan jumlah request yang dialokasikan.
ProxyTimeout 30 menetapkan timeout proxy dalam satuan detik.
connectiontimeout=3 membatasi waktu pembentukan koneksi ke backend.
retry=5 mengatur waktu retry worker yang telah dianggap mengalami error, tetapi bukan interval pemeriksaan health check aktif.
Untuk kebutuhan health check aktif, Apache memerlukan konfigurasi tambahan seperti mod_proxy_hcheck.
7.2 Mengaktifkan Koneksi Proxy pada SELinux
Pada AlmaLinux dengan SELinux aktif, Apache mungkin tidak diizinkan membuat koneksi jaringan ke backend.
Periksa:
getenforce
Jika hasilnya Enforcing, konfigurasi SELinux dapat diperlukan:
sudo setsebool -P httpd_can_network_connect 1
Perintah ini memperluas izin koneksi jaringan bagi proses HTTPD.
Gunakan hanya jika memang dibutuhkan, dan tetap batasi akses backend menggunakan firewall serta jaringan internal.
Jangan menonaktifkan SELinux hanya untuk mengatasi masalah proxy.
7.3 Menguji Konfigurasi
Jalankan:
sudo apachectl configtest
Jika benar:
Syntax OK
Kemudian:
sudo systemctl restart httpd
Untuk perubahan berikutnya, gunakan reload setelah konfigurasi berhasil divalidasi:
sudo systemctl reload httpd
8. Menggunakan HTTPS
Aplikasi production sebaiknya menggunakan HTTPS.
Untuk server yang dapat diakses publik dengan DNS yang benar, sertifikat dapat diperoleh melalui layanan seperti Let's Encrypt.
Instal Certbot dan integrasi Apache dari repository yang sesuai dengan versi AlmaLinux:
sudo dnf install epel-release -y
sudo dnf install certbot python3-certbot-apache -y
Jika paket tidak tersedia, periksa repository resmi atau metode instalasi Certbot yang direkomendasikan untuk sistem operasi tersebut.
Jalankan:
sudo certbot --apache -d app.example.com
Ikuti petunjuk untuk memperoleh sertifikat dan mengaktifkan HTTPS.
Perintah ini membutuhkan domain yang benar-benar mengarah ke server dan mekanisme validasi domain yang dapat dijangkau.
8.1 Contoh Konfigurasi HTTPS
Setelah sertifikat tersedia, konfigurasi HTTPS dapat berbentuk:
<VirtualHost *:80>
ServerName app.example.com
Redirect permanent / https://app.example.com/
</VirtualHost>
<VirtualHost *:443>
ServerName app.example.com
SSLEngine on
SSLCertificateFile \
/etc/letsencrypt/live/app.example.com/fullchain.pem
SSLCertificateKeyFile \
/etc/letsencrypt/live/app.example.com/privkey.pem
ProxyRequests Off
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"
ProxyTimeout 30
ProxyPass "/" "balancer://java-cluster/" \
connectiontimeout=3 timeout=30
ProxyPassReverse "/" "balancer://java-cluster/"
ErrorLog /var/log/httpd/app-ssl-error.log
CustomLog /var/log/httpd/app-ssl-access.log combined
</VirtualHost>
Blok balancer://java-cluster yang dibuat sebelumnya tetap diperlukan dan tidak perlu didefinisikan ulang.
Hindari mempertahankan dua VirtualHost berbeda dengan nama dan port yang sama. Ketika berpindah dari HTTP ke HTTPS, sesuaikan atau ganti konfigurasi awal.
8.2 Keamanan Header Forwarding
Header seperti X-Forwarded-For dan X-Forwarded-Proto sering digunakan agar backend mengetahui informasi request asli.
Namun, header yang dikirim pengguna tidak boleh langsung dianggap tepercaya.
Apache dapat menambahkan informasi forwarding, dan Tomcat perlu dikonfigurasi untuk hanya mempercayai proxy yang diketahui.
Pastikan backend tidak dapat diakses langsung dari internet.
Jika terdapat CDN atau load balancer lain di depan Apache, pengaturan trusted proxy harus disesuaikan dengan topologi sebenarnya.
9. Instalasi Java dan Tomcat
Sekarang kita beralih ke APP-01, APP-02, dan APP-03.
Lakukan konfigurasi yang sama pada ketiga server.
9.1 Instalasi Java
Jalankan:
sudo dnf install java-21-openjdk-headless -y
Periksa:
java -version
Gunakan Java 21 yang kompatibel dengan aplikasi.
9.2 Membuat User Tomcat
Untuk keamanan, jangan menjalankan Tomcat menggunakan user root.
Buat user sistem:
sudo useradd --system \
--home-dir /opt/tomcat \
--shell /sbin/nologin \
tomcat
Siapkan direktori:
sudo mkdir -p /opt/tomcat
9.3 Menginstal Tomcat
Gunakan rilis Tomcat 10.1.x terbaru yang masih didukung dan sudah diverifikasi dari situs resmi.
Download melalui:
Contoh prosedur:
cd /tmp
Download arsip binary Tomcat dari mirror resmi Apache, kemudian ekstrak:
sudo tar -xzf apache-tomcat-10.1.x.tar.gz \
-C /opt/tomcat \
--strip-components=1
Ganti 10.1.x dengan versi yang benar-benar diunduh.
Periksa checksum atau signature rilis sebelum digunakan.
Atur kepemilikan:
sudo chown -R tomcat:tomcat /opt/tomcat
Berikan izin eksekusi:
sudo chmod +x /opt/tomcat/bin/*.sh
Catatan kompatibilitas: Tomcat 10.1 menggunakan Jakarta Servlet API. Aplikasi lama yang masih menggunakan package javax.servlet tidak bisa langsung diasumsikan kompatibel dan mungkin memerlukan migrasi. Untuk aplikasi Java EE lama, pemilihan versi Tomcat harus disesuaikan dengan framework dan API aplikasi.
10. Konfigurasi Tomcat untuk Trafik Tinggi
File utama konfigurasi Tomcat adalah:
/opt/tomcat/conf/server.xml
Sebelum mengubahnya, buat backup:
sudo cp /opt/tomcat/conf/server.xml \
/opt/tomcat/conf/server.xml.bak
Cari elemen Connector HTTP.
Gunakan contoh berikut sebagai pengganti Connector HTTP 8080 yang lama, bukan menambahkan Connector duplikat pada port yang sama.
<Connector
port="8080"
protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="200"
minSpareThreads="25"
maxConnections="2000"
acceptCount="200"
connectionTimeout="10000"
keepAliveTimeout="10000"
maxKeepAliveRequests="100"
maxHttpRequestHeaderSize="16384"
enableLookups="false"
proxyName="app.example.com"
proxyPort="443"
scheme="https"
secure="true"
URIEncoding="UTF-8"
/>
Memahami Konfigurasi Connector
| Parameter | Nilai Awal | Fungsi |
|---|---|---|
| maxThreads | 200 | Maksimum request processing threads |
| minSpareThreads | 25 | Thread minimum yang dipertahankan |
| maxConnections | 2000 | Batas koneksi yang diterima Connector |
| acceptCount | 200 | Panjang antrean koneksi tingkat OS yang diminta |
| connectionTimeout | 10000 ms | Timeout koneksi/request awal |
| keepAliveTimeout | 10000 ms | Waktu menunggu request berikutnya |
| maxKeepAliveRequests | 100 | Maksimum request per koneksi keep-alive |
Nilai-nilai tersebut adalah baseline pengujian, bukan angka ideal universal.
Perlu diketahui bahwa maxThreads bukan batas jumlah pengguna login dan bukan jumlah koneksi database.
Pada model request synchronous, thread digunakan selama request diproses. Jika seluruh thread sibuk, request lain dapat menunggu atau akhirnya gagal sesuai batas koneksi dan antrean.
Meningkatkan maxThreads secara berlebihan dapat meningkatkan penggunaan memori, context switching, dan tekanan terhadap database.
10.1 Mengapa Tidak Langsung Menggunakan 1.000 Thread?
Bayangkan satu instance Tomcat memiliki:
maxThreads = 1000
Jika seluruh request melakukan query database, kita dapat menciptakan tekanan yang sangat besar terhadap connection pool dan database.
Thread yang banyak tidak otomatis berarti throughput meningkat.
Sebagai ilustrasi:
200 thread
|
v
30 database connections
|
v
PostgreSQL
Jika 200 request memerlukan database secara bersamaan, sebagian harus menunggu koneksi.
Jika antrean terlalu panjang, latency akan meningkat.
Karena itu, thread pool, database pool, dan kemampuan database harus dirancang bersama.
11. Konfigurasi JVM untuk Tomcat
Tomcat menjalankan aplikasi Java di atas Java Virtual Machine atau JVM.
JVM membutuhkan memori untuk:
-
Java Heap.
-
Thread Stack.
-
Metaspace.
-
Code Cache.
-
Direct Buffer.
-
Native Memory.
Kesalahan yang cukup umum adalah mengalokasikan hampir seluruh RAM server sebagai heap.
Misalnya server memiliki RAM 16 GB, kemudian JVM diberi:
-Xmx15g
Konfigurasi tersebut berisiko karena sistem operasi dan native memory JVM tetap membutuhkan RAM.
11.1 Contoh Konfigurasi Heap
Untuk server aplikasi dengan RAM 16 GB, kita dapat memulai pengujian dengan:
-Xms4g
-Xmx8g
Artinya:
- Heap awal 4 GB.
- Heap maksimum 8 GB.
Sisa memori digunakan untuk kebutuhan lain, termasuk native memory, filesystem cache, dan sistem operasi.
Jumlah ideal harus ditentukan dari pengukuran heap occupancy, allocation rate, garbage collection, dan penggunaan memori aktual.
11.2 Konfigurasi JVM melalui systemd
Buat file service:
sudo nano /etc/systemd/system/tomcat.service
Contoh:
[Unit]
Description=Apache Tomcat
After=network.target
[Service]
Type=simple
User=tomcat
Group=tomcat
WorkingDirectory=/opt/tomcat
Environment="CATALINA_HOME=/opt/tomcat"
Environment="CATALINA_BASE=/opt/tomcat"
Environment="JAVA_OPTS=-Xms4g -Xmx8g -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/tomcat/logs"
ExecStart=/opt/tomcat/bin/catalina.sh run
Restart=on-failure
RestartSec=5
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
Perhatikan bahwa file service ini menggunakan JAVA_OPTS sebagai contoh konfigurasi JVM.
Untuk instalasi Tomcat dengan beberapa instance atau kebutuhan operasional lebih kompleks, gunakan konfigurasi environment yang dipisahkan dengan jelas.
Aktifkan service:
sudo systemctl daemon-reload
sudo systemctl enable --now tomcat
Periksa:
sudo systemctl status tomcat
Lihat log:
sudo journalctl -u tomcat -f
11.3 Mengapa Menggunakan G1GC?
G1 Garbage Collector merupakan pilihan umum untuk aplikasi Java dengan heap menengah hingga besar.
G1 berusaha menyeimbangkan throughput dan pause time.
Namun, jangan langsung menambahkan banyak parameter GC tanpa mengetahui masalah yang ingin diselesaikan.
Pada Java 21, G1 sudah menjadi default untuk banyak konfigurasi server JVM.
Karena itu, -XX:+UseG1GC pada contoh ini bersifat eksplisit, bukan optimasi khusus yang pasti meningkatkan kinerja.
12. Menghubungkan Tomcat ke Apache
Pada setiap server Tomcat, pastikan aplikasi Java sudah ter-deploy dan dapat diakses melalui jaringan internal.
Contoh:
http://10.10.10.21:8080/
http://10.10.10.22:8080/
http://10.10.10.23:8080/
Jika aplikasi memiliki context path, misalnya /myapp, URL pengujian harus menyesuaikan.
Dari WEB-01, uji:
curl -I http://10.10.10.21:8080/
Lakukan juga untuk APP-02 dan APP-03.
Untuk endpoint kesehatan aplikasi, lebih baik menggunakan URL khusus seperti:
/health
Endpoint tersebut sebaiknya memberikan status yang jelas tanpa membuka informasi sensitif.
12.1 Firewall Antarserver
Atur firewall agar port 8080 hanya dapat diakses dari WEB-01 atau subnet internal yang disetujui.
Jangan membuka port Tomcat langsung ke internet.
Pada contoh ini, komunikasi Apache ke Tomcat menggunakan HTTP melalui jaringan internal tepercaya.
Jika lalu lintas melewati jaringan yang tidak sepenuhnya tepercaya, gunakan TLS antara Apache dan Tomcat juga.
12.2 Pengaturan Reverse Proxy pada Tomcat
Jika Tomcat hanya menerima request dari Apache, kita dapat mengatur atribut proxy pada Connector.
Namun, untuk topologi yang melibatkan beberapa proxy, CDN, atau protokol berbeda, pertimbangkan penggunaan RemoteIpValve dengan daftar trusted proxy yang eksplisit.
Jangan mempercayai header X-Forwarded-* dari sembarang sumber.
13. Load Balancing: Bagaimana Request Dibagikan?
Misalnya terdapat tiga Tomcat:
Tomcat 1
Tomcat 2
Tomcat 3
Apache menggunakan algoritma byrequests.
Secara sederhana, request akan didistribusikan berdasarkan jumlah request dan bobot worker.
Contoh ilustratif:
Request 1 → Tomcat 1
Request 2 → Tomcat 2
Request 3 → Tomcat 3
Request 4 → Tomcat 1
Namun, distribusi aktual tidak harus mengikuti urutan persis seperti itu.
Algoritma load balancer mempertimbangkan konfigurasi worker dan kondisi backend.
13.1 Apakah Semua Request Memiliki Beban yang Sama?
Tidak.
Contohnya:
GET /products
Mungkin hanya membutuhkan 20 milidetik.
Sedangkan:
POST /generate-report
Bisa membutuhkan beberapa detik.
Artinya, pembagian jumlah request yang merata tidak selalu menghasilkan pembagian beban CPU yang merata.
Untuk aplikasi dengan request yang durasinya sangat bervariasi, algoritma lain atau pemisahan workload dapat memberikan hasil lebih baik.
13.2 Mengapa Perlu Health Check?
Jika Tomcat 2 mengalami gangguan, load balancer sebaiknya tidak terus mengirim request kepadanya.
Apache memiliki mekanisme penanganan worker error dan dapat dikonfigurasi dengan health check aktif.
Untuk production, gunakan endpoint readiness yang memeriksa apakah aplikasi benar-benar siap menerima trafik.
Health check harus dibedakan dari sekadar proses Tomcat yang masih hidup.
Tomcat bisa saja berjalan, tetapi aplikasi belum siap karena database tidak dapat diakses atau proses inisialisasi belum selesai.
14. Session Management pada Banyak Tomcat
Salah satu masalah yang sering muncul setelah menggunakan load balancer adalah pengguna tiba-tiba logout.
Bayangkan pengguna melakukan login melalui Tomcat 1.
Session disimpan di memori Tomcat 1.
Pada request berikutnya, Apache mengarahkan pengguna ke Tomcat 2.
Jika session hanya tersedia di Tomcat 1, Tomcat 2 tidak mengenali pengguna tersebut.
Ada beberapa pendekatan untuk mengatasi masalah ini.
14.1 Sticky Session
Sticky session berusaha mengarahkan request dari session yang sama ke backend yang sama.
Apache mendukung mekanisme sticky session melalui konfigurasi load balancer.
Contoh:
<Proxy "balancer://java-cluster">
BalancerMember "http://10.10.10.21:8080" route=app1
BalancerMember "http://10.10.10.22:8080" route=app2
BalancerMember "http://10.10.10.23:8080" route=app3
ProxySet lbmethod=byrequests \
stickysession=JSESSIONID|jsessionid
</Proxy>
Pada Tomcat APP-01, sesuaikan atribut jvmRoute pada elemen Engine yang sudah ada:
<Engine name="Catalina"
defaultHost="localhost"
jvmRoute="app1">
APP-02 menggunakan:
jvmRoute="app2"
APP-03 menggunakan:
jvmRoute="app3"
Konfigurasi ini membantu Apache mengenali tujuan session berdasarkan route.
Kelemahannya, ketika Tomcat yang menyimpan session gagal, session pengguna dapat hilang.
14.2 Shared Session Menggunakan Redis
Untuk aplikasi yang membutuhkan ketersediaan lebih tinggi, session dapat disimpan dalam penyimpanan bersama.
Contohnya:
Apache
|
+--------+--------+
| | |
Tomcat 1 Tomcat 2 Tomcat 3
| | |
+--------+--------+
|
Redis
Dengan pendekatan ini, ketiga instance dapat mengakses informasi session yang sama.
Untuk aplikasi Spring Boot, integrasi dapat dilakukan menggunakan Spring Session Redis.
Namun, Redis juga perlu dirancang agar tidak menjadi single point of failure.
14.3 Stateless Authentication
Alternatif lain adalah membangun backend yang tidak bergantung pada HTTP session lokal.
Contohnya menggunakan token autentikasi dengan mekanisme validasi yang tepat.
Pendekatan stateless mempermudah horizontal scaling, tetapi tidak otomatis menyelesaikan persoalan logout, pencabutan token, keamanan cookie, dan masa berlaku autentikasi.
Rekomendasi: Untuk aplikasi baru, prioritaskan desain yang tidak bergantung pada memori session satu Tomcat. Untuk aplikasi legacy, sticky session dapat menjadi solusi transisi yang lebih mudah.
15. Database Connection Pooling
Sekarang kita membahas salah satu bagian terpenting dalam arsitektur aplikasi Java dengan trafik tinggi.
Misalnya kita memiliki:
3 Tomcat
200 thread per Tomcat
Total maksimum request processing threads:
3 × 200 = 600 thread
Apakah PostgreSQL harus memiliki 600 koneksi?
Tidak.
Thread HTTP dan koneksi database adalah dua sumber daya yang berbeda.
Jika setiap Tomcat memiliki pool 30 koneksi:
Tomcat 1 → 30 koneksi
Tomcat 2 → 30 koneksi
Tomcat 3 → 30 koneksi
Total = 90 koneksi
Koneksi database digunakan secara bergantian oleh request yang membutuhkan akses database.
15.1 Mengapa Connection Pool Penting?
Membuat koneksi database baru membutuhkan waktu dan sumber daya.
Connection pool mempertahankan sejumlah koneksi agar dapat digunakan kembali.
Keuntungannya:
- Mengurangi overhead pembuatan koneksi.
- Membatasi jumlah koneksi database.
- Membantu mengendalikan tekanan terhadap PostgreSQL.
- Memungkinkan monitoring penggunaan koneksi.
Namun, pool yang terlalu besar justru dapat membebani database.
15.2 Konfigurasi HikariCP pada Spring Boot
Jika aplikasi menggunakan Spring Boot dengan JDBC atau JPA dan HikariCP, konfigurasi dapat ditempatkan pada application.properties.
spring.datasource.url=jdbc:postgresql://10.10.10.30:5432/appdb
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}
spring.datasource.hikari.maximum-pool-size=30
spring.datasource.hikari.minimum-idle=10
spring.datasource.hikari.connection-timeout=3000
spring.datasource.hikari.validation-timeout=1000
spring.datasource.hikari.idle-timeout=600000
spring.datasource.hikari.max-lifetime=1800000
Penjelasan:
| Parameter | Fungsi |
|---|---|
| maximum-pool-size | Maksimum koneksi dalam pool |
| minimum-idle | Target minimum koneksi idle |
| connection-timeout | Maksimum waktu menunggu koneksi |
| validation-timeout | Timeout validasi koneksi |
| idle-timeout | Waktu sebelum koneksi idle dapat ditutup |
| max-lifetime | Batas umur koneksi |
Angka 30 merupakan contoh awal. Nilai terbaik harus diuji berdasarkan durasi query, tingkat pemakaian koneksi, dan kapasitas database.
Jika menggunakan aplikasi WAR non-Spring Boot, connection pool juga dapat dikonfigurasi melalui DataSource JNDI Tomcat. Jangan menggunakan dua pool yang saling bertumpuk tanpa alasan yang jelas.
16. Konfigurasi PostgreSQL
PostgreSQL juga perlu disesuaikan dengan kapasitas server dan karakteristik workload.
Pada Linux, lokasi postgresql.conf bergantung pada metode instalasi dan versi PostgreSQL.
Kita dapat menemukannya dengan menjalankan:
SHOW config_file;
16.1 Contoh Konfigurasi Awal
Untuk database server khusus dengan RAM 64 GB, contoh baseline:
max_connections = 150
shared_buffers = 16GB
effective_cache_size = 48GB
work_mem = 16MB
maintenance_work_mem = 1GB
checkpoint_completion_target = 0.9
Ini bukan konfigurasi yang cocok untuk semua aplikasi.
shared_buffers sebesar sekitar 25% RAM merupakan titik awal yang umum untuk server database khusus.
effective_cache_size merupakan estimasi cache yang tersedia bagi query planner, bukan alokasi memori langsung.
work_mem dapat digunakan oleh beberapa operasi dalam satu query dan oleh banyak session sekaligus. Karena itu, jangan menaikkannya terlalu tinggi tanpa memahami pola query.
max_connections juga tidak sebaiknya dinaikkan tanpa batas karena PostgreSQL mengalokasikan sumber daya berdasarkan kapasitas koneksi.
16.2 Menghitung Kebutuhan Koneksi
Misalnya:
3 Tomcat × 30 koneksi = 90
Tambahkan kebutuhan koneksi untuk:
- Monitoring.
- Administrasi.
- Background jobs.
- Migrasi database.
- Aplikasi internal lainnya.
Jika aplikasi berkembang menjadi enam Tomcat:
6 × 30 = 180 koneksi
Konfigurasi PostgreSQL dengan max_connections=150 tidak lagi cukup untuk seluruh pool mencapai maksimum secara bersamaan.
Solusinya tidak harus menaikkan koneksi PostgreSQL. Kita dapat meninjau ukuran pool, mempercepat query, mengurangi durasi transaksi, atau mempertimbangkan PgBouncer.
16.3 Memantau Koneksi PostgreSQL
Jalankan:
SELECT
state,
COUNT(*)
FROM pg_stat_activity
GROUP BY state;
Untuk melihat query yang sedang berjalan:
SELECT
pid,
state,
now() - query_start AS duration,
query
FROM pg_stat_activity
WHERE state = 'active'
ORDER BY duration DESC;
Periksa juga transaksi yang terlalu lama, query lambat, lock contention, dan penggunaan I/O.
17. Caching untuk Mengurangi Beban Backend
Tidak semua request harus memanggil database.
Misalnya aplikasi memiliki endpoint:
GET /api/categories
Data kategori mungkin hanya berubah beberapa kali dalam sehari.
Jika setiap request selalu membaca PostgreSQL, database melakukan pekerjaan berulang yang sebenarnya dapat dikurangi.
Kita dapat menggunakan caching.
17.1 Cache di Apache
Apache dapat menyajikan file statis seperti CSS, JavaScript, dan gambar tanpa meneruskannya ke Tomcat.
Untuk aplikasi React, hasil build frontend juga dapat dilayani langsung oleh Apache.
Contoh:
DocumentRoot "/var/www/app"
<Directory "/var/www/app">
Require all granted
AllowOverride None
</Directory>
ProxyPass "/api/" "balancer://java-cluster/api/"
ProxyPassReverse "/api/" "balancer://java-cluster/api/"
Dalam konfigurasi ini, request /api/ diteruskan ke backend, sedangkan file frontend dilayani Apache.
Jika menggunakan React Router dengan client-side routing, perlu konfigurasi fallback ke index.html untuk URL frontend yang bukan file statis.
Jangan menerapkan cache publik untuk respons yang berisi informasi pribadi atau data sensitif.
17.2 Cache Menggunakan Redis
Redis dapat digunakan untuk menyimpan hasil query atau data yang sering diakses.
Contoh alur:
Request
|
v
Cek Redis
|
+-- Cache tersedia → Return data
|
+-- Cache kosong
|
v
PostgreSQL
|
v
Simpan Cache
|
v
Return data
Cache dapat mengurangi latency dan beban database, tetapi membutuhkan strategi invalidasi yang benar.
Data yang sering berubah, seperti saldo rekening atau stok kritis, tidak boleh di-cache sembarangan tanpa mempertimbangkan konsistensi.
18. Optimasi Aplikasi Java
Konfigurasi server yang baik tidak akan banyak membantu jika kode aplikasi tidak efisien.
Contohnya:
for (Product product : products) {
loadProductDetails(product.getId());
}
Jika loadProductDetails() melakukan satu query database untuk setiap produk, aplikasi dapat mengalami masalah N+1 query.
Untuk 1.000 produk, jumlah query dapat menjadi sangat besar.
Beberapa pendekatan optimasi:
- Gunakan pagination.
- Hindari N+1 query.
- Buat indeks database yang sesuai.
- Gunakan batch processing.
- Batasi ukuran respons JSON.
- Hindari transaksi database terlalu lama.
- Terapkan timeout untuk layanan eksternal.
- Gunakan asynchronous processing untuk pekerjaan yang tidak harus selesai dalam HTTP request.
Contoh pagination pada Spring Data JPA:
@GetMapping("/products")
public Page<Product> getProducts(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size) {
int safeSize = Math.min(Math.max(size, 1), 100);
return productRepository.findAll(
PageRequest.of(page, safeSize)
);
}
Dengan pagination, aplikasi tidak perlu mengirim ratusan ribu record sekaligus.
19. Monitoring Apache, Tomcat, dan Database
Arsitektur high traffic membutuhkan observability.
Tanpa monitoring, kita hanya mengetahui aplikasi lambat setelah pengguna melaporkan masalah.
19.1 Monitoring Apache
Apache menyediakan mod_status.
Contoh konfigurasi yang hanya mengizinkan akses dari localhost:
<Location "/server-status">
SetHandler server-status
Require local
</Location>
Pastikan lokasi ini tidak tertimpa aturan reverse proxy umum. Jika menggunakan ProxyPass "/", buat pengecualian sebelum aturan proxy tersebut:
ProxyPass "/server-status" "!"
Untuk membaca status dari server Apache:
curl http://127.0.0.1/server-status?auto
Informasi yang dapat dipantau antara lain worker aktif, worker idle, request, dan throughput.
Jangan membuka halaman status ke publik karena dapat membocorkan informasi operasional.
19.2 Monitoring Tomcat dan JVM
Pantau metrik berikut:
CPU Usage
Heap Used
GC Pause
Thread Count
Busy Threads
HTTP Request Rate
HTTP Error Rate
Request Latency
Database Pool Active
Database Pool Pending
Untuk aplikasi Spring Boot, Micrometer dan Spring Boot Actuator dapat digunakan untuk mengekspos metrik aplikasi.
Metrik dapat dikumpulkan menggunakan Prometheus dan divisualisasikan dengan Grafana.
Untuk aplikasi Java legacy, JMX dapat menjadi salah satu sumber metrik JVM dan Tomcat.
19.3 Monitoring Database
Pantau:
Active Connections
Idle Connections
Long Running Queries
Lock Waits
Cache Hit Ratio
Disk I/O
WAL Activity
Replication Lag
Khusus untuk database, jangan hanya melihat CPU.
Query yang menunggu lock dapat menyebabkan aplikasi lambat meskipun penggunaan CPU relatif rendah.
20. Melakukan Load Testing
Setelah konfigurasi selesai, kita perlu mengukur kapasitas sistem.
Jangan langsung mengasumsikan bahwa tiga Tomcat mampu menangani 10.000 pengguna.
Gunakan alat load testing seperti:
- Apache JMeter.
- k6.
- Gatling.
Contoh sederhana menggunakan k6:
import http from 'k6/http';
import { sleep, check } from 'k6';
export const options = {
stages: [
{ duration: '2m', target: 100 },
{ duration: '5m', target: 300 },
{ duration: '5m', target: 500 },
{ duration: '2m', target: 0 }
]
};
export default function () {
const res = http.get(
'https://app.example.com/api/products'
);
check(res, {
'status 200': (r) => r.status === 200
});
sleep(1);
}
Perlu dipahami bahwa target: 500 berarti 500 virtual users, bukan 500 RPS.
RPS aktual dipengaruhi oleh waktu respons, durasi sleep, dan perilaku script.
Jalankan pengujian hanya pada sistem yang Anda miliki atau yang telah memberikan izin.
20.1 Apa yang Harus Diukur?
Contoh target awal yang dapat ditentukan berdasarkan kebutuhan bisnis:
| Metrik | Contoh Target |
|---|---|
| Throughput | 500 RPS |
| P95 latency | Di bawah 500 ms |
| Error rate | Di bawah 1% |
| CPU aplikasi | Memiliki headroom |
| Database pool | Tidak terus-menerus penuh |
Target tersebut hanyalah ilustrasi, bukan standar universal.
Lakukan pengujian bertahap dengan beban meningkat.
Jika latency meningkat tajam ketika RPS bertambah sedikit, kemungkinan sistem mulai mencapai titik saturasi.
21. Mengidentifikasi Bottleneck
Misalnya hasil load testing menunjukkan:
Apache CPU : 20%
Tomcat CPU : 35%
PostgreSQL CPU : 90%
P95 Latency : 2.500 ms
Dalam kondisi ini, menambahkan Tomcat kemungkinan bukan solusi utama.
Bottleneck mungkin berada pada database.
Sebaliknya:
Apache CPU : 15%
Tomcat CPU : 95%
PostgreSQL CPU : 30%
Kemungkinan bottleneck berada pada aplikasi Java, meskipun tetap perlu diperiksa apakah CPU tinggi berasal dari business logic, garbage collection, serialisasi JSON, atau proses lainnya.
Contoh lain:
Tomcat CPU : 20%
DB CPU : 25%
Busy Threads : 200/200
Ini dapat menunjukkan banyak thread sedang menunggu I/O, lock, atau layanan eksternal.
Karena itu, monitoring harus dikombinasikan dengan thread dump, profiling, dan analisis query.
22. High Availability: Jangan Lupakan Apache
Arsitektur dengan tiga Tomcat memang mengurangi ketergantungan pada satu application server.
Namun, jika hanya ada satu Apache HTTP Server:
Internet
|
Apache 1
|
3 Tomcat
Apache masih menjadi single point of failure.
Jika Apache berhenti, seluruh aplikasi tidak dapat diakses meskipun ketiga Tomcat masih berjalan.
Untuk high availability, gunakan minimal dua reverse proxy.
Contoh:
INTERNET
|
v
LOAD BALANCER
|
+---------+---------+
| |
v v
APACHE 1 APACHE 2
| |
+---------+---------+
|
+---------+---------+
| | |
v v v
TOMCAT 1 TOMCAT 2 TOMCAT 3
| | |
+---------+---------+
|
v
DATABASE
Load balancer paling depan dapat berupa layanan managed load balancer, perangkat khusus, atau mekanisme HA lain yang sesuai.
Untuk infrastruktur on-premise, Keepalived dengan virtual IP dapat menjadi salah satu pendekatan, tetapi membutuhkan desain jaringan dan mekanisme failover yang tepat.
Perlu diingat bahwa database tunggal juga masih menjadi single point of failure.
High availability yang sesungguhnya membutuhkan rancangan failover untuk seluruh komponen kritis, termasuk database, cache, penyimpanan, dan jalur jaringan.
23. Strategi Deployment Tanpa Downtime
Dengan beberapa Tomcat, kita dapat melakukan rolling deployment.
Misalnya terdapat tiga instance:
Tomcat 1
Tomcat 2
Tomcat 3
Langkah deployment:
- Hentikan pengiriman request baru ke Tomcat 1.
- Tunggu request yang sedang berjalan selesai.
- Deploy versi aplikasi terbaru.
- Jalankan health check.
- Masukkan Tomcat 1 kembali ke load balancer.
- Ulangi untuk Tomcat 2 dan Tomcat 3.
Apache mendukung pengelolaan status worker, termasuk mode drain, melalui mekanisme balancer.
Namun, zero-downtime deployment juga memerlukan kompatibilitas session, migrasi database yang aman, dan kompatibilitas API antara versi aplikasi lama dan baru.
24. Konfigurasi Ideal: Rangkuman Awal
Berikut contoh baseline konfigurasi untuk arsitektur dengan tiga Tomcat.
| Komponen | Konfigurasi Awal |
|---|---|
| Apache MPM | Event |
| Apache MaxRequestWorkers | 200 |
| Reverse Proxy | mod_proxy_http |
| Load Balancer | mod_proxy_balancer |
| Algoritma | byrequests |
| Tomcat Instances | 3 |
| Tomcat maxThreads | 200 per instance |
| Tomcat maxConnections | 2000 per instance |
| Tomcat acceptCount | 200 |
| JVM Heap | 4–8 GB per instance |
| Garbage Collector | G1GC |
| HikariCP max pool | 30 per instance |
| PostgreSQL max_connections | 150 |
| PostgreSQL shared_buffers | 16 GB pada RAM 64 GB |
| HTTPS | Wajib untuk akses publik |
| Monitoring | Prometheus/Grafana atau setara |
| Load Testing | k6/JMeter |
Konfigurasi ini adalah titik awal yang harus divalidasi, bukan formula universal.
Kapasitas sistem sangat dipengaruhi oleh ukuran respons, kompleksitas business logic, efisiensi query, durasi transaksi, pola cache, dan karakteristik hardware.
25. Kesalahan yang Sering Dilakukan
Ada beberapa kesalahan umum ketika mencoba meningkatkan performa aplikasi Java.
Pertama, menaikkan maxThreads tanpa mengukur.
Thread yang terlalu banyak dapat memperbesar antrean pekerjaan dan tekanan pada database.
Kedua, menaikkan max_connections PostgreSQL secara berlebihan.
Lebih banyak koneksi tidak otomatis membuat query lebih cepat.
Ketiga, mengalokasikan hampir seluruh RAM sebagai Java heap.
JVM dan sistem operasi membutuhkan memori di luar heap.
Keempat, menambahkan Tomcat tanpa memperhatikan session.
Pengguna dapat mengalami logout jika session hanya tersimpan pada satu instance.
Kelima, menggunakan satu Apache untuk arsitektur yang disebut high availability.
Satu reverse proxy tetap merupakan single point of failure.
Keenam, tidak melakukan load testing.
Tanpa pengujian, kapasitas sistem hanya berdasarkan asumsi.
Ketujuh, mengabaikan performa query database.
Satu query yang lambat dan dipanggil ribuan kali dapat menjadi bottleneck utama seluruh aplikasi.
26. Kesimpulan
Membangun aplikasi web untuk banyak pengguna bukan sekadar memasang server dengan CPU dan RAM besar.
Kita perlu memahami hubungan antara request, thread, koneksi database, penggunaan memori, caching, dan kemampuan aplikasi untuk bertambah kapasitas.
Apache HTTP Server dapat digunakan sebagai reverse proxy dan load balancer yang mendistribusikan trafik ke beberapa Tomcat.
Tomcat menjalankan aplikasi Java, sementara database menyimpan data dan melayani query.
Dengan horizontal scaling, connection pooling, session management, monitoring, dan load testing, aplikasi dapat dikembangkan secara bertahap sesuai pertumbuhan kebutuhan.
Namun, hal terpenting bukanlah berapa banyak Tomcat yang kita jalankan atau seberapa besar maxThreads yang kita konfigurasi.
Arsitektur yang baik adalah arsitektur yang mampu memberikan performa terukur, tetap stabil saat beban meningkat, mudah dipelihara, dan dapat dikembangkan tanpa menambah kompleksitas yang tidak diperlukan.
Mulailah dari arsitektur sederhana, ukur performanya, identifikasi bottleneck, kemudian lakukan scaling berdasarkan data.
Itulah fondasi performance engineering yang sebenarnya.
Referensi
- Apache HTTP Server — https://httpd.apache.org/
- Apache Reverse Proxy — https://httpd.apache.org/docs/2.4/howto/reverse_proxy.html
- Apache mod_proxy — https://httpd.apache.org/docs/2.4/mod/mod_proxy.html
- Apache MPM Event — https://httpd.apache.org/docs/2.4/mod/event.html
- Apache Tomcat — https://tomcat.apache.org/
- Tomcat HTTP Connector — https://tomcat.apache.org/tomcat-10.1-doc/config/http.html
- PostgreSQL Documentation — https://www.postgresql.org/docs/
- Spring Boot — https://spring.io/projects/spring-boot
- HikariCP — https://github.com/brettwooldridge/HikariCP
- Grafana — https://grafana.com/
- k6 — https://grafana.com/docs/k6/
Artikel Nirantara — Membangun Software, Mengeksplorasi AI.
Published by Nirantara
Nirantara is an Indonesian Enterprise AI company specializing in Enterprise AI, RAG, Intelligent Search, and AI Automation. Article written by jsturana.