Mengapa Anda perlu membuat modul untuk nginx

Nginx adalah server web yang memecahkan banyak tugas bisnis, dikonfigurasi secara fleksibel, diskalakan dan bekerja pada hampir semua OS dan platform. Daftar fitur, kemampuan, dan masalah yang harus dipecahkan di luar kotak dapat dijelaskan dalam brosur kecil. Namun terkadang, sejumlah tugas bisnis hanya dapat diselesaikan dengan mengembangkan modul Anda sendiri untuk nginx. Ini adalah modul yang berorientasi bisnis dan mengandung beberapa logika bisnis, dan bukan hanya solusi sistem umum.



Secara umum, semua yang ada di nginx adalah modul yang pernah ditulis oleh seseorang. Oleh karena itu, menulis modul di bawah nginx tidak hanya mungkin, tetapi juga perlu. Ketika perlu untuk melakukannya dan mengapa, Vasily Soshnikov ( dedokOne ) akan memberi tahu contoh beberapa kasus.

Mari kita bicara tentang alasan yang mendorong penulisan modul dalam C, tentang arsitektur dan inti nginx, anatomi modul HTTP, tentang modul C, NJS, Lua, dan nginx.conf. Ini penting untuk diketahui tidak hanya bagi mereka yang berkembang di bawah nginx, tetapi juga bagi mereka yang menggunakan nginx-configs, Lua atau bahasa lain di dalam nginx.

Catatan: artikel ini didasarkan pada laporan oleh Vasily Soshnikov. Laporan ini terus diperbarui dan diperbarui. Informasi dalam materi ini cukup teknis dan untuk mendapatkan hasil maksimal, pembaca perlu memiliki pengalaman bekerja dengan kode nginx pada tingkat rata-rata ke atas.


Secara singkat tentang nginx


Yang Anda gunakan dengan nginx adalah modul . Setiap arahan dalam konfigurasi nginx adalah modul terpisah, yang ditulis dengan cermat oleh rekan-rekan dari komunitas nginx.

Arahan di nginx.conf juga merupakan modul yang memecahkan masalah tertentu. Oleh karena itu, dalam modul nginx adalah segalanya. add_header, proxy_pass, arahan apa saja - ini adalah modul atau kombinasi modul yang bekerja sesuai dengan aturan tertentu.

Nginx adalah kerangka kerja yang memiliki: Network & File I / O, Shared Memory, Configuration & Scripting. Ini adalah lapisan besar pustaka tingkat rendah, tempat Anda dapat melakukan apa saja untuk bekerja dengan drive jaringan.

Nginx cepat dan stabil, tetapi rumit . Anda harus menulis kode tersebut agar tidak kehilangan kualitas nginx ini. Nginx tidak stabil pada produksi adalah klien yang tidak puas, dan semua yang berikut dari ini.

Mengapa membuat modul Anda sendiri


Konversi protokol HTTP ke protokol lain. Inilah alasan utama yang sering memotivasi pembuatan modul tertentu.

Sebagai contoh, modul memcached_pass mengkonversi HTTP ke protokol lain, dan Anda dapat bekerja dengan sistem eksternal lainnya. Modul proxy_pass juga memungkinkan Anda untuk mengkonversi, meskipun dari HTTP (s) ke HTTP (s). Contoh bagus lainnya adalah fastcgi_pass.

Ini semua adalah arahan dari formulir: "pergi ke backend ini dan itu, di mana bukan HTTP (tetapi dalam kasus HTTP proxy_pass)."

Penyisipan konten dinamis: Bypass AdBlock, penyisipan iklan. Sebagai contoh, kami memiliki backend dan perlu untuk mengubah konten yang berasal darinya. Misalnya, AdBlock, yang menganalisis kode penyisipan iklan, dan kami harus menanganinya - untuk menyetelnya dengan satu atau lain cara.

Hal lain yang sering harus Anda lakukan untuk menanamkan konten adalah masalah dengan caching HLS. Ketika parameter di-cache di dalam HLS, maka dua pengguna bisa mendapatkan sesi yang sama atau parameter yang sama. Dari sana, Anda memotong atau menambahkan beberapa parameter saat Anda perlu melacak sesuatu.

