Praktik Terbaik untuk AWS Lambda Container Reuse

Mengoptimalkan Awal yang Hangat Ketika Menghubungkan AWS Lambda ke Layanan Lain

AWS Lambda menyediakan skalabilitas tinggi karena serverless dan stateless, memungkinkan banyak salinan fungsi lambda untuk dihasilkan secara instan (seperti dijelaskan di sini). Namun, ketika menulis kode aplikasi, Anda cenderung ingin mengakses beberapa data yang stateful. Ini berarti menghubungkan ke datastore seperti instance RDS atau S3. Namun, menghubungkan ke layanan lain dari AWS Lambda menambah waktu ke kode fungsi Anda. Mungkin juga ada efek samping dari skalabilitas tinggi seperti mencapai jumlah maksimum koneksi yang diizinkan ke instance RDS. Salah satu opsi untuk mengatasi ini adalah dengan menggunakan kembali wadah di AWS Lambda untuk bertahan koneksi dan mengurangi waktu berjalan lambda.

Ada beberapa diagram yang berguna di sini untuk menjelaskan siklus hidup permintaan lambda.

Berikut ini terjadi selama mulai dingin, ketika fungsi Anda dipanggil untuk pertama kalinya atau setelah periode tidak aktif:

  • Kode dan dependensinya diunduh.
  • Sebuah wadah baru dimulai.
  • Runtime di-bootstrap.

Tindakan terakhir adalah memulai kode Anda, yang terjadi setiap kali fungsi lambda dipanggil. Jika wadah digunakan kembali untuk pemanggilan fungsi lambda berikutnya, kita dapat langsung beralih ke memulai kode. Ini disebut permulaan yang hangat, dan ini adalah langkah yang dapat kami optimalkan saat menghubungkan ke layanan lain dengan mendefinisikan koneksi di luar ruang lingkup metode handler.

Menghubungkan ke Layanan AWS lainnya dari Lambda

Contoh: Hubungkan ke RDS misalnya, ikon AWS bersumber dari sini

Kami memiliki contoh dasar dan umum untuk dijalankan - kami ingin terhubung ke sumber daya wadah untuk mengambil data pengayaan. Dalam contoh ini, muatan JSON hadir dengan ID dan Fungsi Lambda terhubung ke instance RDS yang menjalankan PostgreSQL untuk menemukan nama ID yang sesuai sehingga kami dapat mengembalikan muatan yang diperkaya. Karena fungsi lambda terhubung ke RDS, yang hidup dalam VPC, fungsi lambda sekarang perlu hidup di subnet pribadi juga. Ini menambahkan beberapa langkah ke awal yang dingin - antarmuka jaringan elastis VPC (ENI) harus dilampirkan (seperti yang disebutkan dalam blog Jeremy Daly, ini menambah waktu untuk memulai yang dingin Anda).

Catatan: kita bisa menghindari menggunakan VPC jika kita menggunakan penyimpanan kunci / nilai dengan DynamoDB bukan RDS.

Saya akan membahas dua solusi untuk tugas ini, yang pertama adalah solusi 'naif' saya, sedangkan solusi kedua dioptimalkan untuk waktu mulai hangat dengan menggunakan kembali koneksi untuk doa berikutnya. Kemudian kami akan membandingkan kinerja setiap solusi.

Opsi 1 - Hubungkan ke RDS di dalam Handler

Contoh kode ini menunjukkan bagaimana saya bisa secara naif mendekati tugas ini - koneksi basis data berada dalam metode handler. Ada kueri pemilihan sederhana untuk mengambil nama ID sebelum mengembalikan payload, yang sekarang termasuk namanya.

Mari kita lihat bagaimana opsi ini berkinerja selama tes kecil dengan ledakan 2.000 doa dengan konkurensi 20. Durasi minimum adalah 18 ms dengan rata-rata 51 ms dan maksimum hanya 1 detik (durasi mulai dingin).

Durasi Lambda

