Zrozumienie technik obniżania kosztów AWS Lambda w aplikacjach bezserwerowych

17 maja 2023

Zrozumienie technik obniżania kosztów AWS Lambda w aplikacjach bezserwerowych

Aplikacje bezserwerowe mogą obniżyć całkowity koszt posiadania (TCO) w porównaniu z modelem wykonywania w chmurze opartym na serwerze, ponieważ skutecznie przenosi obowiązki operacyjne, takie jak zarządzanie serwerami, na dostawcę chmury. Badania firmy Deloitte dotyczące bezserwerowego całkowitego kosztu posiadania, przeprowadzone z klientami z listy Fortune 100 z różnych branż, pokazują, że aplikacje bezserwerowe mogą oferować do 57% oszczędności kosztów w porównaniu z rozwiązaniami opartymi na serwerach.

Aplikacje bezserwerowe mogą oferować niższe koszty w:

  • Początkowym rozwoju: bezserwerowy umożliwia konstruktorom większą elastyczność, szybsze dostarczanie funkcji i skupienie się na zróżnicowanej logice biznesowej.
  • Bieżąca konserwacja i infrastruktura: Bezserwerowe przeniesienie ciężaru operacyjnego na AWS. Bieżące prace konserwacyjne, w tym instalowanie poprawek i aktualizacje systemu operacyjnego.

Ten artykuł koncentruje się na dostępnych opcjach zmniejszenia bezpośrednich kosztów AWS podczas tworzenia aplikacji bezserwerowych. AWS Lambda jest często warstwą obliczeniową w tych obciążeniach i może stanowić znaczącą część całkowitego kosztu.

Aby pomóc zoptymalizować koszty związane z Lambdą, w tym artykule omówiono niektóre z najczęściej stosowanych technik optymalizacji kosztów, z naciskiem na zmiany konfiguracji zamiast aktualizacji kodu. Ten artykuł jest przeznaczony dla architektów i programistów, którzy dopiero zaczynają budować bez użycia serwera.

Tworzenie bezserwerowe ułatwia zarówno eksperymentowanie, jak i iteracyjne ulepszanie. Wszystkie opisane tutaj techniki można zastosować przed opracowaniem aplikacji lub po wdrożeniu aplikacji w środowisku produkcyjnym. Techniki są z grubsza według możliwości zastosowania: pierwsza może dotyczyć dowolnego obciążenia pracą; ostatnia dotyczy mniejszej liczby obciążeń.

Odpowiednie dopasowanie funkcji Lambda

Lambda korzysta z modelu kosztów typu pay-per-use, który opiera się na trzech metrykach:

  • Konfiguracja pamięci: przydzielona pamięć od 128 MB do 10 240 MB. Procesor i inne zasoby dostępne dla funkcji są przydzielane proporcjonalnie do pamięci.
  • Czas trwania funkcji: czas działania funkcji, mierzony w milisekundach.
  • Liczba wywołań: liczba uruchomień funkcji.

Nadmierna alokacja pamięci jest jednym z głównych czynników wzrostu kosztów Lambda. Jest to szczególnie dotkliwe wśród konstruktorów, którzy nie znają Lambdy, którzy są przyzwyczajeni do udostępniania hostów uruchamiających wiele procesów. Lambda skaluje się w taki sposób, że każde środowisko wykonawcze funkcji obsługuje tylko jedno żądanie na raz. Każde środowisko wykonawcze ma dostęp do stałych zasobów (pamięć, procesor, pamięć masowa) w celu zakończenia pracy nad żądaniem.

Dzięki odpowiedniej konfiguracji pamięci funkcja ma zasoby do wykonania swojej pracy, a Ty płacisz tylko za potrzebne zasoby. Chociaż masz również bezpośrednią kontrolę nad czasem trwania funkcji, jest to mniej efektywna optymalizacja kosztów do wdrożenia. Koszty inżynieryjne związane z uzyskaniem kilku milisekund oszczędności mogą przeważyć nad oszczędnościami. W zależności od obciążenia liczba wywołań funkcji może być poza twoją kontrolą. W następnej sekcji omówiono technikę zmniejszania liczby wywołań dla niektórych typów obciążeń.

