---
title: "OpenResty FAQ | Dynamic Load, NYI, dan Caching dari Shared Dict - API7.ai"
description: "Artikel ini menjelaskan tentang dynamic loading, blocking operations, NYI, dynamic upstream, dan caching dari shared dictionaries."
url: "https://api7.ai/id/learning-center/openresty/faq-4"
---

# OpenResty FAQ | Dynamic Load, NYI, dan Caching dari Shared Dict

API7.ai

January 19, 2023

[OpenResty (NGINX + Lua)](https://api7.ai/learning-center/openresty)

Seri artikel Openresty telah diperbarui sejauh ini, dan bagian tentang optimasi performa adalah semua yang telah kita pelajari. Selamat kepada Anda yang tidak tertinggal, masih aktif belajar dan berlatih, serta antusias meninggalkan pemikiran Anda.

Kami telah mengumpulkan banyak pertanyaan yang lebih khas dan menarik, dan berikut adalah lima di antaranya.

## Pertanyaan 1: Bagaimana cara melakukan pemuatan dinamis modul Lua?

> **Deskripsi:** Saya memiliki pertanyaan tentang pemuatan dinamis yang diimplementasikan di OpenResty. Bagaimana cara menggunakan fungsi `loadstring` untuk menyelesaikan pemuatan file baru setelah diganti? Saya memahami bahwa `loadstring` hanya dapat memuat string, jadi jika saya ingin memuat ulang file/modul lua, bagaimana cara melakukannya di OpenResty?

Seperti yang kita ketahui, `loadstring` digunakan untuk memuat string, sedangkan `loadfile` dapat memuat file yang ditentukan, misalnya: `loadfile("foo.lua")`. Kedua perintah ini mencapai hasil yang sama. Adapun cara memuat modul Lua, berikut adalah contohnya:

```
resty -e 'local s = [[
local ngx = ngx
local _M = {}
function _M.f()
    ngx.say("hello world")
end
return _M
]]
local lua = loadstring(s)
local ret, func = pcall(lua)
func.f()'
```

Konten dari string `s` adalah modul Lua yang lengkap. Jadi, ketika Anda menemukan perubahan dalam kode modul ini, Anda dapat memulai ulang pemuatan dengan `loadstring` atau `loadfile`. Dengan cara ini, fungsi dan variabel di dalamnya akan diperbarui bersamanya.

Untuk melangkah lebih jauh, Anda juga dapat membungkus pengambilan perubahan dan pemuatan ulang dengan lapisan yang disebut fungsi `code_loader`.

```
local func = code_loader(name)
```

Ini membuat pembaruan kode menjadi jauh lebih ringkas. Pada saat yang sama, `code_loader` umumnya menggunakan `lru cache` untuk menyimpan `s` agar tidak perlu memanggil `loadstring` setiap kali.

## Pertanyaan 2: Mengapa OpenResty tidak melarang operasi yang memblokir?

> **Deskripsi:** Selama bertahun-tahun, saya selalu bertanya-tanya, karena panggilan yang memblokir ini secara resmi tidak disarankan, mengapa tidak langsung menonaktifkannya? Atau menambahkan flag untuk memungkinkan pengguna memilih untuk menonaktifkannya?

Ini adalah pendapat pribadi saya. Pertama, karena ekosistem di sekitar OpenResty tidak sempurna, terkadang kita harus memanggil library yang memblokir untuk mengimplementasikan beberapa fungsi. Misalnya, sebelum versi 1.15.8, Anda harus menggunakan library Lua `os.execute` alih-alih `lua-resty-shell` untuk memanggil perintah eksternal. Misalnya, di OpenResty, membaca dan menulis file masih hanya mungkin dengan library I/O Lua, dan belum ada alternatif non-blocking.

Kedua, OpenResty sangat berhati-hati dalam optimasi semacam ini. Misalnya, `lua-resty-core` telah dikembangkan untuk waktu yang lama, tetapi belum pernah diaktifkan secara default, mengharuskan Anda untuk memanggil `require 'resty.core'` secara manual. Baru diaktifkan hingga rilis terbaru 1.15.8.

Terakhir, para pengelola OpenResty lebih suka menstandarisasi panggilan yang memblokir dengan menghasilkan kode Lua yang sangat dioptimalkan melalui kompiler dan DSL. Jadi, tidak ada upaya untuk melakukan sesuatu seperti opsi flag pada platform OpenResty itu sendiri. Tentu saja, saya tidak yakin apakah arah ini dapat menyelesaikan masalah.

Dari sudut pandang pengembang eksternal, masalah yang lebih praktis adalah bagaimana menghindari pemblokiran semacam itu. Kita dapat memperluas alat deteksi kode Lua, seperti `luacheck`, untuk menemukan dan mengingatkan operasi pemblokiran umum, atau kita dapat secara intrusif menonaktifkan atau menulis ulang beberapa fungsi langsung dengan menulis ulang `_G`, misalnya:

```
resty -e '_G.ngx.print = function()
ngx.say("hello")
end
ngx.print()'

# hello
```

Dengan kode contoh ini, Anda dapat menulis ulang fungsi `ngx.print` secara langsung.

## Pertanyaan 3: Apakah operasi NYI LuaJIT memiliki dampak besar pada performa?

> **Deskripsi:** `loadstring` menunjukkan `never` dalam daftar NYI LuaJIT. Apakah ini akan memiliki dampak besar pada performa?

Mengenai NYI LuaJIT, kita tidak perlu terlalu ketat. Untuk operasi yang dapat di-JIT, pendekatan JIT tentu yang terbaik; tetapi untuk operasi yang belum dapat di-JIT, kita dapat terus menggunakannya.

Untuk optimasi performa, kita perlu mengambil pendekatan ilmiah berbasis statistik, itulah yang dilakukan oleh sampling flame graph. Optimasi prematur adalah akar dari segala kejahatan. Kita hanya perlu mengoptimalkan kode panas yang banyak dipanggil dan mengonsumsi banyak CPU.

Kembali ke `loadstring`, kita hanya akan memanggilnya untuk memuat ulang ketika kode berubah, bukan saat diminta, jadi ini bukan operasi yang sering. Pada titik ini, kita tidak perlu khawatir tentang dampaknya terhadap performa keseluruhan sistem.

Sejalan dengan masalah pemblokiran kedua, di OpenResty, kita terkadang juga memanggil operasi I/O file yang memblokir selama fase `init` dan `init worker`. Operasi ini lebih mengorbankan performa daripada NYI, tetapi karena hanya dilakukan sekali saat layanan dimulai, ini dapat diterima.

Seperti biasa, optimasi performa harus dilihat dari perspektif makro, poin yang perlu Anda perhatikan dengan baik. Jika tidak, dengan terobsesi pada detail tertentu, Anda kemungkinan akan mengoptimalkan untuk waktu yang lama tetapi tidak memiliki efek yang baik.

## Pertanyaan 4: Bisakah saya mengimplementasikan upstream dinamis sendiri?

> **Deskripsi:** Untuk upstream dinamis, pendekatan saya adalah menyiapkan 2 upstream untuk satu layanan, memilih upstream yang berbeda sesuai dengan kondisi routing, dan langsung memodifikasi IP di upstream ketika IP mesin berubah. Apakah ada kelemahan atau jebakan dalam pendekatan ini dibandingkan dengan menggunakan `balancer_by_lua` langsung?

Keuntungan dari `balancer_by_lua` adalah memungkinkan pengguna untuk memilih algoritma load balancing, misalnya, apakah menggunakan `roundrobin` atau `chash`, atau algoritma lain yang diimplementasikan pengguna, yang fleksibel dan berkinerja tinggi.

Jika Anda melakukannya dengan cara aturan routing, hasilnya sama. Tetapi pemeriksaan kesehatan upstream perlu diimplementasikan oleh Anda, menambah banyak pekerjaan tambahan.

Kita juga dapat memperluas pertanyaan ini dengan menanyakan bagaimana kita harus mengimplementasikan skenario ini untuk `abtest`, yang memerlukan upstream yang berbeda.

Anda dapat memutuskan upstream mana yang akan digunakan dalam fase `balancer_by_lua` berdasarkan `uri`, `host`, `parameter`, dll. Anda juga dapat menggunakan gateway API untuk mengubah penilaian ini menjadi aturan routing, memutuskan rute mana yang akan digunakan dalam fase `access` awal, dan kemudian menemukan upstream yang ditentukan melalui hubungan binding antara rute dan upstream. Ini adalah pendekatan umum untuk gateway API, dan kita akan membahasnya lebih spesifik nanti di bagian praktik.

## Pertanyaan 5: Apakah caching `shared dict` wajib?

> **Deskripsi:**
>
> Dalam aplikasi produksi nyata, saya pikir lapisan cache `shared dict` adalah suatu keharusan. Sepertinya semua orang hanya mengingat kebaikan `lru cache`, tidak ada batasan format data, tidak perlu deserialisasi, tidak perlu menghitung ruang memori berdasarkan volume k/v, tidak ada persaingan antar worker, tidak ada kunci baca/tulis dan performa tinggi.
>
> Namun, jangan mengabaikan bahwa salah satu kelemahan paling fatalnya adalah bahwa siklus hidup `lru cache` mengikuti `Worker`. Setiap kali NGINX reload, bagian cache ini akan hilang sepenuhnya, dan pada saat ini, jika tidak ada `shared dict`, sumber data `L3` akan tergantung dalam hitungan menit.
>
> Tentu saja, ini adalah kasus konkurensi yang lebih tinggi, tetapi karena caching digunakan, volume bisnis pasti tidak kecil, yang berarti analisis yang baru saja disebutkan masih berlaku. Jika saya benar dalam pandangan ini?

Dalam beberapa kasus, memang benar, seperti yang Anda katakan, `shared dict` tidak hilang selama reload, jadi itu diperlukan. Tetapi ada kasus khusus di mana hanya `lru cache` yang dapat diterima jika semua data tersedia secara aktif dari sumber data `L3` dalam fase `init` atau `init_worker`.

Misalnya, jika gateway API open source [APISIX](https://apisix.apache.org/) memiliki sumber datanya di `etcd`, itu hanya mengambil data dari `etcd`. Ini menyimpannya dalam `lru cache` selama fase `init_worker`, dan pembaruan cache selanjutnya diambil secara aktif melalui mekanisme `watch` `etcd`. Dengan cara ini, bahkan jika NGINX reload, tidak akan ada cache stampede.

Jadi, kita dapat memiliki preferensi dalam memilih teknologi tetapi jangan menggeneralisasi secara absolut karena tidak ada solusi tunggal yang cocok untuk semua skenario caching. Ini adalah cara yang baik untuk membangun solusi minimal yang tersedia sesuai dengan kebutuhan skenario aktual dan kemudian meningkatkannya secara bertahap.

Share article link

Share

Related Posts

[![OpenResty FAQ | Bagaimana OpenResty Digunakan dalam Praktik](https://static.api7.ai/uploads/2023/02/12/jbv9M0zi_Hello%20World%20in%20OpenResty%20%283%29.png)](https://api7.ai/learning-center/openresty/faq-5)

## [OpenResty FAQ | Bagaimana OpenResty Digunakan dalam Praktik](https://api7.ai/learning-center/openresty/faq-5)

[![Bagian 3: Cara Membangun Microservices API Gateway Menggunakan OpenResty](https://static.api7.ai/uploads/2023/02/07/3XJXY9Jy_45.png)](https://api7.ai/learning-center/openresty/how-to-build-a-microservices-api-gateway-part-3)

## [Bagian 3: Cara Membangun Microservices API Gateway Menggunakan OpenResty](https://api7.ai/learning-center/openresty/how-to-build-a-microservices-api-gateway-part-3)

Table of Contents

- [Pertanyaan 1: Bagaimana cara melakukan pemuatan dinamis modul Lua?](#pertanyaan-1-bagaimana-cara-melakukan-pemuatan-dinamis-modul-lua)
- [Pertanyaan 2: Mengapa OpenResty tidak melarang operasi yang memblokir?](#pertanyaan-2-mengapa-openresty-tidak-melarang-operasi-yang-memblokir)
- [Pertanyaan 3: Apakah operasi NYI LuaJIT memiliki dampak besar pada performa?](#pertanyaan-3-apakah-operasi-nyi-luajit-memiliki-dampak-besar-pada-performa)
- [Pertanyaan 4: Bisakah saya mengimplementasikan upstream dinamis sendiri?](#pertanyaan-4-bisakah-saya-mengimplementasikan-upstream-dinamis-sendiri)
- [Pertanyaan 5: Apakah caching `shared dict` wajib?](#pertanyaan-5-apakah-caching-shared-dict-wajib)