Pengumpulan data Clickstream dari internet / meter seluler. Kasus yang populer dalam praktik saya. Paling sering ini dilakukan pada nginx, tetapi tidak pada access.log, tetapi sedikit lebih cerdas.

Konversi semua jenis konten. Misalnya, modul rtmp untuk memungkinkan Anda bekerja tidak hanya dengan rtmp, tetapi juga dengan HLS. Modul ini dapat melakukan banyak hal dengan konten video.

Titik otorisasi umum: SEP atau Api Gateway. Ini adalah kasus ketika nginx berfungsi sebagai bagian dari infrastruktur: mengesahkan, mengumpulkan metrik, mengirim data ke pemantauan dan ClickStream. Nginx bekerja di sini sebagai hub infrastruktur - titik masuk tunggal untuk backend.

Pengayaan permintaan untuk penelusuran selanjutnya. Sistem modern sangat kompleks, dengan beberapa jenis backend yang membuat tim berbeda. Sebagai aturan, mereka sulit untuk debut, kadang-kadang bahkan sulit untuk memahami dari mana permintaan itu berasal dan ke mana ia pergi. Untuk menyederhanakan debugging, beberapa perusahaan besar menggunakan teknik yang rumit - mereka menambahkan data tertentu ke permintaan. Pengguna tidak akan melihatnya, tetapi dari data ini mudah untuk melacak jalur permintaan di dalam sistem. Ini disebut jejak .

S3-proxy. Tahun ini, saya sering melihat orang-orang bekerja dengan objek mereka melalui s3. Tetapi tidak perlu melakukan ini pada modul-C, infrastrukturnya cukup memadai di nginx juga. Untuk mengatasi beberapa masalah ini, Anda dapat menggunakan Lua, sesuatu sedang dipecahkan di NJS. Tetapi kadang-kadang perlu untuk menulis modul dalam C.

Kapan waktu untuk membuat modul


Ada dua kriteria untuk dipahami bahwa waktunya telah tiba.

Generalisasi fungsionalitas. Ketika Anda memahami bahwa orang lain membutuhkan produk Anda, maka Anda berkontribusi ke Open Source, membuat fungsionalitas umum, mempostingnya dan membiarkannya digunakan.

Memecahkan masalah bisnis. Ketika sebuah bisnis menetapkan persyaratan seperti itu yang dapat dipenuhi hanya dengan menulis modul sendiri untuk nginx. Misalnya, penyisipan dinamis / perubahan konten, koleksi ClickStream dapat dilakukan pada Lua, tetapi kemungkinan besar itu tidak akan berfungsi secara normal.

Arsitektur nginx


Saya telah menulis kode nginx untuk waktu yang lama. Sembilan modul saya berputar dalam produksi, salah satunya di Open Source, dan dalam produksi untuk banyak orang. Karena itu, saya memiliki pengalaman dan pengertian.
Nginx adalah boneka bersarang di mana semuanya dibangun di sekitar kernel.
Jadi saya mengerti nginx.
Inti adalah pembungkus di atas epoll.
Epoll adalah metode yang memungkinkan Anda untuk bekerja secara tidak sinkron dengan file deskriptor apa pun, bukan hanya soket, karena deskriptor bukan hanya soket.

Di atas intinya adalah upstreams, HTTP, dan scripting. Dengan scripting, maksud saya nginx.conf, bukan NJS. Di atas upstreams, HTTP, dan scripting, modul HTTP sudah dibangun, yang akan kita bicarakan.



Contoh klasik upstreams dan HTTP adalah server upstream - arahan di dalam konfigurasi. Contoh modul untuk HTTP adalah add_header. Contoh skrip adalah file konfigurasi itu sendiri. File tersebut berisi modul-modul yang terdiri dari nginx, ditafsirkan dengan cara apa pun dan memungkinkan Anda untuk melakukan sesuatu sebagai administrator atau sebagai pengguna Anda.

