Join us in person and online for Firebase Summit on October 18, 2022. Learn how Firebase can help you accelerate app development, release your app with confidence, and scale with ease. Register now

Porady & Triki

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

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 idempotentne funkcje

Twoje funkcje powinny dawać ten sam wynik, nawet jeśli są wywoływane wielokrotnie. Dzięki temu możesz ponowić wywołanie, jeśli poprzednie wywołanie nie powiedzie się w połowie 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 callback argumentu wywołania zwrotnego w funkcjach Node.js sterowanych zdarzeniami. Żaden kod uruchomiony po łagodnym 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 nieoczekiwanych zachowań i błędów, które są trudne 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 poszczególnych wywołań, znajdując wszystko, co jest rejestrowane po wierszu informującym o zakończeniu wywołania. Aktywność w tle może czasami być pochowana głębiej w kodzie, zwłaszcza gdy występują operacje asynchroniczne, takie jak wywołania zwrotne lub czasomierze. Przejrzyj swój kod, aby upewnić się, że wszystkie operacje asynchroniczne kończą się przed zakończeniem funkcji.

Zawsze usuwaj pliki tymczasowe

Lokalna pamięć dyskowa w katalogu tymczasowym to system plików w pamięci. Pliki, które zapisujesz, zużywają pamięć dostępną dla Twojej funkcji i czasami utrzymują się między wywołaniami. Niepowodzenie w jawnym usunięciu tych plików może ostatecznie doprowadzić do błędu braku pamięci i następującego po nim zimnego startu.

Możesz zobaczyć pamięć używaną przez pojedynczą funkcję, wybierając ją na liście funkcji w konsoli GCP i wybierając wykres użycia pamięci .

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

Możesz zmniejszyć wymagania dotyczące pamięci podczas przetwarzania większych plików za pomocą potoku. Na przykład możesz przetworzyć plik w Cloud Storage, tworząc strumień odczytu, przekazują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 korzystania z narzędzi do implementacji, testowania i interakcji z Cloud Functions.

Rozwój lokalny

Wdrażanie funkcji zajmuje trochę czasu, więc często szybciej jest przetestować kod funkcji lokalnie.

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

Użyj Sendgrid do wysyłania e-maili

Cloud Functions nie zezwala na połączenia wychodzące na porcie 25, więc nie można 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 znajdziesz w samouczku Wysyłanie wiadomości e-mail z instancji dla Google Compute Engine.

Wydajność

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

Mądrze korzystaj z zależności

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

Jeśli 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, poprawnie ładując zależności i nie ładując zależności, których nie używa funkcja.

Użyj zmiennych globalnych, aby ponownie użyć obiektów w przyszłych wywołaniach

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

W ten sposób możesz buforować obiekty, których odtworzenie może być kosztowne przy każdym wywołaniu funkcji. Przeniesienie takich obiektów z treści funkcji do zakresu 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 we wszystkich wywołaniach funkcji docierających 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, odwołań do bibliotek i obiektów klientów API w zakresie globalnym. Przykłady można znaleźć w sekcji Optymalizacja sieci .

Wykonaj leniwą inicjalizację zmiennych globalnych

Jeśli zainicjujesz zmienne w zakresie globalnym, kod inicjujący będzie zawsze wykonywany przez wywołanie zimnego startu, zwiększając opóźnienie funkcji. W niektórych przypadkach powoduje to sporadyczne przekroczenie limitu czasu 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ż inicjowanie ich leniwie 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żywasz inicjalizacji z opóźnieniem, 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 przychodzących żądań. 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ń zmniejsza zimny start aplikacji. Zalecamy ustawienie minimalnej liczby wystąpień, jeśli aplikacja jest wrażliwa na opóźnienia.

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

Dodatkowe zasoby

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