Grafik di bawah ini menunjukkan bahwa ada jumlah maksimum delapan koneksi ke database.

Jumlah koneksi ke basis data RDS dalam waktu 5 menit.

Opsi 2 - Gunakan Koneksi Global

Opsi kedua adalah mendefinisikan koneksi sebagai global di luar metode handler. Kemudian di dalam handler, kami menambahkan tanda centang untuk melihat apakah koneksi itu ada, dan hanya menghubungkannya jika tidak. Ini berarti bahwa koneksi hanya dilakukan satu kali per kontainer. Mengatur koneksi dengan cara ini dengan kondisional di tempat berarti bahwa kita tidak perlu membuat koneksi jika tidak diperlukan oleh logika kode.

Kami tidak lagi menutup koneksi ke database, jadi koneksi tetap untuk permohonan fungsi berikutnya. Menggunakan kembali koneksi secara signifikan mengurangi durasi mulai hangat - durasi rata-rata sekitar 3 kali lebih cepat dan minimum adalah 1 ms daripada 18 ms.

Durasi Lambda

Menghubungkan ke instance RDS adalah tugas yang menghabiskan waktu, dan tidak harus terhubung untuk setiap doa bermanfaat untuk kinerja. Saat menyambungkan ke basis data untuk kueri basis data sederhana, kami mencapai jumlah koneksi basis data maksimum 20, yang cocok dengan tingkat konkurensi (kami membuat 20 doa serentak x 100 kali). Ketika ledakan doa berhenti, koneksi secara bertahap menutup.

Sekarang AWS telah meningkatkan jeda durasi lambda menjadi 15 menit, ini berarti koneksi database bisa bertahan lebih lama dan Anda bisa berada dalam bahaya mencapai nomor koneksi max RDS. Koneksi maks default dapat ditimpa dalam pengaturan grup parameter RDS, meskipun meningkatkan jumlah koneksi maksimum dapat menyebabkan masalah dengan alokasi memori. Mesin virtual yang lebih kecil dapat memiliki nilai max_connections default kurang dari 100. Berhati-hatilah dengan batasan-batasan ini, dan hanya tambahkan logika aplikasi untuk terhubung ke database bila diperlukan.

Menggunakan Koneksi Global untuk Tugas Lainnya

Lambda Menghubungkan ke S3

Tugas umum yang mungkin perlu kita lakukan dengan Lambda adalah mengakses data stateful dari S3. Cuplikan kode di bawah ini adalah cetak biru Fungsi Python Lambda yang disediakan AWS - yang dapat Anda navigasikan dengan masuk ke konsol AWS dan mengklik di sini. Anda dapat melihat dalam kode bahwa klien S3 sepenuhnya ditentukan di luar handler ketika wadah diinisialisasi, sedangkan untuk contoh RDS koneksi global ditetapkan di dalam handler. Kedua pendekatan akan mengatur variabel global yang memungkinkan mereka tersedia untuk doa berikutnya.

s3-get-object snipet kode cetak biru lambda https://console.aws.amazon.com/lambda/home?region=us-east-1#/create/new?bp=s3-get-object-python

Variabel Lingkungan Dekripsi

Konsol lambda memberi Anda opsi untuk mengenkripsi variabel lingkungan Anda untuk keamanan tambahan. Cuplikan kode berikut adalah contoh Java yang disediakan AWS dari skrip pembantu untuk mendekripsi variabel lingkungan dari fungsi Lambda. Anda dapat menavigasi ke cuplikan kode dengan mengikuti tutorial ini (khusus langkah 6). Karena DECRYPTED_KEY didefinisikan sebagai kelas global, fungsi dan logika decryptKey () hanya dipanggil sekali per wadah lambda. Oleh karena itu, kita akan melihat peningkatan yang signifikan dalam durasi mulai hangat.

https://console.aws.amazon.com/lambda/home?region=us-east-1#/functions dan https://docs.aws.amazon.com/lambda/latest/dg/tutorial-env_console.html

Menggunakan Variabel Global dalam Solusi FaaS Lain