Kami tidak akan mempertimbangkan inti dan tinggal sebentar di upstream, karena itu adalah alam semesta yang terpisah di dalam nginx. Kisah tentang mereka layak untuk beberapa artikel.

Anatomi Modul HTTP


Bahkan jika Anda tidak menulis kode C di dalam nginx, tetapi menggunakannya, ingat aturan utama.
Dalam nginx, semuanya mematuhi Rantai Tanggung Jawab - pola COR.
Saya tidak tahu bagaimana menerjemahkan ini ke dalam bahasa Rusia, tetapi saya akan menjelaskan logikanya. Permintaan Anda melewati galaksi modul rantai yang dikonfigurasi, mulai dari lokasi. Masing-masing modul ini mengembalikan hasilnya. Jika hasilnya buruk, rantai terputus.



Saat mengembangkan modul atau menggunakan beberapa arahan dalam NJS dan Lua, jangan lupa bahwa kode Anda dapat menyebabkan crash pada eksekusi rantai ini.

Analogi terdekat dengan Chain of Responsibility adalah garis kode Bash:

grep -RI pool nginx | awk -F":" '{print $1}' | sort -u | wc -l 

Dalam kode, semuanya cukup sederhana: jika AWK jatuh di tengah baris, maka sort dan perintah berikut tidak akan dieksekusi. Modul nginx bekerja dengan cara yang sama, tetapi kebenarannya ada di nginx dan Anda bisa menyiasatinya - restart kode. Tetapi Anda harus siap untuk crash dan menjalankan, sama seperti modul Anda yang Anda gunakan dalam konfigurasi, tetapi bukan fakta bahwa ini benar.

Jenis-jenis Modul HTTP


HTTP dan nginx adalah sekelompok FASE berbeda.

  • Penanganan Fase - penangan FASE .
  • Filter - Filter Badan / Tajuk . Penyaringan ini adalah Kepala atau badan permintaan.
  • Proksi . Modul proxy yang umum adalah proxy_pass, fastcgi_pass, memcached_pass.
  • Modul untuk menyeimbangkan beban tertentu - Load balancers . Ini adalah jenis modul yang paling tidak terpilin, mereka tidak banyak dikembangkan. Contohnya adalah modul Ketama CHash, yang memungkinkan Anda melakukan hashing yang konsisten di dalam nginx untuk mendistribusikan permintaan ke backend.

Saya akan menceritakan tentang masing-masing tipe ini dan tujuannya.

Penangan fase


Bayangkan kita memiliki beberapa fase, mulai dari fase akses. Ada beberapa modul di setiap fase. Misalnya, fase ACCESS dibagi menjadi koneksi, permintaan ke nginx, verifikasi otorisasi pengguna. Setiap modul adalah sel dalam rantai. Mungkin ada jumlah modul yang tak terbatas dalam fase.



Penangan terakhir, terakhir adalah fase KONTEN di mana konten dikirimkan sesuai permintaan.
Caranya selalu seperti ini: request - rantai penangan - konten keluaran.
Fase yang tersedia untuk pengembang modul dari sumber NGINX :

 typedef enum { NGX_HTTP_POST_READ_PHASE = 0, NGX_HTTP_SERVER_REWRITE_PHASE, NGX_HTTP_FIND_CONFIG_PHASE, NGX_HTTP_REWRITE_PHASE, NGX_HTTP_POST_REWRITE_PHASE, NGX_HTTP_PREACCESS_PHASE, NGX_HTTP_ACESS_PHASE, NGX_HTTP_POST_ACESS_PHASE, NGX_HTTP_PRECONTENT_PHASE, NGX_HTTP_CONTENT_PHASE, NGX_HTTP_LOG_PHASE, } ngx_http_phases; 

Fase dapat ditimpa, tambahkan handler Anda sendiri. Tidak semuanya dibutuhkan dalam kehidupan nyata, jika Anda bukan pengembang nginx core. Karena itu, saya tidak akan berbicara tentang setiap fase, tetapi hanya tentang yang utama yang saya gunakan.

Yang utama adalah ACCESS_PHASE. Sangat berguna untuk menambahkan otorisasi Anda ke nginx - untuk memeriksa eksekusi permintaan dalam hal akses.

