Porady i wskazówki

W tym dokumencie opisujemy sprawdzone metody projektowania, wdrażania, testowania i wdrażanie funkcji w Cloud Functions.

Poprawność

W tej sekcji znajdziesz ogólne sprawdzone metody projektowania i wdrażania Cloud Functions.

Zapisz funkcje idempotentne

Funkcje powinny dawać taki sam wynik, nawet jeśli są nazywane wieloma razy. Dzięki temu możesz ponowić wywołanie, jeśli poprzednie wywołanie się nie powiedzie w trakcie przetwarzania kodu. Więcej informacji: ponownego uruchomienia funkcji opartych na zdarzeniach.

Nie uruchamiaj działań w tle

Aktywność w tle to wszystko, co dzieje się po zakończeniu działania funkcji. Wywołanie funkcji kończy się, gdy funkcja zostanie zwrócona lub w inny sposób sygnalizuje ukończenia, np. przez wywołanie argumentu callback w opartym na zdarzeniach środowiskiem Node.js funkcji. Każdy uruchomiony kod po zakończeniu bez utraty danych nie ma dostępu do procesora i nie dokona żadnych postępów.

Ponadto, gdy kolejne wywołanie zostanie wykonane w tym samym środowisku, aktywność w tle zostanie wznowiona, zakłócając działanie nowego wywołania. Może to spowodować może prowadzić do nieoczekiwanego działania i trudnych do zdiagnozowania błędów. Uzyskiwanie dostępu zakończenie działania sieci zazwyczaj prowadzi do zresetowania połączeń. (ECONNRESET kod błędu).

Aktywność w tle można często wykryć w dziennikach z poszczególnych wywołań, znajdując wszystko, co zostanie zarejestrowane po wierszu, które mówi, że wywołanie . Aktywność w tle może czasem leżeć głębiej w kodzie, zwłaszcza w przypadku operacji asynchronicznych, takich jak wywołania zwrotne czy liczniki czasu. Sprawdź swój kod, aby upewnić się, że wszystkie operacje asynchroniczne zostały zakończone, zanim i zakończyć działanie funkcji.

Zawsze usuwaj pliki tymczasowe

Przechowywanie danych na dysku lokalnym w katalogu tymczasowym jest systemem plików w pamięci. Pliki i które możesz zapisać, wykorzystują pamięć dostępną dla funkcji i czasem pozostają między wywołaniami. Jeśli nie usuniesz tych plików, może się zdarzyć doprowadzi do błędu braku pamięci i uruchomienia „na zimno”.

Aby zobaczyć ilość pamięci używanej przez daną funkcję, wybierz ją w listę funkcji w tabeli konsolę GCP i wybierając wykres Wykorzystanie pamięci.

Nie próbuj zapisywać danych poza katalogiem tymczasowym i pamiętaj, aby użyć metody tworzenia ścieżek do plików niezależne od platformy i systemu operacyjnego.

Możesz zmniejszyć wymagania dotyczące pamięci podczas przetwarzania większych plików przy użyciu potoku. Aby na przykład przetworzyć plik w Cloud Storage, utwórz strumień odczytu, przekazywanie go przez proces oparty na strumieniu i zapisanie strumienia wyjściowego, bezpośrednio do Cloud Storage.

Platforma funkcji

Po wdrożeniu funkcji platforma funkcji jest automatycznie dodawana jako w bieżącej wersji. Aby te same zależności są instalowane spójnie w różnych środowiskach, zalecamy możesz przypiąć funkcję do konkretnej wersji platformy Functions.

Aby to zrobić, uwzględnij preferowaną wersję w odpowiednim pliku blokady. (na przykład package-lock.json w przypadku Node.js lub requirements.txt w przypadku Pythona).

Narzędzia

Ta sekcja zawiera wskazówki dotyczące korzystania z narzędzi do wdrażania, testowania i interakcji z funkcjami w Cloud Functions.

Programowanie lokalne

Wdrożenie funkcji zajmuje trochę czasu, więc często szybciej sprawdza się kod Twojej funkcji lokalnie.

Programiści Firebase mogą używać Emulator Cloud Functions interfejsu wiersza poleceń Firebase.

Używaj Sendgrid do wysyłania e-maili

