Dokumen ini berisi penjelasan mengenai praktik terbaik untuk merancang, mengimplementasikan, menguji, dan men-deploy Cloud Functions.
Ketepatan
Bagian ini menjelaskan praktik terbaik yang umum untuk merancang dan mengimplementasikan Cloud Functions.
Menulis fungsi idempoten
Fungsi Anda harus memberikan hasil yang sama sekalipun dipanggil berkali-kali. Dengan demikian, Anda dapat mencoba ulang pemanggilan jika pemanggilan sebelumnya gagal di tengah jalan akibat masalah pada kode Anda. Untuk mengetahui informasi selengkapnya, lihat mencoba ulang fungsi berdasarkan peristiwa.
Jangan memulai aktivitas latar belakang
Aktivitas latar belakang meliputi segala sesuatu yang terjadi setelah fungsi Anda dihentikan.
Pemanggilan fungsi dianggap selesai setelah fungsi tersebut menampilkan atau menandakan penyelesaian, misalnya dengan memanggil argumen callback
di fungsi berdasarkan peristiwa Node.js. Setiap kode yang dijalankan setelah penghentian normal tidak dapat mengakses CPU dan tidak akan diproses.
Selain itu, ketika pemanggilan berikutnya dijalankan di lingkungan yang sama, aktivitas latar belakang Anda akan dilanjutkan, dan itu akan mengganggu pemanggilan baru. Hal ini dapat menyebabkan perilaku yang tidak terduga dan error yang sulit untuk didiagnosis. Mengakses jaringan setelah suatu fungsi berakhir biasanya menyebabkan koneksi disetel ulang (kode error ECONNRESET
).
Aktivitas latar belakang sering kali dapat dideteksi dalam log dari pemanggilan individu, dengan menemukan hal apa pun yang dicatat dalam log setelah baris yang menyatakan bahwa pemanggilan selesai. Aktivitas latar belakang terkadang dapat diletakkan lebih dalam di kode, terutama ketika terdapat operasi asinkron seperti callback atau timer. Tinjau kode Anda untuk memastikan semua operasi asinkron selesai sebelum fungsi dihentikan.
Selalu hapus file sementara
Penyimpanan disk lokal di direktori sementara adalah sistem file dalam memori. File yang Anda tulis menggunakan memori yang disediakan untuk fungsi Anda, dan terkadang tetap dipertahankan di antara pemanggilan. Jika file ini tidak dihapus secara eksplisit, dapat terjadi error kehabisan memori yang disusul dengan cold start.
Anda dapat melihat memori yang digunakan oleh setiap fungsi dengan memilihnya pada daftar fungsi di Konsol Google Cloud dan memilih plot Memory usage.
Usahakan tidak menulis di luar direktori sementara, dan pastikan untuk menggunakan metode yang tidak bergantung pada platform/OS untuk membuat jalur file.
Anda dapat mengurangi persyaratan memori saat memproses file yang lebih besar menggunakan pipeline. Misalnya, Anda dapat memproses file di Cloud Storage dengan membuat aliran data baca, meneruskannya melalui proses berbasis aliran data, dan menuliskan aliran data output langsung ke Cloud Storage.
Functions Framework
Saat Anda men-deploy suatu fungsi, Functions Framework akan otomatis ditambahkan sebagai dependensi menggunakan versi saat ini. Untuk memastikan dependensi yang sama diinstal secara konsisten di berbagai lingkungan, sebaiknya sematkan fungsi Anda ke versi Functions Framework tertentu.
Untuk melakukannya, sertakan versi pilihan Anda dalam file kunci yang relevan
(misalnya, package-lock.json
untuk Node.js, atau requirements.txt
untuk Python).
Alat
Bagian ini berisi panduan cara menggunakan fitur untuk mengimplementasikan, menguji, dan berinteraksi dengan Cloud Functions.
Pengembangan lokal
Deployment fungsi memerlukan waktu cukup lama. Jadi, sebaiknya lakukan pengujian kode fungsi secara lokal karena durasinya bisa lebih cepat.
Developer Firebase dapat menggunakan Firebase CLI Cloud Functions Emulator.Menggunakan Sendgrid untuk mengirim email
Cloud Functions tidak mengizinkan koneksi keluar pada port 25, sehingga Anda tidak dapat membuat koneksi tidak aman ke server SMTP. Cara yang direkomendasikan untuk mengirim email adalah dengan menggunakan SendGrid. Anda dapat menemukan opsi lain untuk mengirim email dalam tutorial Mengirim Email dari Instance untuk Google Compute Engine.
Performa
Bagian ini menjelaskan praktik terbaik untuk mengoptimalkan performa.
Menggunakan dependensi dengan bijak
Karena fungsi bersifat stateless, lingkungan eksekusi biasanya diinisialisasi sejak awal (selama periode yang disebut cold start). Saat terjadi cold start, konteks global fungsi akan dievaluasi.
Jika fungsi Anda mengimpor modul, waktu pemuatan untuk modul tersebut dapat meningkatkan latensi pemanggilan selama cold start. Anda dapat mengurangi latensi ini dan waktu yang diperlukan untuk men-deploy fungsi. Caranya, dengan memuat dependensi secara benar dan tidak memuat dependensi yang tidak digunakan fungsi Anda.
Menggunakan variabel global untuk menggunakan kembali objek dalam pemanggilan selanjutnya
Tidak ada jaminan bahwa status fungsi akan dipertahankan untuk pemanggilan selanjutnya. Namun, Cloud Functions sering mendaur ulang lingkungan eksekusi dari pemanggilan sebelumnya. Jika Anda mendeklarasikan sebuah variabel dalam cakupan global, nilainya dapat digunakan kembali dalam pemanggilan selanjutnya tanpa harus dikomputasi ulang.
Dengan begitu, Anda dapat melakukan caching untuk objek yang mungkin memakan biaya tinggi jika harus dibuat ulang di setiap pemanggilan fungsi. Pemindahan objek semacam ini dari isi fungsi ke cakupan global dapat menghasilkan peningkatan performa secara signifikan. Contoh berikut membuat objek berat hanya satu kali per instance fungsi, dan membagikannya ke semua pemanggilan fungsi yang mencapai instance tersebut:
Node.js
console.log('Global scope'); const perInstance = heavyComputation(); const functions = require('firebase-functions'); exports.function = functions.https.onRequest((req, res) => { console.log('Function invocation'); const perFunction = lightweightComputation(); res.send(`Per instance: ${perInstance}, per function: ${perFunction}`); });
Python
import time from firebase_functions import https_fn # Placeholder def heavy_computation(): return time.time() # Placeholder def light_computation(): return time.time() # Global (instance-wide) scope # This computation runs at instance cold-start instance_var = heavy_computation() @https_fn.on_request() def scope_demo(request): # Per-function scope # This computation runs every time this function is called function_var = light_computation() return https_fn.Response(f"Instance: {instance_var}; function: {function_var}")
Fungsi HTTP ini mengambil objek permintaan (flask.Request
), dan menampilkan teks respons, atau kumpulan nilai apa pun yang dapat diubah menjadi objek Response
menggunakan make_response
.
Sangatlah penting untuk menyimpan koneksi jaringan, referensi library, dan objek klien API ke dalam cache pada cakupan global. Untuk mendapatkan contoh, baca bagian Mengoptimalkan Jaringan.
Menginisialisasi variabel global berdasarkan permintaan
Jika Anda menginisialisasi variabel dalam cakupan global, kode inisialisasi akan selalu dijalankan melalui pemanggilan cold start, sehingga latensi fungsi Anda meningkat.
Dalam kasus tertentu, hal ini menyebabkan waktu tunggu yang terputus-putus pada layanan yang sedang dipanggil jika variabel tersebut tidak ditangani dengan benar dalam blok try
/catch
. Jika beberapa objek tidak digunakan di semua jalur kode, sebaiknya lakukan inisialisasi berdasarkan permintaan:
Node.js
const functions = require('firebase-functions'); let myCostlyVariable; exports.function = functions.https.onRequest((req, res) => { doUsualWork(); if(unlikelyCondition()){ myCostlyVariable = myCostlyVariable || buildCostlyVariable(); } res.status(200).send('OK'); });
Python
from firebase_functions import https_fn # Always initialized (at cold-start) non_lazy_global = file_wide_computation() # Declared at cold-start, but only initialized if/when the function executes lazy_global = None @https_fn.on_request() def lazy_globals(request): global lazy_global, non_lazy_global # This value is initialized only if (and when) the function is called if not lazy_global: lazy_global = function_specific_computation() return https_fn.Response(f"Lazy: {lazy_global}, non-lazy: {non_lazy_global}.")
Fungsi HTTP ini menggunakan global yang diinisialisasi secara lambat. Fungsi ini mengambil objek permintaan (flask.Request
), dan menampilkan teks respons, atau kumpulan nilai apa pun yang dapat diubah menjadi objek Response
menggunakan make_response
.
Hal ini sangat penting jika Anda menetapkan beberapa fungsi dalam satu file, dan fungsi yang berbeda menggunakan variabel yang berbeda. Jika tidak menggunakan inisialisasi berdasarkan permintaan, Anda dapat menyia-nyiakan resource pada variabel yang telah diinisialisasi tapi tidak pernah digunakan.
Mengurangi cold start dengan menetapkan jumlah minimum instance
Secara default, Cloud Functions menskalakan jumlah instance berdasarkan jumlah permintaan yang masuk. Anda dapat mengubah perilaku default ini dengan menetapkan jumlah minimum instance yang harus selalu disiapkan oleh Cloud Functions untuk menyalurkan permintaan. Menetapkan jumlah minimum instance akan mengurangi cold start pada aplikasi Anda. Sebaiknya tetapkan jumlah minimum instance jika aplikasi Anda sensitif terhadap latensi.
Lihat Mengontrol perilaku penskalaan untuk informasi selengkapnya tentang opsi runtime ini.Referensi lainnya
Cari tahu selengkapnya tentang pengoptimalan performa di video "Google Cloud Performance Atlas" Cloud Functions Cold Boot Time.