Fase penting berikutnya yang sering saya manfaatkan adalah fase pra-konten dan konten. PRECONTENT_PHASE memungkinkan Anda mengumpulkan metrik tentang konten yang akan dikirim sebagai respons kepada klien. CONTENT_PHASE memungkinkan Anda membuat konten unik sendiri berdasarkan sesuatu.

Fase terakhir yang sering saya gunakan adalah fase logging LOG_PHASE. Secara kebetulan, arahan ACCESS_LOG berfungsi di dalamnya. Fase logging memiliki batasan terliar yang membuat saya gila: Anda tidak dapat menggunakan subrequest dan umumnya Anda tidak dapat menggunakan permintaan apa pun. Anda telah menyerahkan konten kepada pengguna, dan penangan, pengalih pesan dan setiap subrequest tidak akan dieksekusi.

Saya akan menjelaskan mengapa itu menjengkelkan. Katakanlah ketika Anda ingin menyeberang nginx dan Kafka dalam fase logging. Pada fase ini, semuanya telah selesai: ada ukuran konten, status, semua data yang dihitung, tetapi Anda tidak dapat melakukannya subrequest. Mereka tidak bekerja di sana. Anda harus menulis di soket kosong pada fase logging untuk mengirim data ke Kafka.

Filter Badan / Tajuk


Ada dua jenis filter: Filter tubuh dan filter Tajuk.

Contoh dari filter Tubuh adalah modul filter gzip. Mengapa filter tubuh diperlukan? Bayangkan Anda memiliki proxy_pass tertentu, dan Anda ingin mengubah konten atau menganalisisnya. Dalam hal ini, Anda harus menggunakan filter Tubuh.

Ini bekerja seperti ini: banyak potongan datang kepada Anda, Anda melakukan sesuatu dengan mereka, lihat isinya, agregat, dll. Tetapi filter juga memiliki batasan yang signifikan. Misalnya, jika Anda memutuskan untuk mengubah isi - untuk menyisipkan atau memotong isi tanggapan, ingat bahwa atribut HTTP, misalnya, umpan konten, akan diganti. Ini dapat menyebabkan efek aneh jika Anda tidak memberikan batasan dan merefleksikan dengan benar dalam kode Anda.

Contoh filter Header adalah add_header yang digunakan semua orang. Algoritma bekerja seperti pada filter Tubuh. Respons disiapkan untuk klien, dan filter add_header memungkinkan Anda melakukan sesuatu di sana: tambahkan tajuk, hapus tajuk, ganti tajuk, kirim subrequest.

Ngomong-ngomong, di filter Tubuh dan di subrequest filter Header tersedia, Anda bahkan dapat mengirim identifikasi internal ke lokasi tambahan di sana.

Proksi


Ini adalah jenis modul yang paling kompleks dan kontroversial yang memungkinkan Anda untuk mem-proxy permintaan ke sistem eksternal, misalnya, mengonversi HTTP ke protokol lain . Contoh: proxy_pass, redis_pass, tnt_pass.

Proxy adalah antarmuka yang diusulkan pengembang nginx core untuk membuat penulisan modul proxy lebih mudah. Jika ini dilakukan dengan cara klasik, maka untuk proxy penangan PHASES, filter, Balancers akan dieksekusi. Namun, jika protokol yang ingin Anda konversi HTTP berbeda dari yang klasik, maka masalah besar akan dimulai. API proxy yang diberikan nginx sama sekali tidak cocok - Anda harus membuat modul proxy ini dari awal.

Contoh modul yang bagus adalah postgres_pass. Memungkinkan nginx untuk berkomunikasi dengan PostgreSQL. Modul ini tidak menggunakan antarmuka yang dikembangkan di nginx sama sekali - ia memiliki jalurnya sendiri.
Ingat proksi, tetapi sebaiknya jangan menulis. Untuk menulis proxy, Anda harus mempelajari semua nginx dengan hati - itu sangat panjang dan sulit.

Muat penyeimbang


