Fitur Andalan OpenResty: Dinamis

API7.ai

January 12, 2023

OpenResty (NGINX + Lua)

Sejauh ini, kita hampir selesai dengan konten terkait performa OpenResty. Menguasai dan menerapkan teknik optimasi ini secara fleksibel dapat sangat meningkatkan performa kode kita. Hari ini, di bagian terakhir dari optimasi performa, mari kita pelajari tentang kemampuan yang sering diremehkan dalam OpenResty: "dinamis".

Mari kita mulai dengan melihat apa itu dinamis dan bagaimana kaitannya dengan performa. Dinamis dalam konteks ini berarti program dapat memodifikasi parameter, konfigurasi, dan bahkan kode mereka saat runtime, tanpa perlu memuat ulang. Secara spesifik, dalam NGINX dan OpenResty, Anda dapat mengubah upstream, sertifikat SSL, dan batas limit rate tanpa perlu memulai ulang layanan, mencapai dinamis. Adapun hubungan antara dinamis dan performa, jelas bahwa jika jenis operasi ini tidak dapat dilakukan secara dinamis, maka reload yang sering pada layanan NGINX secara alami akan mengakibatkan kehilangan performa.

Namun, kita tahu bahwa versi open source NGINX tidak mendukung fitur dinamis, sehingga Anda harus mengubah upstream dan sertifikat SSL dengan memodifikasi file konfigurasi dan memulai ulang layanan agar efektif. NGINX Plus (versi komersial NGINX) menyediakan beberapa kemampuan dinamis, dan Anda dapat menggunakan REST API untuk memperbarui, tetapi ini adalah peningkatan yang kurang radikal.

Di OpenResty, belenggu ini tidak ada, dan dinamis adalah fitur andalan OpenResty. Anda mungkin bertanya-tanya mengapa OpenResty, yang berbasis NGINX, dapat mendukung dinamis. Alasannya sederhana: logika NGINX dilakukan melalui modul C, sementara OpenResty dilakukan melalui Lua, sebuah bahasa skrip. Salah satu keuntungan bahasa skrip adalah mereka dapat diubah secara dinamis saat runtime.

Memuat kode secara dinamis

Berikut adalah cara memuat kode Lua secara dinamis di OpenResty.

resty -e 'local s = [[ngx.say("hello world")]] local func, err = loadstring(s) func()'

Kita dapat melihat bahwa hanya dalam beberapa baris kode, kita dapat mengubah string menjadi fungsi Lua dan menjalankannya. Mari kita lihat lebih dekat baris-baris kode ini:

  • Pertama, kita mendeklarasikan sebuah string yang isinya adalah potongan kode Lua yang mencetak hello world;
  • Kemudian, menggunakan fungsi loadstring di Lua, mengubah objek string menjadi objek fungsi func.
  • Terakhir, menambahkan tanda kurung pada nama fungsi untuk mengeksekusi func dan mencetak hello world.

Tentu saja, kita juga dapat memperluas fungsi yang lebih menarik dan praktis berdasarkan kode ini. Selanjutnya, saya akan mengajak Anda mencobanya.

Fungsi 1: FaaS

Pertama adalah FaaS (Function-as-a-Service), yang baru-baru ini menjadi arah teknologi yang sangat populer. Mari kita lihat bagaimana mengimplementasikannya di OpenResty. Dalam kode yang baru saja disebutkan, string adalah kode Lua. Kita juga dapat mengubahnya menjadi fungsi Lua:

local s = [[ return function() ngx.say("hello world") end ]]

Seperti yang telah kita katakan, fungsi adalah warga negara kelas satu di Lua, dan kode ini mengembalikan fungsi anonim. Saat mengeksekusi fungsi anonim ini, kita menggunakan pcall untuk memberikan lapisan perlindungan. pcall akan menjalankan fungsi dalam mode terlindungi dan menangkap pengecualian. Jika normal, akan mengembalikan true dan hasil eksekusi. Jika gagal, akan mengembalikan false dan informasi kesalahan, yang merupakan kode berikut:

local func1, err = loadstring(s) local ret, func = pcall(func1)

Secara alami, jika Anda menggabungkan dua bagian di atas, Anda akan mendapatkan contoh yang lengkap dan dapat dioperasikan:

resty -e 'local s = [[ return function() ngx.say("hello world") end ]] local func1 = loadstring(s) local ret, func = pcall(func1) func()'

Untuk melangkah lebih jauh, kita dapat mengubah string s yang berisi fungsi menjadi bentuk yang dapat ditentukan pengguna dan menambahkan kondisi untuk eksekusinya. Ini adalah prototipe FaaS. Di sini, saya menyediakan implementasi lengkap. Jika tertarik dengan FaaS dan ingin melanjutkan penelitian Anda, ikuti tautan untuk mempelajari lebih lanjut.

Fungsi 2: Edge Computing

Dinamis OpenResty dapat digunakan untuk FaaS, membuat dinamika bahasa skrip diperhalus hingga ke tingkat fungsi, dan memainkan peran dinamis dalam edge computing.

Karena keuntungan ini, kita dapat memperluas jangkauan OpenResty dari bidang gateway API, WAF (Web Application Firewall), server web, dan ujung server lainnya ke node edge yang paling dekat dengan pengguna, seperti perangkat IoT, node edge CDN, router, dan sebagainya.

Ini bukan hanya fantasi. OpenResty telah digunakan secara luas di bidang-bidang di atas. Mengambil node edge CDN sebagai contoh, Cloudflare, pengguna terbesar OpenResty, telah lama menyadari kontrol dinamis node edge CDN dengan bantuan karakteristik dinamis OpenResty.

