Bu belgede, Cloud Functions'ü tasarlama, uygulama, test etme ve dağıtmayla ilgili en iyi uygulamalar açıklanmaktadır.
Doğruluk
Bu bölümde, Cloud Functions'ü tasarlama ve uygulamayla ilgili genel en iyi uygulamalar açıklanmaktadır.
Tekil fonksiyonlar yazma
İşlevleriniz birden çok kez çağrılsa bile aynı sonucu vermelidir. Bu sayede, önceki çağrı kodunuzun ortasında başarısız olursa çağrıyı yeniden deneyebilirsiniz. Daha fazla bilgi için etkinlik odaklı işlevleri yeniden deneme konusuna bakın.
Arka planda işlem başlatmayın
Arka plan etkinliği, işleviniz sona erdikten sonra gerçekleşen her şeydir.
Bir işlev çağrısı, işlev döndürdüğünde veya başka bir şekilde tamamlandığını belirttiğinde (ör. Node.js etkinlik odaklı işlevlerinde callback
bağımsız değişkeni çağrıldığında) sona erer. Sorunsuz sonlandırmadan sonra çalıştırılan kodlar CPU'ya erişemez ve herhangi bir ilerleme kaydedemez.
Ayrıca, aynı ortamda sonraki bir çağrı yürütüldüğünde arka plan etkinliğiniz devam ederek yeni çağrıyı engeller. Bu durum, beklenmedik davranışlara ve teşhis edilmesi zor hatalara neden olabilir. Bir işlev sona erdikten sonra ağa erişmek genellikle bağlantıların sıfırlanmasına neden olur (ECONNRESET
hata kodu).
Arka plan etkinliği, genellikle bağımsız çağrıların günlüklerinde, çağrının sona erdiğini belirten satırdan sonra günlüğe kaydedilen her şey bulunarak tespit edilebilir. Arka plan etkinliği, özellikle geri çağırma veya zamanlayıcı gibi eşzamansız işlemler mevcut olduğunda bazen kodun daha derinlerine gömülebilir. İşlevi sonlandırmadan önce tüm zaman uyumsuz işlemlerin tamamlandığından emin olmak için kodunuzu inceleyin.
Geçici dosyaları her zaman sil
Geçici dizindeki yerel disk depolama alanı, bellek içi bir dosya sistemidir. Yazdığınız dosyalar, işlevinizin kullanabileceği belleği tüketir ve bazen çağrılar arasında kalır. Bu dosyaları açıkça silmemek, zaman içinde bellek yetersizliği hatasına ve ardından soğuk başlatmaya neden olabilir.
Google Cloud Console'daki işlev listesinden işlevi seçip Bellek kullanımı grafiğini belirleyerek tek bir işlevin kullandığı belleği görebilirsiniz.
Uzun süreli depolamaya erişmeniz gerekiyorsa Cloud RunCloud Storage veya NFS birimleriyle birim bağlama işlemlerini kullanabilirsiniz.
Ardışık düzen kullanarak daha büyük dosyaları işlerken bellek gereksinimlerini azaltabilirsiniz. Örneğin, bir okuma akışı oluşturarak, bu akışı akış tabanlı bir işleme geçirerek ve çıkış akışını doğrudan Cloud Storage'a yazarak Cloud Storage'da bir dosyayı işleyebilirsiniz.
Functions Framework
Aynı bağımlılıkların tüm ortamlarda tutarlı bir şekilde yüklenmesini sağlamak için Functions Framework kitaplığını paket yöneticinize eklemenizi ve bağımlılığı Functions Framework'un belirli bir sürümüne sabitlemenizi öneririz.
Bunu yapmak için tercih ettiğiniz sürümü ilgili kilit dosyasına ekleyin (örneğin, Node.js için package-lock.json
veya Python için requirements.txt
).
Functions Framework, bağımlılık olarak açıkça listelenmemişse mevcut en son sürüm kullanılarak derleme işlemi sırasında otomatik olarak eklenir.
Araçlar
Bu bölümde, Cloud Functions'ü uygulamak, test etmek ve bu araçla etkileşime geçmek için araçları nasıl kullanacağınızla ilgili yönergeler verilmektedir.
Yerel geliştirme
İşlev dağıtımı biraz zaman aldığından işlevinizin kodunu yerel olarak test etmek genellikle daha hızlıdır.
Firebase geliştiricileri Firebase CLI Cloud Functions Emulator'ı kullanabilir.E-posta göndermek için SendGrid'i kullanma
Cloud Functions, 25 numaralı bağlantı noktasında giden bağlantılara izin vermez. Bu nedenle, SMTP sunucusuyla güvenli olmayan bağlantılar kuramazsınız. E-posta göndermenin önerilen yolu, SendGrid gibi bir üçüncü taraf hizmeti kullanmaktır. E-posta göndermeyle ilgili diğer seçenekleri Google Compute Engine'e yönelik Bir Birimden E-posta Gönderme eğitiminde bulabilirsiniz.
Performans
Bu bölümde, performansı optimize etmeye yönelik en iyi uygulamalar açıklanmaktadır.
Düşük eşzamanlılıktan kaçının
Sıfırdan başlatmalar pahalı olduğundan, ani artış sırasında yakın zamanda başlatılan örnekleri yeniden kullanabilmek, yükü yönetmek için mükemmel bir optimizasyondur. Eşzamanlılığı sınırlamak, mevcut örneklerden nasıl yararlanılabileceğini sınırlandırır ve bu nedenle daha fazla soğuk başlatmaya neden olur.
Eşzamanlılığı artırmak, örnek başına birden fazla isteği ertelemeye yardımcı olarak yük artışlarının daha kolay ele alınmasını sağlar.Bağımlılıkları akıllıca kullanın
İşlevler durum bilgisi içermediğinden yürütme ortamı genellikle sıfırdan başlatılır (soğuk başlatma olarak bilinen işlem sırasında). Sıfırdan başlatma işlemi gerçekleştiğinde işlevin genel bağlamı değerlendirilir.
İşlevleriniz modül içe aktarıyorsa bu modüllerin yükleme süresi, sıfırdan başlatma sırasındaki çağrı gecikmesine eklenebilir. Bağımlılıkları doğru şekilde yükleyerek ve işlevinizin kullanmadığı bağımlılıkları yüklemeyerek bu gecikmeyi ve işlevinizi dağıtmak için gereken süreyi azaltabilirsiniz.
Nesneleri gelecekteki çağrılarda yeniden kullanmak için genel değişkenleri kullanma
Bir işlevin durumunun gelecekteki çağrılar için korunacağı garanti edilmez. Ancak Cloud Functions genellikle önceki bir çağrının yürütme ortamını geri dönüştürür. Bir değişkeni global kapsamda tanımlarsanız değeri, yeniden hesaplanmadan sonraki çağrılarda yeniden kullanılabilir.
Bu sayede, her işlev çağrısında yeniden oluşturulması pahalı olabilecek nesneleri önbelleğe alabilirsiniz. Bu tür nesneleri işlev gövdesinden genel kapsama taşımak önemli performans iyileştirmelerine neden olabilir. Aşağıdaki örnekte, ağır bir nesne yalnızca işlev örneği başına bir kez oluşturulur ve belirli bir örneğe ulaşan tüm işlev çağrılarında paylaşılır:
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}")
Bu HTTP işlevi bir istek nesnesi (flask.Request
) alır ve yanıt metnini veya make_response
kullanılarak Response
nesnesine dönüştürülebilecek herhangi bir değer grubunu döndürür.
Özellikle ağ bağlantılarını, kitaplık referanslarını ve API istemci nesnelerini global kapsamda önbelleğe almak önemlidir. Örnekler için Ağ bağlantısını optimize etme başlıklı makaleyi inceleyin.
Minimum örnek sayısı belirleyerek baştan başlatma işlemlerini azaltma
Cloud Functions, varsayılan olarak örnek sayısını gelen istek sayısına göre ölçeklendirir. Cloud Functions'ın istek sunmak için hazır tutması gereken minimum sayıda örnek belirleyerek bu varsayılan davranışı değiştirebilirsiniz. Minimum örnek sayısı ayarlamak, uygulamanızın baştan başlatılma sayısını azaltır. Uygulamanız gecikmeye duyarlıysa minimum sayıda örnek ayarlamanızı ve yükleme sırasında başlatmayı tamamlamanızı öneririz.
Bu çalışma zamanı seçenekleri hakkında daha fazla bilgi için Ölçeklendirme davranışını kontrol etme başlıklı makaleyi inceleyin.Baştan başlatma ve başlatma hakkında notlar
Genel ilk kullanıma hazırlama işlemi, yükleme sırasında gerçekleşir. Aksi takdirde, ilk isteğinin başlatma işlemini tamamlaması ve modülleri yüklemesi gerekir. Bu da daha yüksek gecikmeye neden olur.
Ancak genel ilklendirme, sıfırdan başlatma üzerinde de bir etkiye sahiptir. Bu etkiyi en aza indirmek için ilk isteğinin gecikmesini mümkün olduğunca düşük tutmak amacıyla yalnızca ilk istek için gerekenleri başlatın.
Bu, özellikle gecikme süresine duyarlı bir işlev için minimum örneği yukarıda açıklandığı gibi yapılandırdıysanız önemlidir. Bu senaryoda, ilklendirmenin yükleme sırasında tamamlanması ve faydalı verilerin önbelleğe alınması, ilk isteğin bunu yapması gerekmediğinden ve düşük gecikmeli olarak sunulduğundan emin olur.
Değişkenleri genel kapsamda başlatırsanız dile bağlı olarak uzun başlatma süreleri iki davranışa neden olabilir: - Bazı dil ve ayarsız kitaplık kombinasyonlarında işlev çerçevesi ayarsız olarak çalışabilir ve hemen dönebilir. Bu da kodun arka planda çalışmaya devam etmesine neden olur. Bu durum, CPU'ya erişememe gibi sorunlara yol açabilir. Bunu önlemek için aşağıda açıklandığı şekilde modülün başlatılmasını engellemeniz gerekir. Bu, ilk kullanıma hazırlama işlemi tamamlanana kadar isteklerin yayınlanmamasını da sağlar. - Öte yandan, başlatma işlemi eşzamanlıysa uzun başlatma süresi daha uzun soğuk başlatmalara neden olur. Bu durum, özellikle yük artışları sırasında düşük eşzamanlılık işlevlerinde sorun oluşturabilir.
Asynchronize bir node.js kitaplığını ısıtmaya yönelik örnek
Firestore ile Node.js, asynkron node.js kitaplığına örnektir. min_instances özelliğinden yararlanmak için aşağıdaki kod, yükleme ve başlatma işlemlerini yükleme sırasında tamamlar ve modülün yüklenmesini engeller.
TLA kullanılıyorsa ES6 gereklidir. Bunun için node.js kodu için .mjs
uzantısı kullanılır veya package.json dosyasına type: module
eklenir.
{ "main": "main.js", "type": "module", "dependencies": { "@google-cloud/firestore": "^7.10.0", "@google-cloud/functions-framework": "^3.4.5" } }
Node.js
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. });
Global başlatma örnekleri
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}.")
Bu HTTP işlevi, tembel başlatılmış genel değişkenler kullanır. Bir istek nesnesi (flask.Request
) alır ve yanıt metnini veya make_response
kullanılarak Response
nesnesine dönüştürülebilecek herhangi bir değer kümesini döndürür.
Bu, özellikle tek bir dosyada birden fazla işlev tanımlarsanız ve farklı işlevler farklı değişkenler kullanıyorsa önemlidir. Tembel başlatma özelliğini kullanmazsanız, başlatılan ancak hiç kullanılmayan değişkenler için kaynak israf edebilirsiniz.
Ek kaynaklar
Performansı optimize etme hakkında daha fazla bilgi edinmek için "Google Cloud Performance Atlas" videosundaki Cloud Functions Soğuk Başlatma Süresi bölümünü inceleyin.