Tugas Load balancers sangat sederhana - untuk bekerja dalam mode round-robin. Bayangkan bahwa Anda memiliki bagian hulu, beberapa server di dalamnya, Anda menentukan bobot dan metode penyeimbangan. Ini adalah penyeimbang beban tipikal.

Mode ini tidak selalu cocok. Oleh karena itu, modul Ketama CHash dikembangkan, di mana dimungkinkan secara kondisional untuk sampai pada permintaan hash yang konsisten ke beberapa server. Terkadang itu nyaman. Nginx Lua menawarkan balancer_by_lua. Pada Lua, Anda dapat menulis penyeimbang apa pun secara umum.

Modul C


Berikutnya akan menjadi pendapat subjektif saya tentang pengembangan C-modules. Untuk mulai dengan - aturan subjektif saya.

Modul ini dimulai dengan arahan nginx.conf. Bahkan jika Anda membuat modul-C yang hanya akan dioperasikan oleh perusahaan Anda, selalu pikirkan arahan. Mulai merancang modul dengan mereka, karena ini adalah apa yang akan berkomunikasi dengan administrator sistem. Ini penting - koordinasikan semua nuansa dengan dia atau dengan orang yang akan mengoperasikan modul-C Anda. NGINX adalah produk yang terkenal, arahannya mematuhi undang-undang tertentu yang diketahui oleh administrator sistem. Karena itu, selalu memikirkannya.

Gunakan gaya kode nginx. Bayangkan bahwa modul Anda akan didukung oleh orang lain. Jika dia sudah terbiasa dengan nginx dan gaya kodenya, akan lebih mudah baginya untuk membaca dan memahami kode Anda.

Baru-baru ini, seorang teman baik dari Jerman meminta saya untuk membantunya menangani bug di dalam kode nginx-nya. Saya tidak tahu untuk gaya kode apa yang ditulisnya, tetapi saya bahkan tidak bisa membaca kodenya secara normal.

Gunakan kumpulan memori yang benar. Ingatlah selalu hal ini, bahkan jika Anda memiliki banyak pengalaman dengan nginx. Kesalahan umum pengembang modul C pemula untuk nginx adalah mendapatkan kumpulan yang salah.

Sedikit latar belakang: nginx umumnya menggunakan ideologi pengalokasi yang lemah. Anda dapat menggunakan malloc di sana, tetapi tidak disarankan. Ini memiliki lempengan sendiri, pengalokasi memorinya sendiri; Oleh karena itu, setiap objek memiliki tautan ke kumpulannya, dan kumpulan ini perlu digunakan. Kesalahan pemula pada umumnya adalah menggunakan koneksi kumpulan di filter header, bukan permintaan kumpulan. Ini berarti bahwa jika kita memiliki koneksi tetap-hidup, kolam akan membengkak sampai kehabisan memori atau efek samping lainnya terjadi. Karena itu, penting.

Apalagi kesalahan seperti itu sangat sulit untuk debut. Valgrind ("syshniks" akan mengerti) tidak bekerja dengan alokasi slab - ini akan menampilkan gambar yang aneh.

Jangan gunakan pemblokiran I / O. Kesalahan umum dari mereka yang ingin menerapkan sesuatu eksternal lebih cepat adalah dengan menggunakan memblokir I / O dan memblokir soket. Anda tidak pernah dapat melakukan ini di nginx - ada banyak proses di dalamnya, tetapi setiap proses menggunakan satu utas.

Anda dapat melakukan multi-threading, tetapi, sebagai aturan, ini hanya memperburuknya. Jika Anda menggunakan pemblokiran I / O dalam arsitektur seperti itu, maka semua orang akan menunggu bagian pemblokiran ini.

Saya akan menguraikan apa yang saya katakan di atas.

Modul ini dimulai dengan arahan nginx.conf

Tentukan di mana array arahan Anda harus hidup: Utama, Server, HTTP, lokasi, lokasi jika.
Cobalah untuk menghindari lokasi jika - sebagai aturan, ini mengarah ke penggunaan konfigurasi nginx yang sangat aneh.