Pendekatan ini tidak terisolasi untuk AWS Lambda. Metode menggunakan koneksi global dapat diterapkan ke fungsi tanpa server penyedia cloud lainnya juga. Halaman tips dan trik Fungsi Google Cloud memberikan penjelasan yang baik untuk variabel non-malas (ketika variabel selalu diinisialisasi di luar metode handler) versus variabel malas (variabel global hanya diatur bila diperlukan) variabel global.

Praktik Terbaik Lainnya

Berikut adalah beberapa praktik terbaik yang perlu diingat.

Pengujian

Menggunakan FaaS memfasilitasi memiliki arsitektur layanan mikro. Dan memiliki fungsionalitas kecil yang terpisah berjalan seiring dengan pengujian unit yang efektif. Untuk membantu pengujian unit Anda:

  • Ingatlah untuk mengecualikan dependensi tes dari paket lambda.
  • Pisahkan logika dari metode handler, seperti yang Anda lakukan dengan metode utama program.

Ketergantungan dan Ukuran Paket

Mengurangi ukuran paket penyebaran berarti mengunduh kode akan lebih cepat saat inisialisasi dan karenanya akan meningkatkan waktu mulai dingin Anda. Hapus pustaka yang tidak digunakan dan kode mati untuk mengurangi ukuran file ZIP penyebaran. AWS SDK disediakan untuk runtime Python dan JavaScript sehingga tidak perlu untuk memasukkannya dalam paket penerapan Anda.

Jika Node.js adalah runtime Lambda pilihan Anda, Anda bisa menerapkan minifikasi dan uglifikasi untuk mengurangi ukuran kode fungsi Anda dan meminimalkan ukuran paket penempatan Anda. Beberapa tetapi tidak semua aspek minifikasi dan uglifikasi dapat diterapkan ke runtimes lain, misalnya. Anda tidak dapat menghapus spasi dari kode python tetapi Anda dapat menghapus komentar dan mempersingkat nama variabel.

Mengatur Memori

Eksperimen untuk menemukan jumlah memori optimal untuk Fungsi Lambda. Anda membayar alokasi memori, jadi menggandakan memori berarti Anda harus membayar dua kali lipat per milidetik; tetapi menghitung kapasitas meningkat dengan memori yang dialokasikan sehingga berpotensi mengurangi waktu berjalan menjadi kurang dari setengahnya. Sudah ada beberapa alat yang berguna untuk memilih pengaturan memori optimal untuk Anda seperti ini.

Untuk menyimpulkan…

Satu hal yang perlu dipertimbangkan adalah apakah menerapkan metode koneksi ulang diperlukan. Jika fungsi lambda Anda jarang digunakan, seperti sekali sehari, maka Anda tidak akan mendapat manfaat dari mengoptimalkan untuk memulai hangat. Seringkali ada trade-off untuk membuat antara mengoptimalkan kinerja versus keterbacaan kode Anda - istilah "uglification" berbicara untuk dirinya sendiri! Selain itu, menambahkan variabel global ke kode Anda untuk menggunakan kembali koneksi ke layanan lain berpotensi membuat kode Anda lebih sulit dilacak. Ada dua pertanyaan yang muncul:

  • Akankah anggota tim baru memahami kode Anda?
  • Apakah Anda dan tim Anda dapat men-debug kode di masa mendatang?

Tetapi kemungkinan Anda telah memilih Lambda untuk skalanya dan menginginkan kinerja tinggi dan biaya rendah, jadi temukan keseimbangan yang sesuai dengan kebutuhan tim Anda.

Pendapat ini adalah dari penulis. Kecuali disebutkan sebaliknya dalam posting ini, Capital One tidak berafiliasi dengan, juga tidak didukung oleh salah satu perusahaan yang disebutkan. Semua merek dagang dan kekayaan intelektual lain yang digunakan atau ditampilkan adalah kepemilikan masing-masing pemiliknya. Artikel ini adalah © 2019 Capital One.