Tips & Trik
Dokumen ini berisi penjelasan mengenai praktik terbaik untuk mendesain, mengimplementasikan, menguji, dan men-deploy fungsi Cloud Run.
Ketepatan
Bagian ini menjelaskan praktik terbaik umum untuk merancang dan mengimplementasikan fungsi Cloud Run.
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.
Memastikan fungsi HTTP mengirimkan respons HTTP
Jika fungsi Anda dipicu HTTP, jangan lupa untuk mengirim respons HTTP, seperti yang ditunjukkan di bawah ini. Jika tidak dilakukan, fungsi dapat dieksekusi hingga waktu tunggu habis. Jika hal ini terjadi, Anda akan dikenakan biaya untuk seluruh waktu tunggu. Waktu tunggu juga dapat menyebabkan perilaku yang tidak dapat diprediksi atau cold start pada pemanggilan berikutnya, yang mengakibatkan perilaku yang tidak dapat diprediksi atau latensi tambahan.
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.
Jika Anda memerlukan akses ke penyimpanan jangka panjang, pertimbangkan untuk menggunakan pemasangan volume Cloud Run dengan Cloud Storage atau volume NFS.
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
Untuk memastikan dependensi yang sama diinstal secara konsisten di seluruh lingkungan, sebaiknya sertakan library Functions Framework dalam pengelola paket Anda dan sematkan dependensi 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).
Jika tidak dicantumkan secara eksplisit sebagai dependensi, Functions Framework akan otomatis ditambahkan selama proses build menggunakan versi terbaru yang tersedia.
Alat
Bagian ini berisi panduan cara menggunakan alat untuk mengimplementasikan, menguji, dan berinteraksi dengan fungsi Cloud Run.
Pengembangan lokal
Deployment fungsi memerlukan waktu cukup lama. Jadi, sebaiknya lakukan pengujian kode fungsi secara lokal karena durasinya bisa lebih cepat.
Pelaporan error
Dalam bahasa yang menggunakan penanganan pengecualian, jangan menampilkan pengecualian yang tidak tertangkap, karena pengecualian tersebut memaksa cold start pada pemanggilan di berikutnya. Lihat panduan Pelaporan Error untuk mendapatkan informasi tentang cara melaporkan error dengan benar.
Jangan keluar secara manual
Keluar secara manual dapat menyebabkan perilaku yang tidak terduga. Sebagai gantinya, gunakan idiom spesifik bahasa berikut:
Jangan gunakan process.exit()
. Fungsi HTTP harus mengirimkan respons dengan res.status(200).send(message)
, dan fungsi berbasis peristiwa akan keluar setelah fungsi tersebut ditampilkan (baik secara implisit maupun eksplisit).
Jangan gunakan sys.exit()
. Fungsi HTTP harus secara eksplisit menampilkan respons sebagai string, dan fungsi yang dipicu peristiwa akan keluar setelah fungsi tersebut menampilkan nilai (baik secara implisit maupun eksplisit).
Jangan gunakan os.Exit()
. Fungsi HTTP harus secara eksplisit menampilkan respons sebagai string, dan fungsi yang dipicu peristiwa akan keluar setelah fungsi tersebut menampilkan nilai (baik secara implisit maupun eksplisit).
Jangan gunakan System.exit()
. Fungsi HTTP harus mengirimkan respons dengan response.getWriter().write(message)
, dan fungsi berbasis peristiwa akan keluar setelah fungsi tersebut ditampilkan (baik secara implisit maupun eksplisit).
Jangan gunakan System.Environment.Exit()
. Fungsi HTTP harus mengirimkan respons dengan context.Response.WriteAsync(message)
, dan fungsi berbasis peristiwa akan keluar setelah fungsi tersebut ditampilkan (baik secara implisit maupun eksplisit).
Jangan gunakan exit()
atau abort()
. Fungsi HTTP harus secara eksplisit menampilkan respons sebagai string, dan fungsi yang dipicu peristiwa akan keluar setelah fungsi tersebut menampilkan nilai (baik secara implisit maupun eksplisit).
Jangan gunakan exit()
atau die()
. Fungsi HTTP harus secara eksplisit menampilkan respons sebagai string, dan fungsi yang dipicu peristiwa akan keluar setelah fungsi tersebut menampilkan nilai (baik secara implisit maupun eksplisit).
Menggunakan Sendgrid untuk mengirim email
Fungsi Cloud Run 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 layanan pihak ketiga seperti 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.
Menghindari konkurensi rendah
Karena cold start mahal, kemampuan untuk menggunakan kembali instance yang baru dimulai selama lonjakan adalah pengoptimalan yang tepat untuk menangani beban. Pembatasan konkurensi akan membatasi cara memanfaatkan instance yang ada, sehingga menyebabkan lebih banyak cold start.
Meningkatkan konkurensi membantu menunda beberapa permintaan per instance, sehingga membuat lonjakan beban lebih mudah ditangani. Catatan: Fungsi generasi ke-1 memiliki konkurensi yang dibatasi hingga 1. Sebaiknya migrasikan ke fungsi Cloud Run.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 Cloud Run akan dipertahankan untuk pemanggilan selanjutnya. Namun, fungsi Cloud Run 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:
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.
Mengurangi cold start dengan menetapkan jumlah minimum instance
Secara default, fungsi Cloud Run menskalakan jumlah instance berdasarkan jumlah permintaan yang masuk. Anda dapat mengubah perilaku default ini dengan menetapkan jumlah minimum instance yang harus selalu disiapkan oleh fungsi Cloud Run untuk menyalurkan permintaan. Menetapkan jumlah minimum instance akan mengurangi cold start pada aplikasi Anda. Sebaiknya tetapkan jumlah minimum instance, dan selesaikan inisialisasi pada waktu pemuatan, jika aplikasi Anda sensitif terhadap latensi.
Untuk mempelajari cara menetapkan jumlah instance minimum, baca Menggunakan instance minimum.
Catatan tentang cold start dan inisialisasi
Inisialisasi global terjadi pada waktu pemuatan. Tanpa inisialisasi global, permintaan pertama harus menyelesaikan inisialisasi dan memuat modul, sehingga menimbulkan latensi yang lebih tinggi.
Namun, inisialisasi global juga berdampak pada cold start. Untuk meminimalkan dampak ini, lakukan inisialisasi hanya pada hal yang diperlukan untuk permintaan pertama, agar latensi permintaan pertama tetap serendah mungkin.
Hal ini sangat penting jika Anda mengonfigurasi instance minimum seperti yang dijelaskan di atas untuk fungsi yang sensitif terhadap latensi. Dalam skenario tersebut, menyelesaikan inisialisasi pada waktu pemuatan dan meng-cache data yang berguna memastikan bahwa permintaan pertama tidak perlu melakukannya dan disajikan dengan latensi yang rendah.
Jika Anda melakukan inisialisasi variabel dalam cakupan global, bergantung pada bahasa, waktu inisialisasi yang lama dapat menghasilkan dua perilaku: - untuk beberapa kombinasi bahasa dan library asinkron, framework fungsi dapat berjalan secara asinkron dan langsung ditampilkan, sehingga kode terus berjalan di latar belakang, yang dapat menyebabkan masalah seperti tidak dapat mengakses CPU. Untuk menghindari hal ini, Anda harus memblokir inisialisasi modul seperti yang dijelaskan di bawah. Hal ini juga memastikan bahwa permintaan tidak disajikan hingga inisialisasi selesai. - di sisi lain, jika inisialisasi bersifat sinkron, waktu inisialisasi yang lama akan menyebabkan cold start yang lebih lama, yang dapat menjadi masalah, terutama dengan fungsi konkurensi rendah selama lonjakan beban.
Contoh pra-penyiapan library node.js asinkron
Node.js dengan Firestore adalah contoh library node.js asinkron. Untuk memanfaatkan min_instances, kode berikut menyelesaikan pemuatan dan inisialisasi pada waktu pemuatan, yang memblokir pemuatan modul.
TLA digunakan, yang berarti ES6 diperlukan, menggunakan ekstensi .mjs
untuk
kode node.js atau menambahkan type: module
ke file package.json.
{ "main": "main.js", "type": "module", "dependencies": { "@google-cloud/firestore": "^7.10.0", "@google-cloud/functions-framework": "^3.4.5" } }
import Firestore from '@google-cloud/firestore'; import * as functions from '@google-cloud/functions-framework'; const firestore = new Firestore({preferRest: true}); // Pre-warm firestore connection pool, and preload our global config // document in cache. In order to ensure no other request comes in, // block the module loading with a synchronous global request: const config = await firestore.collection('collection').doc('config').get(); functions.http('fetch', (req, res) => { // Do something with config and firestore client, which are now preloaded // and will execute at lower latency. });
Contoh inisialisasi global
Fungsi PHP tidak dapat mempertahankan variabel di antara permintaan. Contoh cakupan di atas menggunakan pemuatan lambat untuk meng-cache nilai variabel global dalam file.
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.
Referensi lainnya
Cari tahu selengkapnya tentang pengoptimalan performa di video "Google Cloud Performance Atlas" Cloud Run functions Cold Boot Time.