Semua arahan dalam nginx hidup dalam konteks dan lingkup yang berbeda. Arahan add_header dapat bekerja pada level HTTP, pada level lokasi, pada level lokasi-jika-level. Ini biasanya dijelaskan dalam dokumentasi.
Pahami pada level apa arahan Anda dapat bekerja, di mana arahan dijalankan: PHASE Handler, Filter Header / Badan.
Ini penting karena dalam nginx konfigurasi dibekukan. Secara konvensi, ketika Anda menulis add_header di suatu tempat di atas, nilai ini dihaluskan di add_header bawah, yang sudah Anda miliki di lokasi. Dengan demikian, Anda akan menambahkan dua header. Ini berlaku untuk arahan apa pun.

Jika Anda menentukan sesuatu port host, maka sebaliknya - kumpulan soket. Ini harus ditunjukkan satu kali.

Secara umum, saya akan melarang penggabungan - Anda hanya tidak membutuhkannya. Oleh karena itu, Anda harus selalu menentukan dengan jelas di mana nginx array dari konfigurasi arahan atau set arahan Anda.

Contoh yang bagus:

 location /my_location/ { add_header “My-Header” “my value”; } 

Di sini add_header hanya ditambahkan ke lokasi. Add_header yang sama bisa berada di suatu tempat di atas, dan semuanya akan berubah bentuk. Ini adalah perilaku yang terdokumentasi dan dapat dimengerti.
Pikirkan tentang apa yang mungkin menghambat implementasi arahan.
Bayangkan Anda sedang mengembangkan filter Tubuh. Seperti yang saya katakan di atas, nginx hanya meletakkan modul Anda di rantai yang sama, dan Anda tidak memiliki jaminan bahwa modul gzip tidak masuk ke rantai di depan filter Tubuh Anda pada waktu kompilasi. Dalam hal ini, jika seseorang menyalakan modul gzip, data akan dikirim ke modul Anda untuk gzip. Ini mengancam bahwa Anda tidak dapat melakukan apa pun dengan konten tersebut. Anda dapat melakukan gzip kembali, misalnya, tetapi ini adalah ejekan dari sudut pandang CPU.

Aturan yang sama berlaku untuk semua penangan fase - tidak ada jaminan siapa yang akan dipanggil sebelum dan siapa yang mengejar. Karena itu, hormati orang yang akan dipanggil, dan ingat bahwa beberapa gzip atau sesuatu yang lain mungkin tiba-tiba terbang ke Anda.

Gaya kode nginx


Ketika Anda membuat produk, ingatlah bahwa seseorang akan mendukungnya. Jangan lupa tentang kode gaya nginx.
Sebelum menulis modul nginx Anda, biasakan diri Anda dengan sumber: satu dan yang kedua .

Jika di masa depan Anda mengambil pengembangan modul nginx, maka Anda akan mengetahui sumber-sumber nginx. Anda akan menyukainya karena tidak ada dokumentasi . Anda akan mempelajari struktur direktori nginx dengan baik, belajar menggunakan Grep, mungkin Sed, ketika Anda perlu mentransfer beberapa bagian dari nginx ke modul Anda.

Kolam memori


Kolam harus digunakan dengan benar. Misalnya, "r-> connection-> pool! = R-> pool". Dalam kasus apa pun Anda tidak dapat menggunakan konfigurasi kumpulan memori saat memproses permintaan, itu akan membengkak sampai nginx restart.

Memahami umur objek. Misalkan permintaan replay memiliki umur pipa yang persis seperti ini. Di kolam ini Anda bisa meletakkan banyak barang dan membuat ruangan. Koneksi dapat hidup secara teoritis tanpa batas - lebih baik menempatkan sesuatu yang sangat penting di dalamnya.

Usahakan untuk tidak menggunakan pengalokasi eksternal, misalnya, malloc / gratis . Ini memiliki efek buruk pada fragmentasi memori. Jika Anda beroperasi dengan volume data yang besar dan menggunakan banyak malloc, nginx ini melambat dengan cukup baik.

