Optimasi: Mengonfigurasi server web Nginx untuk meningkatkan kinerja RPS di API HTTP



Sebelum penskalaan dan penskalaan infrastruktur Anda, langkah pertama adalah memastikan bahwa sumber daya digunakan dengan benar dan konfigurasi aplikasi tidak menghambat kinerjanya. Tujuan utama tim teknik adalah untuk memastikan operasi yang berkelanjutan dan tidak terputus dari sistem yang dirancang dan diterapkan dengan sumber daya minimal.



Kami menghadapi masalah di atas di mana sistem yang kami terapkan digunakan setiap hari oleh jutaan pengguna yang terhubung secara tiba-tiba dari waktu ke waktu. Ini berarti bahwa menerapkan beberapa server atau menskalakannya tidak akan menjadi solusi terbaik dalam situasi ini.



Artikel ini tentang menyetel Nginx untuk meningkatkan kinerja, yaitu untuk meningkatkan RPS (Permintaan Per Detik) di API HTTP. Saya mencoba memberi tahu Anda tentang pengoptimalan yang kami terapkan dalam sistem yang diterapkan untuk memproses puluhan ribu permintaan per detik tanpa membuang banyak sumber daya.



Rencana tindakan: Anda perlu menjalankan API HTTP (ditulis dengan Python menggunakan flask), yang diproksikan dengan Nginx; bandwidth tinggi diperlukan. Konten API akan berubah dalam interval satu hari.



optimasi proses

kata benda



untuk mencapai hasil terbaik; penggunaan situasi atau sumber daya yang paling efisien.


Kami menggunakan supervisor untuk memulai WSGI Server dengan konfigurasi berikut:





Perintah supervisor terlihat seperti ini:



gunicorn api:app --workers=5 --worker-
class=meinheld.gmeinheld.MeinheldWorker --bind=unix:api.sock


Kami mencoba mengoptimalkan konfigurasi Nginx dan memeriksa mana yang terbaik bagi kami.



Untuk mengevaluasi kinerja API, kami menggunakan wrk dengan perintah berikut:



wrk -t20 -c200 -d20s http://api.endpoint/resource


Konfigurasi default



Kami pertama kali melakukan pengujian beban pada API tanpa perubahan apa pun dan mendapatkan statistik berikut:



Running 20s test @ http://api.endpoint/resource
  20 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   192.48ms  274.78ms   1.97s    87.18%
    Req/Sec    85.57     29.20   202.00     72.83%
  33329 requests in 20.03s, 29.59MB read
  Socket errors: connect 0, read 0, write 0, timeout 85
Requests/sec:   1663.71
Transfer/sec:      1.48MB


Memperbarui konfigurasi default



Mari perbarui konfigurasi Nginx default yaitu nginx.conf di /etc/nginx/nginx.conf



worker_processes auto;
#or should be equal to the CPU core, you can use `grep processor /proc/cpuinfo | wc -l` to find; auto does it implicitly.

worker_connections 1024;
# default is 768; find optimum value for your server by `ulimit -n`

access_log off;
# to boost I/O on HDD we can disable access logs
# this prevent nginx from logging every action in a log file named `access.log`.

keepalive_timeout 15;
# default is 65;
# server will close connection after this time (in seconds)

gzip_vary on;
gzip_proxied any;
gzip_comp_level 2;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_min_length 256;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
# reduces the data that needs to be sent over the network
nginx.conf (/etc/nginx/nginx.conf)



Setelah perubahan, kami menjalankan pemeriksaan konfigurasi:



sudo nginx -t


Jika pemeriksaan berhasil, Anda dapat memulai ulang Nginx untuk mencerminkan perubahan:



sudo service nginx restart


Dengan konfigurasi ini, kami melakukan pengujian beban pada API dan mendapatkan hasil sebagai berikut:



Running 20s test @ http://api.endpoint/resource
  20 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   145.80ms  237.97ms   1.95s    89.51%
    Req/Sec   107.99     41.34   202.00     66.09%
  42898 requests in 20.03s, 39.03MB read
  Socket errors: connect 0, read 0, write 0, timeout 46
  Non-2xx or 3xx responses: 2
Requests/sec:   2141.48
Transfer/sec:      1.95MB


Konfigurasi ini mengurangi waktu tunggu dan meningkatkan RPS (permintaan per detik), tetapi tidak banyak.



Menambahkan Cache Nginx



Karena, dalam kasus kami, konten titik akhir akan diperbarui dalam selang waktu satu hari, ini menciptakan lingkungan yang sesuai untuk menyimpan respons API.



Tetapi menambahkan cache membuatnya tidak valid ... ini adalah salah satu dari dua kesulitan di sini.

Dalam ilmu komputer, hanya ada dua komplikasi: membuat cache tidak valid dan memberi nama. - Phil Carlton



Kami memilih solusi mudah untuk menghapus direktori cache dengan cronjob setelah memperbarui konten di sistem hilir.



Selanjutnya, Nginx akan melakukan semua kerja keras, tetapi sekarang kita perlu memastikan bahwa Nginx sudah 100% siap!



Untuk menambahkan caching ke Nginx, Anda perlu menambahkan beberapa arahan ke file konfigurasi Nginx.



Sebelum itu, kita perlu membuat direktori untuk menyimpan data cache:



sudo mkdir -p /data/nginx/cache


Perubahan konfigurasi Nginx:



proxy_cache_path /data/nginx/cache keys_zone=my_zone:10m inactive=1d;
server {
    ...
    location /api-endpoint/ {
        proxy_cache my_zone;
        proxy_cache_key "$host$request_uri$http_authorization";
        proxy_cache_valid 404 302 1m;
        proxy_cache_valid 200 1d;
        add_header X-Cache-Status $upstream_cache_status;
    }
    ...
}


Caching Proxied Requests (Nginx Configuration)



Setelah konfigurasi ini berubah, kami memuat pengujian API dan mendapatkan hasil sebagai berikut:



Running 20s test @ http://api.endpoint/resource
  20 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     6.88ms    5.44ms  88.91ms   81.36%
    Req/Sec     1.59k   500.04     2.95k    62.50%
  634405 requests in 20.06s, 589.86MB read
Requests/sec:  31624.93
Transfer/sec:     29.40MB


Jadi, kami mendapatkan peningkatan kinerja hampir 19x lipat dengan menambahkan caching.

Catatan dari pakar Timeweb :



Penting untuk diingat bahwa kueri caching yang menulis ke database akan menghasilkan respons yang di-cache, tetapi tidak ada operasi tulis ke database.

Cache Nginx di RAM (Random Access Memory)



Mari kita selangkah lebih maju! Saat ini, data cache kami disimpan di disk. Bagaimana jika kita menyimpan data ini dalam RAM? Dalam kasus kami, data respons terbatas dan tidak besar.



Jadi, pertama-tama Anda perlu membuat direktori tempat cache RAM akan dipasang:



sudo mkdir -p /data/nginx/ramcache


Untuk memasang direktori yang dibuat di RAM menggunakan tmpfs , gunakan perintah:



sudo mount -t tmpfs -o size=256M tmpfs /data/nginx/ramcache


Ini memasang / data / nginx / ramcache di RAM, mengalokasikan 256MB.



Jika Anda merasa ingin menonaktifkan cache RAM, jalankan saja perintah:



sudo umount /data/nginx/ramcache


Untuk membuat ulang direktori cache secara otomatis di RAM setelah reboot, kita perlu memperbarui file / etc / fstab . Tambahkan baris berikut ke dalamnya:



tmpfs /data/nginx/ramcache tmpfs defaults,size=256M 0 0


Catatan: Kita juga harus mendaftarkan nilai proxy_cache_path dengan jalur ke ramcache ( / data / nginx / ramcache ).



Setelah memperbarui konfigurasi, kami kembali melakukan pengujian beban API dan menerima hasil berikut:



Running 20s test @ http://api.endpoint/resource
  20 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     5.57ms    5.69ms 277.76ms   92.94%
    Req/Sec     1.98k   403.94     4.55k    71.77%
  789306 requests in 20.04s, 733.89MB read
Requests/sec:  39387.13
Transfer/sec:     36.62MB


Menyimpan cache dalam RAM menghasilkan peningkatan yang signifikan hampir 23 kali lipat .



Log Akses Buffered



Kami menyimpan log akses ke aplikasi yang diproksikan, tetapi Anda dapat menyimpan log terlebih dahulu di buffer dan baru kemudian menulisnya ke disk:



  • jika baris berikutnya dari log tidak sesuai dengan buffer
  • jika data dalam buffer lebih lama dari yang ditentukan dalam parameter flush .


Prosedur ini akan mengurangi frekuensi perekaman yang dilakukan dengan setiap permintaan. Untuk melakukan ini, kita hanya perlu menambahkan parameter buffer dan flush dengan nilai yang sesuai di direktif access_log :



location / {
    ...
    access_log /var/log/nginx/fast_api.log combined buffer=256k flush=10s;
    error_log /var/log/nginx/fast_api.err.log;
}


Buffer log sebelum



ditulis ke disk Jadi, menurut konfigurasi di atas, awalnya log akses akan di-buffer dan disimpan ke disk hanya jika buffer mencapai 256 KB atau data yang di-buffer lebih lama dari 10 detik.



Catatan: Namanya adalah log_format yang digabungkan di sini .



Setelah pengujian beban berulang, kami mendapatkan hasil sebagai berikut:



Running 20s test @ http://api.endpoint/resource
  20 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     4.21ms    3.19ms  84.83ms   83.84%
    Req/Sec     2.53k   379.87     6.02k    77.05%
  1009771 requests in 20.03s, 849.31MB read
Requests/sec:  50413.44
Transfer/sec:     42.40MB


Konfigurasi ini secara signifikan meningkatkan jumlah permintaan per detik, sekitar 30 kali lipat dibandingkan tahap awal.



Keluaran



Pada artikel ini, kita membahas proses pengoptimalan konfigurasi Nginx untuk meningkatkan kinerja RPS. RPS telah ditingkatkan dari 1663 menjadi ~ 50413 ( meningkat sekitar 30 kali lipat ), yang memberikan throughput yang tinggi. Dengan menyesuaikan pengaturan default, Anda dapat meningkatkan kinerja sistem.



Mari akhiri artikel dengan kutipan:

Lakukan dulu. Lalu lakukan dengan benar. Kemudian optimalkan. - Kent Beck

Sumber






All Articles