Cloud Functions nie zezwala na połączenia wychodzące przez port 25, więc nie można nawiązywać niezabezpieczone połączenia z serwerem SMTP. Zalecany sposób wysyłania e-maili to SendGrid. Aby zobaczyć inne opcje, do wysyłania e-maili w Wysyłanie e-maila z instancji Google Compute Engine.

Wydajność

W tej sekcji znajdziesz sprawdzone metody optymalizacji skuteczności.

Mądrze korzystaj z zależności

Ponieważ funkcje są bezstanowe, środowisko wykonawcze często jest inicjowane od zera (w trakcie tzw. „zimnego startu”). Gdy występuje uruchomienie „na zimno”, sprawdzany jest globalny kontekst funkcji.

Jeśli Twoje funkcje importują moduły, ich czas wczytywania może zostać wydłużony opóźnienie wywołania podczas uruchamiania „na zimno”. Możesz zmniejszyć to opóźnienie. w czasie potrzebnym na wdrożenie funkcji przez poprawne wczytanie zależności nie wczytuje zależności, których nie używa Twoja funkcja.

Używanie zmiennych globalnych do ponownego używania obiektów w przyszłych wywołaniach

Nie ma gwarancji, że stan funkcji w Cloud Functions zostanie zachowany przez przyszłych wywołań. Jednak w Cloud Functions często następuje recykling wykonania. w środowisku poprzedniego wywołania. Jeśli zadeklarujesz zmienną w zakresie globalnym, jego wartość może być używana w kolejnych wywołaniach bez konieczności obliczone na nowo.

Dzięki temu można buforować obiekty, których odtwarzanie może być drogie na każdym przez wywołanie funkcji. Przeniesienie takich obiektów z treści funkcji do zakresu globalnego może spowodować znaczną poprawę wydajności. Przykład poniżej tworzy ciężki obiekt tylko raz na instancję funkcji i udostępnia go wszystkim wywołania funkcji docierające do danej instancji:

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}")
  

Ta funkcja HTTP pobiera obiekt żądania (flask.Request) i zwraca tekstu odpowiedzi lub dowolnego zbioru wartości, które można przekształcić w Response obiekt używa funkcji make_response.

Szczególnie ważne jest buforowanie połączeń sieciowych, odwołań do bibliotek i obiektów klientów API w zakresie globalnym. Przykłady znajdziesz w artykule Optymalizowanie sieci.

Leniwe inicjowanie zmiennych globalnych

Jeśli zainicjujesz zmienne w zakresie globalnym, kod inicjowania zawsze będzie może być wykonywane przez wywołanie „na zimno”, co zwiększa czas oczekiwania funkcji. W niektórych przypadkach powoduje to sporadyczne przerwy w dostępie do wywoływanych usług. jeśli nie są odpowiednio obsługiwane w bloku try/catch. Jeśli niektóre obiekty nie są używane we wszystkich ścieżkach kodu; rozważ ich leniwe inicjowanie na żądanie:

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}.")
  

Ta funkcja HTTP używa globalnych zainicjowanych leniwie. Pobiera obiekt żądania (flask.Request) i zwraca tekst odpowiedzi lub dowolny zestaw wartości, można przekształcić w obiekt Response za pomocą funkcji make_response.

Jest to szczególnie ważne, jeśli zdefiniujesz kilka funkcji w jednym pliku, a różne funkcje używają różnych zmiennych. Chyba że używasz leniwego możesz tracić zasoby na zmienne, które są zainicjowane, ale nigdy nie użyto.

Ogranicz uruchomienia „na zimno” przez ustawienie minimalnej liczby instancji

Domyślnie Cloud Functions skaluje liczbę instancji na podstawie liczby przychodzących żądań. Możesz zmienić to domyślne działanie, ustawiając minimalna liczba instancji, które Cloud Functions musi utrzymywać w gotowości żądania obsługi. Ustawienie minimalnej liczby instancji ogranicza uruchomienia „na zimno” Twojej aplikacji. Jeśli Twoja uwzględnia czas oczekiwania.

Zobacz Sterowanie skalowaniem .

Dodatkowe materiały

Więcej informacji o optymalizacji wydajności znajdziesz w artykule „Google Cloud Performance” Atlas” film, Czas uruchamiania „na zimno” w Cloud Functions.