Untuk penggemar Valgrind ada peretasan yang memungkinkan Anda untuk men-debug nginx-pools menggunakan Valgrind. Ini penting jika Anda memiliki banyak kode C pada nginx, karena bahkan pengembang yang berpengalaman dalam bekerja dengan memori dapat membuat kesalahan.

Memblokir I / O

Semuanya sederhana di sini - jangan gunakan pemblokiran I / O.
Kalau tidak, setidaknya akan ada masalah dengan koneksi tetap hidup, tetapi sebagai maksimum, semuanya akan bekerja untuk waktu yang sangat lama.

Saya tahu kasusnya ketika seseorang menggunakan Quora di dalam nginx dalam mode blocking (jangan tanya kenapa). Ini mengarah pada fakta bahwa koneksi tetap hidup meninggalkan aktivitas mereka dan kehabisan waktu sepanjang waktu. Lebih baik tidak melakukan ini - semuanya akan bekerja untuk waktu yang lama, tidak efisien dan Anda harus segera memutar sejuta batas waktu, karena nginx akan memulai batas waktu pada banyak hal.

Tetapi ada alternatif untuk C-modul - NJS dan Lua.

Ketika Anda tidak perlu mengembangkan modul-C


Tahun ini saya memiliki pengalaman pertama saya bekerja di NJS, saya mendapat kesan subjektif, dan saya bahkan menyadari apa yang hilang di sana, sehingga semuanya baik-baik saja. Saya juga ingin berbicara tentang pengalaman saya bekerja pada Lua di bawah nginx, dan, apalagi, berbagi masalah yang ada di Lua.

Lua / LuaJit Essentials


Nginx tidak menggunakan Lua, tetapi LuaJit. Tapi ini bukan Lua, karena Lua sudah maju dua versi, dan LuaJit terjebak di suatu tempat di masa lalu. Penulis praktis tidak mengembangkan LuaJit - ia sering hidup dalam percabangan. Garpu terbaru adalah LuaJit2 . Ini menambah situasi aneh di OpenResty yang sama.

Pengumpul Sampah perlu mendapat perhatian . LuaJit tidak dapat mengatasi masalah ini - cukup buat beberapa solusi. Dengan beban yang besar, ketika banyak Kolektor Sampah yang tetap hidup akan terlihat pada klien dengan kegagalan pada grafik dan 500 kesalahan. Ada banyak cara untuk berurusan dengan Kolektor Sampah di Lua, saya tidak akan fokus pada mereka di sini. Ada banyak informasi tentang ini di Internet.

Implementasi string mengarah ke masalah kinerja . Ini hanya kejahatan LuaJit, dan di Lua itu diperbaiki. Implementasi string di LuaJit hanya menentang logika apa pun. Garis melambat dengan cara terliar, yang terkait dengan implementasi internal.

Ketidakmampuan untuk menggunakan banyak perpustakaan yang sudah jadi . Lua awalnya memblokir, jadi sebagian besar perpustakaan di Lua dan LuaJit menggunakan pemblokiran I / O. Karena fakta bahwa nginx tidak memblokir, tidak mungkin untuk menggunakan perpustakaan yang sudah jadi di dalam nginx yang menggunakan I / O pemblokiran apa pun. Ini akan memperlambat nginx.

Alasan menggunakan LuaJit identik dengan alasan menggunakan modul:

  • pembuatan prototipe modul yang kompleks;
  • HMAC, perhitungan SHA untuk otorisasi;
  • penyeimbang ;
  • aplikasi kecil: penangan header, aturan untuk pengalihan;
  • variabel komputasi untuk nginx.conf.

Di mana lebih baik tidak menggunakan LuaJit?
Aturan utama: jangan memproses tubuh besar di Lua - ini tidak bekerja.
Penangan untuk konten di Lua juga tidak berfungsi . Cobalah untuk meminimalkan logika hingga beberapa if . Sebuah penyeimbang sederhana akan bekerja, tetapi bilah sisi pada Lua akan bekerja dengan sangat buruk.

Memori bersama atau Pengumpul Sampah akan datang. Jangan gunakan Memori bersama dengan Lua - Pengumpul Sampah akan dengan cepat dan dengan jaminan mengeluarkan seluruh otak untuk diproduksi.