Pendekatan Cloudflare mirip dengan prinsip memuat kode secara dinamis di atas, yang dapat dibagi menjadi langkah-langkah berikut:

  • Pertama, mendapatkan file kode yang berubah dari kluster database key-value. Metodenya bisa berupa polling timer latar belakang atau mode "publish-subscribe" untuk memantau;
  • Kemudian, mengganti file lama di disk lokal dengan file kode yang diperbarui dan memperbarui cache yang dimuat dalam memori menggunakan metode loadstring dan pcall;

Dengan cara ini, permintaan klien berikutnya yang akan diproses akan melalui logika kode yang diperbarui. Tentu saja, aplikasi praktis harus mempertimbangkan lebih banyak detail daripada langkah-langkah di atas, seperti kontrol versi dan rollback, penanganan pengecualian, gangguan jaringan, restart node edge, dll., tetapi proses keseluruhannya tidak berubah.

Jika kita memindahkan pendekatan Cloudflare dari node edge CDN ke skenario edge lainnya, kita dapat secara dinamis menugaskan banyak daya komputasi ke perangkat node edge. Ini tidak hanya dapat memanfaatkan sepenuhnya daya komputasi node edge tetapi juga memungkinkan pengguna mendapatkan respons yang lebih cepat terhadap permintaan karena node edge akan memproses data asli dan kemudian meringkasnya ke server jarak jauh, yang sangat mengurangi jumlah transmisi data.

Namun, untuk melakukan pekerjaan yang baik dalam FaaS dan edge computing, dinamis OpenResty hanyalah fondasi yang baik. Anda juga perlu mempertimbangkan peningkatan ekosistem sekitar dan partisipasi produsen, yang bukan hanya kategori teknis.

Upstream Dinamis

Sekarang, mari kita tarik pikiran kita kembali ke OpenResty untuk melihat bagaimana mencapai upstream dinamis. lua-resty-core menyediakan pustaka ngx.balancer untuk mengatur upstream. Ini perlu ditempatkan di tahap balancer OpenResty untuk dijalankan:

balancer_by_lua_block { local balancer = require "ngx.balancer" local host = "127.0.0.2" local port = 8080 local ok, err = balancer.set_current_peer(host, port) if not ok then ngx.log(ngx.ERR, "failed to set the current peer: ", err) return ngx.exit(500) end }

Fungsi set_current_peer mengatur alamat IP dan port upstream. Namun, kami ingin menunjukkan bahwa nama domain tidak didukung di sini. Kita perlu menggunakan pustaka lua-resty-dns untuk membuat lapisan analisis untuk nama domain dan IP.

Namun, ngx.balancer relatif rendah. Meskipun dapat digunakan untuk mengatur upstream, realisasi upstream dinamis jauh dari sederhana. Oleh karena itu, dua fungsi diperlukan di depan ngx.balancer:

  • Pertama, memutuskan apakah algoritma pemilihan upstream adalah consistent hash atau roundrobin;
  • Kedua, mekanisme pemeriksaan kesehatan upstream, yang perlu menghilangkan upstream yang tidak sehat dan bergabung kembali ketika upstream yang tidak sehat menjadi sehat.

Pustaka resmi OpenResty lua-resty-balancer berisi dua jenis algoritma: resty.chash dan resty.roundrobin untuk menyelesaikan fungsi pertama, dan memiliki lua-resty-upstream-healthcheck untuk mencoba menyelesaikan fungsi kedua.

Namun, masih ada dua masalah.

Poin pertama adalah kurangnya implementasi lengkap dari mil terakhir. Menggabungkan ngx.balancer, lua-resty-balancer, dan lua-resty-upstream-healthcheck untuk menggabungkan fungsi upstream dinamis, tetapi masih membutuhkan beberapa pekerjaan, yang menghentikan sebagian besar pengembang.

Kedua, implementasi lua-resty-upstream-healthcheck tidak lengkap. Hanya ada pemeriksaan kesehatan pasif tetapi tidak ada pemeriksaan kesehatan aktif.

Permintaan klien memicu pemeriksaan kesehatan pasif di sini dan kemudian menganalisis nilai kembali upstream sebagai kondisi untuk menentukan apakah kesehatan baik. Jika tidak ada permintaan klien, tidak diketahui apakah upstream sehat. Pemeriksaan kesehatan aktif dapat memperbaiki cacat ini. Ini menggunakan ngx.timer untuk secara berkala memantau antarmuka upstream yang ditentukan untuk mendeteksi status kesehatan.

Oleh karena itu, dalam praktik sebenarnya, kami biasanya merekomendasikan menggunakan lua-resty-healthcheck untuk menyelesaikan pemeriksaan kesehatan upstream. Keuntungannya adalah mencakup pemeriksaan kesehatan aktif dan pasif, dan telah diverifikasi dalam beberapa proyek dengan keandalan yang lebih tinggi.

Selanjutnya, gateway API mikroservis yang muncul Apache APISIX telah membuat implementasi lengkap dari upstream dinamis berdasarkan lua-resty-upstream-healthcheck. Kita dapat merujuk implementasinya. Hanya ada 400 baris kode secara total. Anda dapat dengan mudah mengupasnya dan memasukkannya ke dalam proyek Anda untuk digunakan.

Ringkasan

Mengenai dinamis OpenResty, di bidang dan skenario apa Anda dapat memanfaatkannya? Anda juga dapat memperluas konten setiap bagian yang diperkenalkan dalam bab ini untuk analisis yang lebih rinci dan mendalam.

Anda dipersilakan untuk membagikan artikel ini dan belajar serta membuat kemajuan dengan lebih banyak orang.