OpenResty FAQ | Izin Proses Privileged, Fase Eksekusi, dan Lainnya

API7.ai

November 11, 2022

OpenResty (NGINX + Lua)

Artikel ini berisi enam pertanyaan yang sering diajukan:

1. Izin Proses yang Diistimewakan

Q: Apa itu proses yang diistimewakan? Bagaimana pengguna non-privileged bisa mendapatkan izin root? Bisakah Anda memperkenalkan beberapa skenario dari proses yang diistimewakan?

A: Izin proses yang diistimewakan sama dengan izin proses master. Jika Anda memulai OpenResty sebagai pengguna non-privileged, maka proses master akan mewarisi hak istimewa pengguna tersebut, yang berarti "proses yang diistimewakan" tidak memiliki hak sekarang.

Mudah dipahami bahwa tidak ada hak root ketika pengguna biasa memulai suatu proses.

Adapun skenario penggunaan proses yang diistimewakan, kami umumnya menggunakannya untuk tugas-tugas yang memerlukan hak istimewa tinggi, seperti membersihkan log dan memulai ulang OpenResty. Namun, berhati-hatilah untuk tidak menggunakan proses yang diistimewakan untuk menjalankan tugas proses worker karena risiko keamanan.

Seorang developer menjalankan semua tugas timer dalam proses yang diistimewakan. Mengapa dia melakukan ini? Karena hanya ada satu proses yang diistimewakan, dengan cara ini, timer tidak akan dimulai berulang kali.

Developer tersebut "cerdas" karena mencapai tujuannya tanpa menggunakan worker.id. Namun, jangan lupa, sangat berbahaya jika tugas timer bergantung pada input dari klien.

2. Fase dan Debugging

Q: Setelah menjalankan ngx.say('hello'), apakah OpenResty akan merespons klien langsung setelah mengeksekusi logika sisanya dalam fase saat ini? Artinya, tidak akan melanjutkan ke fase berikutnya.

A: Tidak. Kita dapat melihat fase eksekusinya:

image

Anda dapat menguji ngx.say dalam fase content terlebih dahulu, kemudian menggunakan ngx.log dalam fase log atau body filter untuk mencetak log.

Dalam artikel sebelumnya, saya tidak secara khusus menyebutkan masalah melakukan debugging kode di OpenResty, yang mungkin membuat developer merasa bingung.

Tidak ada fitur canggih untuk debugging kode di OpenResty, seperti breakpoint (ada beberapa plugin berbayar, tetapi saya belum menggunakannya), dan Anda hanya dapat menggunakan ngx.say dan ngx.log untuk melihat output. Ini adalah cara semua developer yang saya kenal melakukan debugging, termasuk penulis dan kontributor OpenResty. Oleh karena itu, Anda memerlukan kasus uji yang kuat dan log debug sebagai jaminan.

3. Praktik ngx.exit

Q: Dalam artikel sebelumnya, ada satu deskripsi: Kode Status HTTP OpenResty memiliki satu konstanta khusus ngx.OK. Setelah menjalankan ngx.exit(ngx.OK), permintaan keluar dari fase saat ini dan melanjutkan ke fase berikutnya alih-alih kembali ke klien langsung.

Saya ingat bahwa ngx.OK seharusnya tidak dianggap sebagai kode status HTTP, nilainya adalah 0. Pemahaman saya adalah:

  • Setelah menjalankan ngx.exit(ngx.OK), ngx.exit(ngx.ERROR) atau ngx.exit(ngx.DECLINED), permintaan keluar dari fase saat ini dan melanjutkan ke fase berikutnya.
  • Ketika ngx.exit(ngx.HTTP_*) mengambil berbagai kode status HTTP dari ngx.HTTP_* sebagai parameter, itu akan merespons langsung ke klien.

Saya tidak tahu apakah pemahaman saya benar.

A: Mengenai pertanyaan pertama Anda, ngx.ok bukanlah kode status HTTP tetapi konstanta di OpenResty dengan nilai 0.

Adapun pertanyaan kedua, dokumentasi resmi untuk ngx.exit dapat menjadi jawaban yang tepat:

  1. Ketika status >= 200 (yaitu, ngx.HTTP_OK dan di atasnya), itu akan menghentikan eksekusi permintaan saat ini dan mengembalikan kode status ke nginx.

  2. Ketika status == 0 (yaitu, ngx.OK), itu hanya akan keluar dari penangan fase saat ini (atau penangan konten jika direktif content_by_lua* digunakan) dan melanjutkan ke fase berikutnya (jika ada) untuk permintaan saat ini.

Namun, dokumentasi tidak menyebutkan bagaimana OpenResty menangani ngx.exit(ngx.ERROR) dan ngx.exit(ngx.DECLINED). Kita dapat melakukan tes sebagai berikut:

location /lua { rewrite_by_lua "ngx.exit(ngx.ERROR)"; echo hello; }

Mengunjungi location ini, Anda dapat melihat bahwa kode respons HTTP kosong, badan respons juga kosong, dan tidak melanjutkan ke fase eksekusi berikutnya.

Semakin dalam Anda mempelajari OpenResty, pada suatu titik Anda pasti akan menemukan bahwa baik dokumentasi maupun kasus uji tidak dapat menjawab pertanyaan Anda. Pada titik ini, Anda perlu membangun kasus uji Anda sendiri untuk memverifikasi ide Anda. Anda dapat melakukannya secara manual, atau Anda dapat menambahkan tes ke set kasus uji yang dibangun oleh test::nginx.

4. Variabel dan Kondisi Race

Q: Seperti yang disebutkan sebelumnya, ruang lingkup variabel ngx.var adalah antara modul nginx C dan lua-nginx-module.

  1. Saya tidak begitu memahami ini. Dari perspektif permintaan, apakah itu berarti satu permintaan dalam satu proses worker?

  2. Pemahaman saya adalah ketika kita memanipulasi variabel dalam suatu modul. Jika ada operasi blocking antara dua operasi, mungkin ada kondisi race. Jadi jika tidak ada operasi blocking antara dua operasi, dan kebetulan proses saat ini masuk ke antrian siap ketika waktu CPU habis, apakah mungkin ada kondisi race?

A: Mari kita lihat pertanyaan-pertanyaan ini.

Pertama, mengenai variabel ngx.var, pemahaman Anda benar. Siklus hidup ngx.var sama dengan permintaan, dan itu hilang ketika permintaan berakhir. Tetapi keuntungannya adalah data dapat diteruskan dalam modul C dan kode Lua, yang tidak mungkin dilakukan dengan beberapa cara lain.

Kedua, selama ada operasi yield antara dua operasi, mungkin ada kondisi race daripada operasi blocking. Tidak ada kondisi race ketika ada operasi blocking. Dengan kata lain, selama Anda tidak memberikan inisiatif ke loop event NGINX, tidak akan ada kondisi race.

5. shared dict Tidak Perlu Penguncian

Q: Jika beberapa worker menyimpan data secara bersamaan, apakah perlu menambahkan kunci?

Contoh:

resty --shdict 'dogs 10m' -e 'local dogs = ngx.shared.dogs local lock= ngx.xxxx.lock lock.lock() dogs:set("Jim", 8) lock.unlock() local v = dogs:get("Jim") ngx.say(v) '

A: Anda tidak perlu menambahkan kunci di sini karena baik operasi get maupun set, operasi shared dict bersifat atomik. OpenResty sudah mempertimbangkan jenis pengolahan seperti penguncian ini.

6. Operasi Waktu di OpenResty

Q: Menggunakan ngx.now() untuk mendapatkan waktu, apakah itu terjadi dalam fase pemulihan fungsi resume?

A: NGINX dirancang dengan kinerja sebagai prioritas utama dan menyimpan cache waktu. Kita dapat memverifikasi ini dengan kode sumber ngx.now:

static int ngx_http_lua_ngx_now(lua_State *L) { ngx_time_t *tp; tp = ngx_timeofday(); lua_pushnumber(L, (lua_Number) (tp->sec + tp->msec / 1000.0L)); return 1; }

Seperti yang Anda lihat, di balik fungsi ngx.now() yang mendapatkan waktu saat ini adalah fungsi ngx_timeofday dari NGINX. Fungsi ngx_timeofday adalah definisi makro:

#define ngx_timeofday() (ngx_time_t *) ngx_cached_time

Di sini nilai ngx_cached_time hanya akan diperbarui dalam fungsi ngx_time_update.

Jadi, pertanyaan berubah menjadi "kapan fungsi ngx_time_update dipanggil?" Jika Anda melacaknya dalam kode sumber NGINX, Anda akan melihat bahwa panggilan ke ngx_time_update terjadi dalam loop event, maka masalah ini terpecahkan.

Ringkasan

Anda seharusnya juga dapat menemukan melalui pertanyaan-pertanyaan ini, manfaat dari proyek open-source adalah Anda dapat mengikuti petunjuk dan mencari jawaban dalam kode sumber, yang akan memberi Anda perasaan seperti memecahkan kasus.

Akhirnya, saya berharap melalui komunikasi dan tanya jawab, saya dapat membantu Anda mengubah apa yang Anda pelajari menjadi apa yang Anda dapatkan. Anda juga dipersilakan untuk membagikan artikel ini, dan kita akan berkomunikasi dan meningkatkan bersama.