Jangan gunakan coroutine dengan banyak senyawa yang tetap hidup. Coroutine menghasilkan lebih banyak sampah di dalam Pengumpul Sampah LuaJit, yang mana ini buruk.

Jika Anda sudah menggunakan LuaJit, maka ingat:

  • tentang pemantauan memori;
  • tentang pemantauan dan optimalisasi pekerjaan Pengumpul Sampah;
  • tentang cara kerja Pengumpul Sampah, jika Anda memang menulis aplikasi yang rumit untuk LuaJit, karena Anda harus menambahkan sesuatu yang baru.

Njs


Ketika saya di NGINX Conf, mereka meyakinkan saya bahwa akan lebih baik untuk tidak menulis kode dalam C. Saya pikir saya harus mencoba, dan itulah yang saya dapatkan.

Otorisasi Berhasil, kodenya sederhana, tidak memengaruhi kecepatan - semuanya hebat. Prototipe kecil saya yang saya mulai adalah 10 baris kode. Tetapi 10 baris ini melakukan otorisasi dengan s3.

Komputasi variabel untuk nginx.conf. Banyak variabel dapat dihitung menggunakan NJS. Di dalam nginx, ini keren. Ada fitur seperti itu di Lua, tetapi ada seorang Kolektor Sampah, jadi tidak begitu keren.

Namun, tidak semuanya baik-baik saja. Untuk melakukan hal-hal yang sangat keren di NJS, dia kehilangan beberapa hal.

Memori Bersama . Saya menambal Memori Bersama, ini adalah garpu saya sendiri, jadi sekarang sudah cukup.

Filter mendukung lebih banyak fase . Di NJS, hanya ada fase konten dan variabel, dan filter header sangat kurang. Anda harus menulis kruk untuk menambahkan banyak tajuk. Tidak ada cukup filter tubuh untuk logika kompleks atau bekerja dengan konten.

Informasi tentang cara memonitor dan membuat profilnya . Saya sekarang tahu caranya, tetapi saya harus mempelajari sumbernya. Tidak ada informasi atau alat yang cukup tentang profil yang tepat. Jika ya, itu tersembunyi di tempat yang tidak dapat ditemukan. Pada saat yang sama, tidak ada cukup informasi tentang di mana saya bisa menggunakan NJS dan di mana saya tidak bisa?

Modul-C . Saya memiliki keinginan untuk memperluas NJS.

Kata penutup


Mengapa membuat modul Anda sendiri? Untuk memecahkan masalah umum dan bisnis.

Kapan saya perlu mengimplementasikan modul dalam C? Jika tidak ada pilihan lain. Misalnya, beban berat, penyisipan konten atau penghematan dasar pada perangkat keras. Maka ini harus dilakukan dijamin dalam C. Dalam kebanyakan kasus, Lua atau NJS cocok. Tetapi Anda harus selalu berpikir ke depan.

Dan pada Lua? Ketika Anda tidak dapat menulis dalam C. Misalnya, Anda tidak perlu mengonversi badan permintaan dengan RPS yang besar. Jumlah pelanggan Anda bertambah, pada titik tertentu Anda akan berhenti mengatasinya - pikirkanlah.

NJS? Ketika LuaJit benar-benar muak dengan Kolektor Sampah dan senarnya. Misalnya, otorisasi menghasilkan banyak objek Sampah di Lua, tetapi ini tidak penting. Namun, ini tercermin dalam pemantauan dan menjengkelkan. Sekarang sudah tidak lagi muncul dalam pemantauan saya, dan semuanya menjadi baik.

Di HighLoad ++ 2019, Vasily Soshnikov akan melanjutkan topik modul nginx dan berbicara lebih banyak tentang NJS, tidak melupakan perbandingan dengan LuaJit dan C.

Lihat daftar lengkap laporan di situs web, dan sampai jumpa pada 7 dan 8 November di konferensi terbesar untuk pengembang sistem yang sangat sarat. Ikuti ide-ide baru kami di buletin dan saluran telegram .

Source: https://habr.com/ru/post/id471684/


All Articles