Catch up on highlights from Firebase at Google I/O 2023. Learn more

Porady & Triki

W tym dokumencie opisano sprawdzone metody projektowania, wdrażania, testowania i wdrażania Cloud Functions.

Poprawność

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

Napisz funkcje idempotentne

Twoje funkcje powinny dawać ten sam wynik, nawet jeśli są wywoływane wiele razy. Dzięki temu możesz ponowić wywołanie, jeśli poprzednie wywołanie nie powiedzie się w trakcie wykonywania kodu. Aby uzyskać więcej informacji, zobacz ponawianie prób funkcji sterowanych zdarzeniami .

Nie rozpoczynaj działań w tle

Aktywność w tle to wszystko, co dzieje się po zakończeniu funkcji. Wywołanie funkcji kończy się, gdy funkcja zwróci lub w inny sposób zasygnalizuje zakończenie, na przykład przez wywołanie argumentu callback w funkcjach sterowanych zdarzeniami Node.js. Żaden kod uruchomiony po płynnym zakończeniu nie może uzyskać dostępu do procesora i nie spowoduje żadnego postępu.

Ponadto, gdy kolejne wywołanie jest wykonywane w tym samym środowisku, aktywność w tle jest wznawiana, zakłócając nowe wywołanie. Może to prowadzić do nieoczekiwanego zachowania i błędów trudnych do zdiagnozowania. Dostęp do sieci po zakończeniu funkcji zwykle prowadzi do zresetowania połączeń (kod błędu ECONNRESET ).

Aktywność w tle można często wykryć w dziennikach z poszczególnych wywołań, znajdując wszystko, co jest zarejestrowane po wierszu informującym o zakończeniu wywołania. Działania w tle mogą czasami być ukryte głębiej w kodzie, zwłaszcza gdy obecne są operacje asynchroniczne, takie jak wywołania zwrotne lub czasomierze. Przejrzyj swój kod, aby upewnić się, że wszystkie operacje asynchroniczne zakończą się przed zakończeniem funkcji.

Zawsze usuwaj pliki tymczasowe

Przechowywanie na dysku lokalnym w katalogu tymczasowym to system plików w pamięci. Pliki, które piszesz, zużywają pamięć dostępną dla twojej funkcji i czasami utrzymują się między wywołaniami. Brak jawnego usunięcia tych plików może ostatecznie doprowadzić do błędu braku pamięci i późniejszego zimnego startu.

Możesz zobaczyć ilość pamięci używanej przez pojedynczą funkcję, wybierając ją z listy funkcji w konsoli GCP i wybierając wykres użycia pamięci .

Nie próbuj pisać poza katalogiem tymczasowym i upewnij się, że używasz metod niezależnych od platformy/systemu operacyjnego do konstruowania ścieżek plików.

Możesz zmniejszyć wymagania dotyczące pamięci podczas przetwarzania większych plików przy użyciu potokowania. Na przykład możesz przetworzyć plik w Cloud Storage, tworząc strumień odczytu, przepuszczając go przez proces oparty na strumieniu i zapisując strumień wyjściowy bezpośrednio w Cloud Storage.

Narzędzia

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

Rozwój lokalny

Wdrożenie funkcji zajmuje trochę czasu, więc często szybsze jest przetestowanie kodu funkcji lokalnie.

Deweloperzy Firebase mogą korzystać z emulatora Firebase CLI Cloud Functions Emulator .

Użyj Sendgrid do wysyłania e-maili

Cloud Functions nie zezwala na połączenia wychodzące na porcie 25, więc nie możesz nawiązywać niezabezpieczonych połączeń z serwerem SMTP. Zalecanym sposobem wysyłania wiadomości e-mail jest użycie SendGrid . Inne opcje wysyłania wiadomości e-mail można znaleźć w samouczku Wysyłanie wiadomości e-mail z instancji dla Google Compute Engine.

Wydajność

W tej sekcji opisano najlepsze praktyki dotyczące optymalizacji wydajności.

Mądrze używaj zależności

Ponieważ funkcje są bezstanowe, środowisko wykonawcze jest często inicjowane od podstaw (podczas tak zwanego zimnego startu ). W przypadku wystąpienia zimnego startu oceniany jest kontekst globalny funkcji.

Jeśli Twoje funkcje importują moduły, czas ładowania tych modułów może zwiększyć opóźnienie wywołania podczas zimnego startu. Możesz zmniejszyć to opóźnienie, a także czas potrzebny do wdrożenia funkcji, ładując poprawnie zależności i nie ładując zależności, których funkcja nie używa.

Użyj zmiennych globalnych do ponownego użycia obiektów w przyszłych wywołaniach

Nie ma gwarancji, że stan Funkcji Cloud zostanie zachowany dla przyszłych wywołań. Jednak Cloud Functions często odtwarza ponownie środowisko wykonawcze poprzedniego wywołania. Jeśli zadeklarujesz zmienną w zasięgu globalnym, jej wartość może być ponownie użyta w kolejnych wywołaniach bez konieczności ponownego obliczania.

W ten sposób można buforować obiekty, których odtworzenie przy każdym wywołaniu funkcji może być kosztowne. Przeniesienie takich obiektów z treści funkcji do zasięgu globalnego może spowodować znaczną poprawę wydajności. Poniższy przykład tworzy ciężki obiekt tylko raz na instancję funkcji i udostępnia go wszystkim wywołaniom funkcji docierającym do danej instancji:

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}`);
});

Szczególnie ważne jest buforowanie połączeń sieciowych, odniesień do bibliotek i obiektów klienckich API w zasięgu globalnym. Przykłady można znaleźć w sekcji Optymalizacja sieci .

Wykonaj leniwą inicjalizację zmiennych globalnych

Jeśli zainicjujesz zmienne w zasięgu globalnym, kod inicjujący będzie zawsze wykonywany poprzez wywołanie zimnego startu, co zwiększy opóźnienie twojej funkcji. W niektórych przypadkach powoduje to sporadyczne przekroczenia limitu czasu dla wywoływanych usług, jeśli nie są one odpowiednio obsługiwane w bloku try / catch . Jeśli niektóre obiekty nie są używane we wszystkich ścieżkach kodu, rozważ leniwe zainicjowanie ich na żądanie:

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');
});

Jest to szczególnie ważne, jeśli definiujesz kilka funkcji w jednym pliku, a różne funkcje używają różnych zmiennych. Jeśli nie użyjesz leniwej inicjalizacji, możesz marnować zasoby na zmienne, które są inicjowane, ale nigdy nie są używane.

Zmniejsz liczbę zimnych startów, ustawiając minimalną liczbę wystąpień

Domyślnie Cloud Functions skaluje liczbę instancji na podstawie liczby żądań przychodzących. Możesz zmienić to domyślne zachowanie, ustawiając minimalną liczbę instancji, które Cloud Functions musi utrzymywać w gotowości do obsługi żądań. Ustawienie minimalnej liczby wystąpień ogranicza zimne uruchamianie aplikacji. Zalecamy ustawienie minimalnej liczby wystąpień, jeśli aplikacja jest wrażliwa na opóźnienia.

Zobacz zachowanie skalowania sterowania, aby uzyskać więcej informacji na temat tych opcji środowiska uruchomieniowego.

Dodatkowe zasoby

Dowiedz się więcej o optymalizacji wydajności w filmie „Google Cloud Performance Atlas” Funkcje chmury Czas zimnego rozruchu .