Dostęp do konfiguracji pamięci można uzyskać za pośrednictwem konsoli zarządzania AWS lub ulubionej infrastruktury jako kodu (IaC). Ustawienie konfiguracji pamięci definiuje przydzieloną pamięć, a nie pamięć używaną przez twoją funkcję. Dopasowanie rozmiaru pamięci to dostosowanie, które może obniżyć koszt (lub zwiększyć wydajność) funkcji. Jednak zmniejszenie pamięci funkcji nie zawsze może skutkować oszczędnościami. Zmniejszenie pamięci funkcji oznacza zmniejszenie dostępnego procesora dla funkcji Lambda, co może wydłużyć czas trwania funkcji, skutkując albo brakiem oszczędności, albo wyższymi kosztami. Ważne jest, aby określić optymalną konfigurację pamięci w celu obniżenia kosztów przy jednoczesnym zachowaniu wydajności.

AWS oferuje dwa podejścia do właściwej alokacji pamięci: AWS Lambda Power Tuning i AWS Compute Optimizer.

AWS Lambda Power Tuning to narzędzie typu open source, którego można użyć do empirycznego znalezienia optymalnej konfiguracji pamięci dla Twojej funkcji, porównując koszt z czasem wykonania. Narzędzie uruchamia wiele współbieżnych wersji Twojej funkcji z fałszywymi danymi wejściowymi przy różnych alokacjach pamięci. Rezultatem jest wykres, który może pomóc Ci znaleźć „najlepszy punkt” między kosztem a czasem trwania/wydajnością. W zależności od obciążenia pracą możesz nadać priorytet jednemu z nich. AWS Lambda Power Tuning to dobry wybór dla nowych funkcji, który może pomóc w wyborze między dwiema architekturami zestawu instrukcji oferowanymi przez Lambdę.

Zrozumienie technik obnizania kosztow AWS Lambda w aplikacjach bezserwerowych

AWS Compute Optimizer wykorzystuje uczenie maszynowe do rekomendowania optymalnej konfiguracji pamięci na podstawie danych historycznych. Compute Optimizer wymaga, aby funkcja była wywoływana co najmniej 50 razy w ciągu ostatnich 14 dni, aby przedstawić rekomendację na podstawie wcześniejszego wykorzystania, więc jest najbardziej efektywna, gdy funkcja jest w fazie produkcyjnej.

Zarówno Lambda Power Tuning, jak i Compute Optimizer pomagają uzyskać alokację pamięci odpowiedniej wielkości dla Twojej funkcji. Użyj tej wartości, aby zaktualizować konfigurację swojej funkcji za pomocą konsoli zarządzania AWS lub IaC.

Ten artykuł zawiera przykładowy kod AWS Serverless Application Model (AWS SAM), aby zademonstrować, jak wdrożyć optymalizacje. Możesz także użyć AWS Cloud Development Kit (AWS CDK), Terraform, Serverless Framework i innych narzędzi IaC, aby zaimplementować te same zmiany.

YAML

MyFunction:
  Type: AWS::Serverless::Function
  Properties:
    Runtime: nodejs18.x
    Handler: app.handler
    MemorySize: 1024   # Set memory configuration to optimize for cost or performance

 

Ustawianie realistycznego limitu czasu funkcji

Funkcje Lambda są skonfigurowane z maksymalnym czasem, w którym każde wywołanie może działać, do 15 minut. Ustawienie odpowiedniego limitu czasu może być korzystne w ograniczaniu kosztów aplikacji opartej na Lambdzie. Nieobsługiwane wyjątki, akcje blokujące (na przykład otwieranie połączenia sieciowego), powolne zależności i inne warunki mogą prowadzić do dłużej działających funkcji lub funkcji, które działają do skonfigurowanego limitu czasu. Właściwe limity czasu są najlepszą ochroną zarówno przed powolnym, jak i błędnym kodem. W pewnym momencie praca wykonywana przez funkcję i koszt na milisekundę tej pracy są marnowane.

