Open File Cache #
Setiap kali Nginx menyajikan berkas statis (seperti berkas HTML, gambar, dokumen CSS, skrip JavaScript, atau font) langsung dari penyimpanan lokal server ke klien, sistem operasi di latar belakang harus melakukan serangkaian pemanggilan sistem (system calls atau syscalls). Pemanggilan sistem ini mencakup proses pencarian lokasi fisik berkas di sistem penyimpanan (inode lookup), membaca metadata berkas (ukuran dan waktu modifikasi terakhir), membuka deskriptor berkas (file descriptor), mentransmisikan data, dan akhirnya menutup kembali deskriptor berkas tersebut.
Pada server produksi yang melayani ribuan permintaan file statik per detik, eksekusi berulang dari syscalls seperti open(), stat(), dan close() ini dapat menjadi hambatan performa (I/O bottlenecks) yang serius bagi CPU server kita. Nginx mengatasi masalah ini dengan menyediakan fitur Open File Cache. Fitur ini menyimpan deskriptor berkas terbuka beserta metadatanya secara langsung di memori RAM Nginx. Di artikel ini, kita akan membahas cara kerja Open File Cache, membedah parameter konfigurasinya, menyusun konfigurasi sinergis “trio performa statik”, serta menganalisis skenario di mana fitur ini memberikan dampak paling signifikan.
Masalah Overhead Pemanggilan Sistem (Syscall Overhead) #
Untuk memahami nilai penting dari Open File Cache, mari kita telaah alur kerja sistem operasi Linux ketika Nginx menyajikan satu file statis tanpa caching descriptor:
- Syscall
open(): Nginx meminta kernel Linux untuk membuka berkas (misalnya/var/www/static/js/app.js). Kernel harus menelusuri struktur direktori pada disk untuk menemukan nomor inode berkas tersebut. - Syscall
fstat(): Nginx meminta kernel untuk membaca metadata berkas guna mengetahui ukuran berkas (untuk headerContent-Length) dan waktu modifikasi terakhir (untuk headerLast-Modified). - Transmisi Data: Nginx membaca berkas ke memori dan mengirimkannya ke soket jaringan.
- Syscall
close(): Nginx menutup kembali deskriptor berkas untuk melepaskan resource sistem operasi.
Setiap pemanggilan sistem (syscall) di atas membutuhkan perpindahan konteks CPU (context switch) dari user space (area aplikasi Nginx) ke kernel space (area inti sistem operasi) dan kembali lagi. Jika server kita harus melayani 10.000 request file statik per detik, CPU server kita akan membuang sebagian besar daya komputasinya hanya untuk bolak-balik melakukan perpindahan konteks dan pencarian inode disk ini. Masalah ini akan terasa jauh lebih parah jika sistem penyimpanan kita memiliki latensi pencarian yang tinggi (seperti pada Network File System - NFS, atau hard disk mekanis biasa).
Cara Kerja open_file_cache di Nginx
#
Dengan mengaktifkan direktif open_file_cache, Nginx akan menyimpan data deskriptor berkas yang terbuka beserta informasi metadatanya di dalam memori RAM Nginx.
Berikut adalah diagram alur perbandingan pencarian file statik tanpa vs dengan open file cache:
flowchart TD
Request["Klien Meminta File Statik"] --> CheckCache{"Apakah File Descriptor<br/>Ada di RAM Cache?"}
CheckCache -->|Ya: Cache HIT| SendFile["Langsung Kirim File via sendfile"]
CheckCache -->|Tidak: Cache MISS| SyscallOpen["Panggil Syscall open & stat ke OS"]
SyscallOpen --> DiskLookup["OS Cari Inode di Disk Storage"]
DiskLookup --> OpenFD["Buka File Descriptor (FD) & Baca Metadata"]
OpenFD --> SaveRAM["Simpan FD & Metadata ke RAM Cache"]
SaveRAM --> SendFile
classDef default fill:#f9f9f9,stroke:#d1d5db,stroke-width:1px,color:#111827;
classDef hitStyle fill:#d1fae5,stroke:#10b981,stroke-width:2px,color:#065f46;
classDef missStyle fill:#fee2e2,stroke:#ef4444,stroke-width:2px,color:#991b1b;
classDef processStyle fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e3a8a;
class SendFile hitStyle;
class CheckCache processStyle;
class SyscallOpen,DiskLookup,OpenFD missStyle;
Ketika cache aktif dan request berikutnya untuk file yang sama masuk:
- Nginx mendeteksi bahwa deskriptor berkas tersebut sudah terdaftar di RAM cache-nya.
- Nginx mengabaikan pemanggilan sistem
open()danfstat()ke sistem operasi. - Nginx langsung mengirimkan data berkas menggunakan deskriptor berkas yang sudah terbuka tersebut.
- Deskriptor berkas dibiarkan tetap terbuka di memori untuk request-request berikutnya.
Hal ini secara dramatis memotong beban kerja CPU, meniadakan latensi lookup sistem berkas disk, dan mempercepat waktu pengiriman respons ke pengguna.
Konfigurasi Direktif open_file_cache
#
Direktif open_file_cache dapat dideklarasikan di dalam konteks http global, server block, atau di dalam level location tertentu.
Sintaksis Dasar Konfigurasi #
http {
# max: jumlah entri maksimum yang disimpan di cache
# inactive: hapus berkas dari cache jika tidak diakses selama waktu ini
open_file_cache max=10000 inactive=30s;
}
max=10000: Nginx akan menampung maksimal 10.000 entri deskriptor berkas aktif di dalam memori RAM-nya. Jika jumlah file unik yang diakses melebihi 10.000, Nginx akan otomatis membuang entri yang paling jarang diakses (Least Recently Used - LRU) untuk memberikan ruang bagi file baru. Ukuran memori yang dikonsumsi sangat kecil, hanya sekitar 500 bita per entri, sehingga 10.000 entri hanya memakan memori sekitar 5 Megabyte RAM.inactive=30s: Menentukan batas waktu retensi ketidakaktifan. Jika sebuah berkas di cache tidak diakses oleh klien mana pun selama 30 detik, entri tersebut akan langsung dihapus dari memori RAM untuk memastikan RAM tidak dipenuhi oleh file sekali-pakai (one-hit wonders).
Konfigurasi Fine-Tuning Open File Cache #
Untuk mengendalikan bagaimana Nginx memvalidasi dan memelihara keakuratan data di dalam cache, kita menggunakan tiga direktif tambahan:
http {
open_file_cache max=10000 inactive=30s;
# 1. Frekuensi Nginx melakukan validasi kebenaran data cache ke disk
open_file_cache_valid 60s;
# 2. Jumlah akses minimum sebelum file dimasukkan ke cache
open_file_cache_min_uses 2;
# 3. Aktifkan caching untuk pesan kesalahan (errors)
open_file_cache_errors on;
}
Memahami Peran Direktif Penyelaras #
open_file_cache_valid 60s;: Ketika deskriptif berkas disimpan di memori, ada risiko file tersebut diubah atau diperbarui oleh pengembang kita di disk. Nginx tidak akan mendeteksi perubahan tersebut secara instan karena ia membaca data descriptor dari memori. Direktif ini menginstruksikan Nginx untuk melakukan pengecekan ke disk setiap 60 detik sekali guna memverifikasi apakah berkas telah dimodifikasi atau dihapus. Menyetel nilai ini lebih tinggi (misal 5 menit) meningkatkan performa, namun memperlambat deteksi pembaruan file statik di browser pengguna.open_file_cache_min_uses 2;: Untuk mencegah berkas acak yang jarang diakses (misalnya dokumen unduhan PDF lama) memenuhi kuota cachemax, Nginx hanya akan memasukkan deskriptor berkas ke dalam cache jika berkas tersebut telah diakses minimal 2 kali dalam rentang waktu yang ditentukan oleh parameterinactive(30 detik).open_file_cache_errors on;: Menginstruksikan Nginx untuk turut meng-cache pesan kesalahan seperti404 Not Found(file tidak ada) atau403 Forbidden(izin ditolak). Jika ada bot penyerang yang mencoba memindai ribuan URL acak palsu ke server kita, Nginx tidak perlu melakukan pemindaian sistem berkas disk berulang kali untuk setiap request spam tersebut—ia cukup menjawabnya secara instan dari RAM cache error miliknya.
Trio Performa Statik: open_file_cache + sendfile + tcp_nopush
#
Optimasi performa statik Nginx akan mencapai puncaknya jika kita menggabungkan Open File Cache dengan dua direktif optimalisasi transfer kernel Linux: sendfile dan tcp_nopush. Ketiganya sering disebut sebagai “Trio Performa Statik” Nginx.
Berikut adalah konfigurasi lengkap yang dioptimalkan untuk server berkas statik tingkat produksi:
http {
# 1. Konfigurasi Open File Cache
open_file_cache max=20000 inactive=30s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# 2. Aktifkan Sendfile (Zero-Copy Transfer)
# Menghindari penyalinan data file ke user space memori Nginx
sendfile on;
# 3. Aktifkan TCP Nopush (Hanya aktif jika sendfile menyala)
# Memaksa Nginx mengirimkan header respons dan isi file dalam satu paket TCP utuh
tcp_nopush on;
# 4. Aktifkan TCP Nodelay (Bypass algoritma Nagle)
# Mengirim data instan tanpa delay untuk koneksi keepalive
tcp_nodelay on;
server {
listen 443 ssl;
server_name assets.unisbadri.com;
root /var/www/assets;
location / {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
}
}
`### Bagaimana Trio Ini Bekerja Bersama?
1. Klien meminta berkas gambar `logo.png`.
2. Nginx memeriksa `open_file_cache` di memori RAM dan langsung mengambil deskriptor berkas `logo.png` tanpa membuang CPU untuk melakukan syscall `open()`.
3. Nginx memanggil syscall **`sendfile()`** dengan menyertakan deskriptor berkas tersebut. Kernel Linux akan langsung menyalin data berkas dari cache halaman kernel (*page cache*) ke soket jaringan secara instan (*zero-copy transfer*), tanpa menyalin data tersebut ke ruang memori aplikasi Nginx terlebih dahulu.
4. Direktif **`tcp_nopush on`** memastikan header respons HTTP dan data gambar digabungkan dan dikirimkan bersamaan dalam satu paket jaringan TCP maksimum (*Maximum Segment Size - MSS*), meminimalkan jumlah paket data yang dikirim dan mengurangi kongesti jaringan internet.
---
## Mekanisme Eviksi Cache, Manajemen Memori, dan Limit OS
Untuk menjaga agar penggunaan memori RAM tetap terkendali dan efisien, Nginx mengimplementasikan algoritma **Least Recently Used (LRU)** untuk mengelola siklus hidup entri di dalam `open_file_cache`.
Ketika batas maksimum entri yang ditentukan oleh parameter `max` telah tercapai, dan ada berkas statis baru yang perlu dimasukkan ke dalam cache, Nginx tidak akan menolak entri baru tersebut. Sebaliknya, Nginx akan pemindaian cache dan membuang entri yang paling jarang atau paling lama tidak diakses oleh klien.
#### Struktur RAM dan Konsumsi Memori
Setiap entri yang disimpan oleh `open_file_cache` di memori RAM terdiri dari komponen-komponen berikut:
- **File Descriptor (FD)**: Referensi integer ke berkas terbuka di tingkat kernel.
- **Informasi Metadata**: Ukuran berkas, waktu modifikasi terakhir (*mtime*), dan inode berkas di disk.
- **Status Akses**: Informasi frekuensi akses berkas untuk kalkulasi LRU.
- **Informasi Kesalahan**: Jika `open_file_cache_errors` aktif, detail kegagalan akses (seperti kode `ENOENT` untuk berkas tidak ditemukan atau `EACCES` untuk masalah hak akses) juga akan dicatat.
Secara rata-rata, satu entri memakan memori sekitar 500 bita hingga 1 kilobita RAM. Dengan konfigurasi `max=20000`, Nginx hanya akan mengonsumsi memori sekitar 10 hingga 20 Megabyte RAM. Ini adalah investasi resource yang sangat murah jika dibandingkan dengan peningkatan performa throughput I/O yang kita dapatkan.
#### Hubungan dengan Batasan Sistem Operasi (OS Limits)
Satu hal krusial yang sering diabaikan oleh administrator sistem adalah batasan maksimum file descriptor yang diizinkan oleh sistem operasi Linux. Setiap entri berkas terbuka di `open_file_cache` menggunakan satu file descriptor aktual dari alokasi sistem.
Jika kita menyetel `open_file_cache max=50000;`, namun sistem Linux kita membatasi jumlah file descriptor per proses worker sebesar 1.024 (nilai default Linux untuk proses non-root), Nginx akan mengalami galat *too many open files* dan mulai menolak koneksi baru dari klien.
Oleh karena itu, kita harus memastikan direktif `worker_rlimit_nofile` di konfigurasi global Nginx kita disetel lebih besar daripada total kebutuhan koneksi dan open file cache kita secara bersamaan:
```nginx
# Di bagian terluar konfigurasi nginx.conf (global context)
worker_rlimit_nofile 65535; # Setel batas fd setinggi mungkin
Panduan Verifikasi Lapangan Menggunakan strace #
Bagaimana kita bisa benar-benar yakin bahwa Nginx telah berhenti melakukan pemanggilan sistem (syscall) ke sistem operasi setelah open_file_cache diaktifkan? Kita bisa memverifikasinya secara langsung menggunakan utilitas analisis proses Linux bernama strace.
Langkah-langkah untuk melakukan verifikasi di server pengujian kita adalah sebagai berikut:
1. Temukan PID dari Worker Process Nginx #
Kita perlu memantau proses worker, bukan proses master, karena worker-lah yang menangani pengiriman berkas ke klien. Jalankan perintah berikut:
ps aux | grep nginx
Output akan menunjukkan proses master (berjalan sebagai root) dan satu atau beberapa worker (berjalan sebagai nginx atau www-data). Catat PID dari salah satu worker process tersebut.
2. Jalankan strace Sebelum Mengaktifkan Cache #
Gunakan strace untuk merekam syscall pembukaan berkas pada worker process tersebut saat kita mengirimkan beberapa permintaan HTTP menggunakan curl atau alat pengujian performa seperti wrk:
# Ganti <worker_pid> dengan PID worker aktual kita
sudo strace -p <worker_pid> -e trace=openat,fstat,close
Kirim beberapa request untuk mengambil file statik yang sama:
curl -I http://localhost/assets/styles.css
curl -I http://localhost/assets/styles.css
Di layar terminal strace, kita akan melihat log syscall bergulir untuk setiap permintaan yang masuk:
openat(AT_FDCWD, "/var/www/assets/styles.css", O_RDONLY|O_NONBLOCK) = 12
fstat(12, {st_mode=S_IFREG|0644, st_size=12045, ...}) = 0
close(12) = 0
Log di atas membuktikan bahwa tanpa cache, sistem operasi terus dipaksa membuka, membaca status, dan menutup file descriptor yang sama berulang kali.
3. Jalankan strace Setelah Mengaktifkan Cache #
Sekarang, aktifkan open_file_cache di konfigurasi Nginx kita, reload konfigurasi dengan nginx -s reload, lalu temukan PID worker baru (karena reload memicu proses worker baru). Jalankan kembali perintah strace:
sudo strace -p <new_worker_pid> -e trace=openat,fstat,close
Kirim kembali permintaan yang sama berturut-turut. Pada permintaan pertama (cache miss), kita masih akan melihat syscall openat dan fstat. Namun, pada permintaan kedua, ketiga, dan seterusnya (cache hit), terminal strace kita akan hening dan tidak menampilkan syscall openat atau fstat sama sekali.
Hal ini membuktikan secara empiris bahwa Nginx menyajikan berkas sepenuhnya dari cache deskriptor memori RAM-nya tanpa menyentuh syscall file system Linux.
Skenario Khusus: Network File System (NFS) dan Storage Terdistribusi #
Jika server Nginx kita membaca data dari sistem penyimpanan lokal berbasis Solid State Drive (SSD) modern dengan koneksi NVMe, latensi untuk pemanggilan open() dan stat() mungkin hanya berkisar di bawah satu milidetik. Namun, situasinya berubah drastis ketika kita menggunakan Network File System (NFS) atau sistem berkas terdistribusi lainnya (seperti GlusterFS atau CephFS).
Dalam arsitektur web scale modern, adalah hal yang lumrah untuk meletakkan aset statik di server penyimpanan terpusat dan membagikannya ke beberapa server Nginx penyeimbang beban (load balancer nodes) via mounting NFS.
Overhead Jaringan pada Syscall File System #
Ketika Nginx tidak menggunakan open_file_cache dalam lingkungan NFS:
- Setiap kali klien meminta file, syscall
open()memicu kernel Linux lokal untuk mengirim paket permintaan jaringan ke server NFS remote. - Server NFS remote mencari berkas di disk miliknya, membuka file descriptor, dan mengirim respons kembali lewat jaringan.
- Proses yang sama terjadi untuk syscall
fstat().
Ini berarti satu permintaan aset statik sederhana di Nginx membutuhkan beberapa putaran komunikasi jaringan (network round-trips) hanya untuk membuka berkas, bahkan sebelum data berkas tersebut mulai ditransfer. Latensi jaringan antar server ini dapat memperlambat waktu respons HTTP (Time to First Byte - TTFB) hingga puluhan atau ratusan milidetik.
Solusi Penyelamat dari open_file_cache #
Dengan mengonfigurasi open_file_cache pada node Nginx kita:
- Deskriptor berkas jarak jauh disimpan di RAM lokal server Nginx kita.
- Nginx hanya perlu melakukan verifikasi perubahan berkas sesuai interval
open_file_cache_valid(misalnya setiap 60 detik) untuk meminimalkan beban jaringan. - Semua akses berkas harian dilayani seketika tanpa menimbulkan lalu lintas jaringan tambahan antara Nginx node dan NFS server.
Dalam pengujian dunia nyata, mengaktifkan open_file_cache pada setup Nginx berbasis NFS mampu meningkatkan throughput pengiriman file statik hingga 300% hingga 500% sekaligus mengurangi pemakaian bandwidth jaringan internal secara signifikan.
Masalah Berkas Kedaluwarsa (Stale Cache) dan Strategi Rilis #
Walaupun memberikan peningkatan performa yang sangat besar, penggunaan open_file_cache menyimpan satu jebakan operasional utama: Berkas Kedaluwarsa (Stale Cache).
Jika kita memperbarui konten berkas statik di server kita (misalnya menimpa berkas gambar banner.png dengan gambar promosi baru), klien yang mengakses berkas tersebut mungkin masih menerima gambar lama, atau bahkan mengalami error jika berkas baru tersebut memiliki ukuran yang berbeda namun Nginx masih menggunakan informasi ukuran dari metadata lama yang tersimpan di memori cache.
Untuk mencegah masalah berkas kedaluwarsa ini merusak pengalaman pengguna kita, kita bisa menerapkan beberapa strategi berikut:
1. Menggunakan Nama Berkas yang Unik (Asset Hashing) #
Ini adalah praktik terbaik standar industri di era web modern. Alur build frontend kita (menggunakan Vite, Webpack, atau Next.js) harus dikonfigurasi untuk menambahkan hash unik dari konten berkas ke dalam nama berkas akhir (misalnya main.a8f9c2d1.js bukan main.js).
Karena setiap kali ada perubahan kode nama berkasnya pasti berubah, Nginx akan mendeteksinya sebagai berkas baru (Cache MISS) dan membuka file descriptor baru. Berkas lama yang sudah tidak digunakan lagi akan otomatis dibuang dari memori open_file_cache setelah melewati masa ketidakaktifan (inactive).
2. Reload Nginx Secara Manual Saat Deployment #
Jika kita tidak menggunakan teknik asset hashing dan terpaksa menimpa berkas statik yang sama secara langsung di disk, kita harus menginstruksikan Nginx untuk membersihkan (flush) RAM cache-nya secara instan.
Kita bisa melakukan ini tanpa memutus koneksi aktif pengguna dengan mengirimkan sinyal reload ke Nginx:
sudo nginx -s reload
Sinyal reload akan membuat master process Nginx membuat proses worker baru yang memorinya bersih dari entri cache lama, lalu menghentikan proses worker lama secara anggun (gracefully) setelah mereka selesai melayani koneksi aktif yang sedang berjalan.
3. Optimasi open_file_cache_valid #
Jika kita tidak bisa melakukan reload Nginx secara manual pada setiap deployment, kita harus menurunkan nilai open_file_cache_valid menjadi lebih pendek (misalnya 5s atau 10s). Hal ini memaksa Nginx untuk memeriksa perubahan file ke disk lebih sering. Meskipun sedikit menaikkan beban CPU, langkah ini memastikan pengguna tidak akan melihat berkas lama terlalu lama setelah deployment baru.
Analisis Use Cases: Kapan Fitur Ini Bermanfaat? #
Open File Cache sangat efektif, namun manfaatnya sangat bergantung pada arsitektur aplikasi kita:
Sangat Bermanfaat Pada: #
- Static Asset Server: Server CDN kustom atau server penyimpanan berkas (seperti MinIO atau server aset static Vite/React) yang melayani ribuan file CSS, JS, gambar, dan font langsung dari disk lokal.
- Situs dengan Trafik Tinggi (High Concurrency): Server yang melayani puluhan ribu pengunjung simultan secara bersamaan.
- Sistem Penyimpanan Lambat: Server yang berkasnya disimpan di dalam media penyimpanan berjaringan (Network Attached Storage / NFS) atau sistem penyimpanan cloud block (seperti AWS EBS) yang memiliki latensi lookup sistem berkas yang lambat.
Kurang Bermanfaat Pada: #
- Pure Reverse Proxy: Jika Nginx kita hanya bertindak sebagai gerbang masuk (API Gateway) yang 100% trafiknya langsung diteruskan ke upstream backend (seperti Node.js atau Docker container). Nginx tidak pernah membaca file lokal dari disk servernya sendiri untuk request tersebut, sehingga cache deskriptor tidak akan pernah terisi.
Ringkasan dan Praktik Terbaik #
- Gunakan max Secara Proporsional: Setel parameter
maxagar sedikit lebih tinggi dari jumlah total file statis aktif yang ada di repositori web server kita.- Aktifkan open_file_cache_errors: Selalu nyalakan caching error untuk memotong beban I/O disk akibat pemindaian request file yang tidak ada (404).
- Gabungkan dengan Sendfile: Selalu aktifkan
sendfile on;dantcp_nopush on;bersamaan dengan open file cache untuk mencapai kecepatan transfer data tertinggi.- Sesuaikan Validasi: Atur
open_file_cache_validlebih rendah (misal 10-20 detik) jika kita sering melakukan deployment aset baru ke server tanpa mengubah hash nama berkas.- Hindari pada Reverse Proxy Murni: Matikan atau abaikan konfigurasi ini jika server Nginx kita murni hanya bertindak sebagai jembatan reverse proxy ke backend.