Autorzy zalecają ustawienie limitu czasu na mniej niż 29 sekund dla wszystkich wywołań synchronicznych lub tych, w których obiekt wywołujący czeka na odpowiedź. Dłuższe limity czasu są odpowiednie dla wywołań asynchronicznych, ale limity czasu dłuższe niż 1 minuta należy traktować jako wyjątek, który wymaga przeglądu i przetestowania.

 

Użycie Graviton

Lambda oferuje dwie architektury zestawów instrukcji w większości regionów AWS: x86 i arm64.

Wybierając Graviton możesz zaoszczędzić pieniądze na dwa sposoby. Po pierwsze, Twoje funkcje mogą działać wydajniej dzięki architekturze Graviton2. Po drugie, możesz zapłacić mniej za czas ich działania. Funkcje Lambda obsługiwane przez Graviton2 zostały zaprojektowane tak, aby zapewnić do 19 procent lepszą wydajność przy 20 procent niższych kosztach. Rozważ rozpoczęcie od Graviton podczas tworzenia nowych funkcji Lambda, szczególnie tych, które nie wymagają natywnie skompilowanych plików binarnych.

Jeśli twoja funkcja opiera się na natywnych skompilowanych plikach binarnych lub jest spakowana jako obraz kontenera, musisz dokonać przebudowania, aby przejść między arm64 i x86. Warstwy Lambda mogą również zawierać zależności ukierunkowane na jedną lub drugą architekturę. Autorzy zachęcają do przejrzenia zależności i przetestowania funkcji przed zmianą architektury. Narzędzie AWS Lambda Power Tuning umożliwia również porównanie ceny i wydajności arm64 i x86 przy różnych ustawieniach pamięci.

Możesz zmodyfikować konfigurację architektury swojej funkcji w konsoli lub wybranym IaC. Na przykład w AWS SAM:

YAML

MyFunction:
  Type: AWS::Serverless::Function
  Properties:
    Architectures:
      - arm64  # Set architecture to use Graviton2
    Runtime: nodejs18.x
    Handler: app.handler

Filtrowanie nadchodzących wydarzeń

Lambda jest zintegrowana z ponad 200 źródłami zdarzeń, w tym Amazon SQS, Amazon Kinesis Data Streams, Amazon DynamoDB Streaming, Amazon Managed Streaming for Apache Kafka i Amazon MQ. Usługa Lambda integruje się z tymi źródłami zdarzeń w celu pobierania komunikatów i wywoływania funkcji w razie potrzeby w celu przetworzenia tych komunikatów.

Podczas pracy z jednym z tych źródeł zdarzeń konstruktorzy mogą konfigurować filtry w celu ograniczenia zdarzeń wysyłanych do Twojej funkcji. Ta technika może znacznie zmniejszyć liczbę wywołań funkcji w zależności od liczby zdarzeń i specyfiki filtrów. Gdy nie jest używane filtrowanie zdarzeń, należy wywołać funkcję, aby najpierw określić, czy zdarzenie powinno zostać przetworzone przed wykonaniem rzeczywistej pracy. Filtrowanie zdarzeń eliminuje potrzebę przeprowadzania tej kontroli z góry, jednocześnie zmniejszając liczbę wywołań.

Na przykład możesz chcieć, aby funkcja była uruchamiana tylko wtedy, gdy w wiadomości w strumieniu danych Kinesis zostaną znalezione zamówienia o wartości przekraczającej 200 USD. Możesz skonfigurować wzorzec filtrowania zdarzeń za pomocą konsoli lub IaC w sposób podobny do konfiguracji pamięci.

Aby zaimplementować filtr strumienia Kinesis za pomocą AWS SAM:

YAML

MyFunction:
  Type: AWS::Serverless::Function
  Properties:
    Runtime: nodejs18.x
    Handler: app.handler
    Events:
      Type: Kinesis
      Properties:
        StartingPosition: LATEST
        Stream: "arn:aws:kinesis:us-east-1:0123456789012:stream/orders"
        FilterCriteria:
          Filters:
            - Pattern: '{ "data" : { "order" : { "value" : [{ "numeric": [">", 200] }] } } }'

Jeśli zdarzenie spełnia jeden z filtrów zdarzeń powiązanych ze źródłem zdarzenia, Lambda wysyła zdarzenie do Twojej funkcji w celu przetworzenia. W przeciwnym razie zdarzenie jest odrzucane jako pomyślnie przetworzone bez wywoływania funkcji.

Jeśli budujesz lub uruchamiasz funkcję Lambda, która jest wywoływana przez jedno z wcześniej wspomnianych źródeł zdarzeń, zaleca się przejrzenie dostępnych opcji filtrowania. Ta technika nie wymaga żadnych zmian w kodzie funkcji Lambda – nawet jeśli funkcja przeprowadza kontrolę przetwarzania wstępnego, kontrola ta nadal kończy się pomyślnie z zaimplementowanym filtrowaniem.

Aby dowiedzieć się więcej na ten temat, przeczytaj: Filtering event sources for AWS Lambda functions.

Unikanie rekurencji

Być może znasz koncepcję programowania funkcji rekurencyjnej lub funkcji/procedury, która wywołuje samą siebie. Chociaż jest to rzadkie, klienci czasami nieumyślnie budują rekursję w swojej architekturze, więc funkcja Lambda ciągle wywołuje samą siebie.

Najpopularniejszy wzorzec rekurencyjny występuje między Lambda a Amazon S3. Akcje w zasobniku S3 mogą wyzwalać funkcję Lambda, a rekurencja może wystąpić, gdy ta funkcja Lambda zapisuje z powrotem do tego samego zasobnika.

Warto rozważyć przypadek użycia, w którym funkcja Lambda jest używana do generowania miniatur obrazów przesłanych przez użytkowników. Konfigurujesz zasobnik tak, aby uruchamiał funkcję generowania miniatur po umieszczeniu nowego obiektu w zasobniku. Co się stanie, jeśli funkcja Lambda zapisze miniaturę do tego samego zasobnika? Proces rozpoczyna się od nowa, a następnie funkcja Lambda działa na samym obrazie miniatury. Jest to rekurencja i może prowadzić do warunku nieskończonej pętli.

Chociaż istnieje wiele sposobów zapobiegania temu problemowi, najlepszą praktyką jest użycie drugiego zasobnika S3 do przechowywania miniatur. Takie podejście minimalizuje zmiany w architekturze, ponieważ nie trzeba zmieniać ustawień powiadomień ani podstawowego zasobnika S3. Aby dowiedzieć się więcej o innych podejściach, przeczytaj artykuł Avoiding recursive invocation with Amazon S3 and AWS Lambda.

Jeśli napotkasz rekurencję w swojej architekturze, ustaw współbieżność zarezerwowaną Lambda na zero, aby zatrzymać działanie funkcji. Odczekaj kilka minut do godzin przed podniesieniem zarezerwowanego limitu współbieżności. Ponieważ zdarzenia S3 są wywołaniami asynchronicznymi z automatycznymi ponownymi próbami, rekurencja może być nadal widoczna do czasu rozwiązania problemu lub wygaśnięcia wszystkich zdarzeń.

Wnioski

Lambda oferuje szereg technik, których możesz użyć, aby zminimalizować koszty infrastruktury, niezależnie od tego, czy dopiero zaczynasz z Lambdą, czy masz już wdrożone liczne funkcje w środowisku produkcyjnym. W połączeniu z niższymi kosztami początkowego rozwoju i bieżącej konserwacji rozwiązanie bezserwerowe może oferować niski całkowity koszt posiadania. Zapoznaj się z tymi technikami i nie tylko dzięki warsztatom optymalizacji bezserwerowej.

Aby dowiedzieć się więcej o architekturach bezserwerowych i znaleźć wzorce wielokrotnego użytku i być na bieżąco, odwiedź Serverless Land.

Źródło: AWS

 

Case Studies
Referencje

Zespół Hostersi błyskawicznie reaguje na nasze potrzeby, jest bardzo elastyczny, a przy tym dostarcza najwyższej klasy rozwiązań technologicznych. Polecam firmę Hostersi jako rzetelnego i profesjonalnego partnera.

Paweł Grzebyk
Marketing & E-commerce Director
W skrócie o nas
Specjalizujemy się w dostarczaniu rozwiązań IT w obszarach projektowania infrastruktury serwerowej, wdrażania chmury obliczeniowej, opieki administracyjnej i bezpieczeństwa danych.