Wzorzec nowoczesnej aplikacji internetowej dla platformy .NET

Azure App Service
Azure Front Door
Azure Cache for Redis
.NET

W tym artykule pokazano, jak zaimplementować wzorzec nowoczesnej aplikacji internetowej. Wzorzec nowoczesnej aplikacji internetowej definiuje sposób modernizacji aplikacji internetowych w chmurze i wprowadzenie architektury zorientowanej na usługę. Wzorzec nowoczesnej aplikacji internetowej zawiera normatywne wskazówki dotyczące architektury, kodu i konfiguracji, które są zgodne z zasadami platformy Azure Well-Architected Framework i opiera się na wzorcu niezawodnej aplikacji internetowej.

Dlaczego warto używać wzorca nowoczesnej aplikacji internetowej?

Wzorzec nowoczesnej aplikacji internetowej ułatwia optymalizowanie obszarów wysokiego zapotrzebowania aplikacji internetowej. Oferuje szczegółowe wskazówki dotyczące oddzielenia tych obszarów, co umożliwia niezależne skalowanie na potrzeby optymalizacji kosztów. Takie podejście umożliwia przydzielanie dedykowanych zasobów do krytycznych składników, zwiększając ogólną wydajność. Oddzielenie usług separowalnych może zwiększyć niezawodność, zapobiegając spowolnieniu w jednej części aplikacji, aby wpływać na inne. Oddzielenie umożliwia również niezależne przechowywanie wersji poszczególnych składników aplikacji.

Jak zaimplementować wzorzec nowoczesnej aplikacji internetowej

Ten artykuł zawiera wskazówki dotyczące architektury, kodu i konfiguracji w celu zaimplementowania wzorca nowoczesnej aplikacji internetowej. Skorzystaj z poniższych linków, aby przejść do potrzebnych wskazówek:

  • Wskazówki dotyczące architektury: Dowiedz się, jak modularyzować składniki aplikacji internetowej i wybierać odpowiednie rozwiązania platformy jako usługi (PaaS).
  • Wskazówki dotyczące kodu: Zaimplementuj cztery wzorce projektowe, aby zoptymalizować składniki rozdzielone: rysowanie stranglera, bilansowanie obciążenia oparte na kolejce, konkurujący konsumenci i wzorce monitorowania punktu końcowego kondycji.
  • Wskazówki dotyczące konfiguracji: Konfigurowanie uwierzytelniania, autoryzacji, skalowania automatycznego i konteneryzacji dla składników rozdzielonych.

Napiwek

Logo usługi GitHubIstnieje implementacja referencyjna (przykładowa aplikacja) wzorca nowoczesnej aplikacji internetowej. Reprezentuje stan końcowy implementacji nowoczesnej aplikacji internetowej. Jest to aplikacja internetowa klasy produkcyjnej, która zawiera wszystkie aktualizacje kodu, architektury i konfiguracji omówione w tym artykule. Wdrażanie i używanie implementacji referencyjnej w celu kierowania implementacją wzorca nowoczesnej aplikacji internetowej.

Wskazówki dotyczące architektury

Wzorzec nowoczesnej aplikacji internetowej opiera się na wzorcu niezawodnej aplikacji internetowej. Implementacja wymaga kilku dodatkowych składników architektury. Potrzebujesz kolejki komunikatów, platformy kontenerów, odłączonego magazynu danych usługi i rejestru kontenerów (zobacz rysunek 1).

Diagram przedstawiający architekturę bazową wzorca nowoczesnej aplikacji internetowej.Rysunek 1. Podstawowe elementy architektury wzorca nowoczesnej aplikacji internetowej.

Aby uzyskać wyższy cel poziomu usług (SLO), możesz dodać drugi region do architektury aplikacji internetowej. Drugi region wymaga skonfigurowania modułu równoważenia obciążenia w celu kierowania ruchu do drugiego regionu w celu obsługi konfiguracji aktywne-aktywne lub aktywne-pasywne. Topologia sieci piasty i szprych umożliwia scentralizowanie i współużytkowanie zasobów, takich jak zapora sieciowa. Uzyskaj dostęp do repozytorium kontenerów za pośrednictwem sieci wirtualnej koncentratora. Jeśli masz maszyny wirtualne, dodaj hosta bastionu do sieci wirtualnej koncentratora, aby zarządzać nimi bezpiecznie (zobacz rysunek 2).

Diagram przedstawiający architekturę wzorca nowoczesnej aplikacji internetowej z topologią sieci piasty i szprych.Rysunek 2. Architektura wzorca nowoczesnej aplikacji internetowej z topologią sieci piasty i szprych.

Architektura rozdzielania

Aby zaimplementować wzorzec nowoczesnej aplikacji internetowej, należy rozdzielić istniejącą architekturę aplikacji internetowej. Oddzielenie architektury polega na podzieleniu aplikacji monolitycznej na mniejsze, niezależne usługi, z których każda odpowiada za określoną funkcję lub funkcjonalność. Ten proces obejmuje ocenę bieżącej aplikacji internetowej, zmodyfikowanie architektury i wyodrębnienie kodu aplikacji internetowej na platformę kontenera. Celem jest systematyczne identyfikowanie i wyodrębnianie usług aplikacji, które najbardziej korzystają z oddzielenia. Aby rozdzielić architekturę, wykonaj następujące zalecenia:

  • Identyfikowanie granic usługi. Stosowanie zasad projektowania opartych na domenie w celu identyfikowania powiązanych kontekstów w aplikacji monolitycznej. Każdy ograniczony kontekst reprezentuje granicę logiczną i może być kandydatem do oddzielnej usługi. Usługi, które reprezentują odrębne funkcje biznesowe i mają mniej zależności, są dobrymi kandydatami do oddzielenia.

  • Ocena korzyści z usługi. Skoncentruj się na usługach, które korzystają najbardziej z niezależnego skalowania. Oddzielenie tych usług i konwertowanie zadań przetwarzania z synchronicznych na operacje asynchroniczne umożliwia bardziej wydajne zarządzanie zasobami, obsługuje niezależne wdrożenia i zmniejsza ryzyko wpływu na inne części aplikacji podczas aktualizacji lub zmian. Na przykład możesz oddzielić wyewidencjonowania zamówienia od przetwarzania zamówień.

  • Ocena możliwości technicznych. Sprawdź bieżącą architekturę, aby zidentyfikować ograniczenia techniczne i zależności, które mogą mieć wpływ na proces oddzielenia. Planowanie sposobu zarządzania danymi i udostępniania ich w usługach. Oddzielone usługi powinny zarządzać własnymi danymi i zminimalizować bezpośredni dostęp do bazy danych w granicach usługi.

  • Wdrażanie usług platformy Azure. Wybierz i wdróż usługi platformy Azure potrzebne do obsługi usługi aplikacji internetowej, którą chcesz wyodrębnić. Skorzystaj z poniższej sekcji Wybierz odpowiednie usługi platformy Azure, aby uzyskać wskazówki.

  • Rozdziel usługi aplikacji internetowych. Zdefiniuj jasne interfejsy i interfejsy API dla nowo wyodrębnionych usług aplikacji internetowych w celu interakcji z innymi częściami systemu. Zaprojektuj strategię zarządzania danymi, która umożliwia każdej usłudze zarządzanie własnymi danymi przy jednoczesnym zapewnieniu spójności i integralności. Aby użyć określonych strategii implementacji i wzorców projektowych podczas tego procesu wyodrębniania, zapoznaj się z sekcją Wskazówki dotyczące kodu.

  • Użyj niezależnego magazynu na potrzeby usług rozdzielonych. Każda usługa oddzielona powinna mieć własny izolowany magazyn danych, aby ułatwić niezależne przechowywanie wersji, wdrażanie, skalowalność i utrzymywanie integralności danych. Na przykład implementacja referencyjna oddziela usługę renderowania biletów od internetowego interfejsu API i eliminuje konieczność uzyskania dostępu do bazy danych interfejsu API. Zamiast tego usługa komunikuje adres URL, pod którym obrazy biletów zostały wygenerowane z powrotem do internetowego interfejsu API za pośrednictwem komunikatu usługi Azure Service Bus, a interfejs API utrwala ścieżkę do bazy danych.

  • Zaimplementuj oddzielne potoki wdrażania dla każdej usługi oddzielonej. Oddzielne potoki wdrażania umożliwiają aktualizowanie każdej usługi we własnym tempie. Jeśli różne zespoły lub organizacje w firmie posiadają różne usługi, posiadanie oddzielnych potoków wdrażania zapewnia każdemu zespołowi kontrolę nad własnymi wdrożeniami. Użyj narzędzi ciągłej integracji i ciągłego dostarczania (CI/CD), takich jak Jenkins, GitHub Actions lub Azure Pipelines, aby skonfigurować te potoki.

  • Popraw mechanizmy kontroli zabezpieczeń. Upewnij się, że mechanizmy kontroli zabezpieczeń są aktualizowane tak, aby uwzględniały nową architekturę, w tym reguły zapory i mechanizmy kontroli dostępu.

Wybieranie odpowiednich usług platformy Azure

W przypadku każdej usługi platformy Azure w architekturze zapoznaj się z odpowiednim przewodnikiem dotyczącym usługi platformy Azure w strukturze dobrze zaprojektowanej. W przypadku wzorca nowoczesnej aplikacji internetowej potrzebny jest system obsługi komunikatów asynchronicznych, platforma aplikacji obsługująca konteneryzację i repozytorium obrazów kontenerów.

  • Wybierz kolejkę komunikatów. Kolejka komunikatów jest ważnym elementem architektur zorientowanych na usługę. Umożliwia oddzielenie nadawców komunikatów i odbiorników w celu włączenia asynchronicznej obsługi komunikatów. Skorzystaj ze wskazówek dotyczących wybierania usługi obsługi komunikatów platformy Azure, aby wybrać system obsługi komunikatów platformy Azure, który obsługuje twoje potrzeby projektowe. Platforma Azure ma trzy usługi obsługi komunikatów: Azure Event Grid, Azure Event Hubs i Service Bus. Zacznij od usługi Service Bus jako domyślnego wyboru i użyj pozostałych dwóch opcji, jeśli usługa Service Bus nie spełnia Twoich potrzeb.

    Usługa Przypadek użycia
    Service Bus Wybierz usługę Service Bus, aby zapewnić niezawodne, uporządkowane i ewentualnie transakcyjne dostarczanie komunikatów o wysokiej wartości w aplikacjach dla przedsiębiorstw.
    Event Grid Wybierz usługę Event Grid, jeśli chcesz wydajnie obsługiwać dużą liczbę zdarzeń dyskretnych. Usługa Event Grid jest skalowalna w przypadku aplikacji opartych na zdarzeniach, w których wiele małych, niezależnych zdarzeń (takich jak zmiany stanu zasobu) musi być kierowanych do subskrybentów w modelu z małym opóźnieniem i modelem publikowania-subskrybowania.
    Event Hubs Wybierz usługę Event Hubs na potrzeby masowego pozyskiwania danych o wysokiej przepływności, takich jak dane telemetryczne, dzienniki lub analiza w czasie rzeczywistym. Usługa Event Hubs jest zoptymalizowana pod kątem scenariuszy przesyłania strumieniowego, w których dane zbiorcze muszą być pozyskiwane i przetwarzane w sposób ciągły.
  • Zaimplementuj usługę kontenera. W przypadku części aplikacji, które chcesz konteneryzować, potrzebujesz platformy aplikacji obsługującej kontenery. Skorzystaj ze wskazówek dotyczących wybierania usługi kontenera platformy Azure, aby pomóc w podjęciu decyzji. Platforma Azure ma trzy główne usługi kontenerów: Azure Container Apps, Azure Kubernetes Service (AKS) i aplikacja systemu Azure Service. Zacznij od usługi Container Apps jako domyślnego wyboru i użyj pozostałych dwóch opcji, jeśli usługa Container Apps nie spełnia Twoich potrzeb.

    Usługa Przypadek użycia
    Aplikacje kontenera Wybierz pozycję Container Apps, jeśli potrzebujesz bezserwerowej platformy, która automatycznie skaluje kontenery i zarządza nimi w aplikacjach opartych na zdarzeniach.
    AKS Wybierz usługę AKS, jeśli potrzebujesz szczegółowej kontroli nad konfiguracjami platformy Kubernetes i zaawansowanymi funkcjami skalowania, sieci i zabezpieczeń.
    Web Apps for Container Wybierz pozycję Web App for Containers w usłudze App Service, aby uzyskać najprostsze środowisko PaaS.
  • Zaimplementuj repozytorium kontenerów. W przypadku korzystania z dowolnej usługi obliczeniowej opartej na kontenerach należy mieć repozytorium do przechowywania obrazów kontenerów. Możesz użyć publicznego rejestru kontenerów, takiego jak Docker Hub lub zarządzanego rejestru, takiego jak Azure Container Registry. Skorzystaj z artykułu Wprowadzenie do rejestrów kontenerów na platformie Azure, aby pomóc w podjęciu decyzji.

Wskazówki dotyczące kodu

Aby pomyślnie oddzielić i wyodrębnić niezależną usługę, należy zaktualizować kod aplikacji internetowej przy użyciu następujących wzorców projektowych: wzorzec ściągnięty, wzorzec bilansowania obciążenia opartego na kolejce, wzorzec konkurujących konsumentów, wzorzec monitorowania punktu końcowego kondycji i wzorzec ponawiania prób.

Diagram przedstawiający rolę wzorców projektowych w architekturze wzorca nowoczesnej aplikacji internetowej.Rysunek 3. Rola wzorców projektowych.

  1. Wzorzec fig stranglera: Wzorzec figowy strangler przyrostowo migruje funkcje z aplikacji monolitycznej do usługi oddzielonej. Zaimplementuj ten wzorzec w głównej aplikacji internetowej, aby stopniowo migrować funkcje do niezależnych usług, kierując ruch na podstawie punktów końcowych.

  2. Wzorzec bilansowania obciążenia opartego na kolejce: wzorzec bilansowania obciążenia opartego na kolejce zarządza przepływem komunikatów między producentem a odbiorcą przy użyciu kolejki jako buforu. Zaimplementuj ten wzorzec w części producenta usługi oddzielonej, aby zarządzać przepływem komunikatów asynchronicznie przy użyciu kolejki.

  3. Wzorzec konkurujących odbiorców: Wzorzec konkurujących odbiorców umożliwia niezależne odczytywanie z tej samej kolejki komunikatów wielu wystąpień usługi rozdzielanej i konkurowanie o przetwarzanie komunikatów. Zaimplementuj ten wzorzec w oddzielonej usłudze, aby dystrybuować zadania między wieloma wystąpieniami.

  4. Wzorzec monitorowania punktu końcowego kondycji: Wzorzec monitorowania punktu końcowego kondycji uwidacznia punkty końcowe na potrzeby monitorowania stanu i kondycji różnych części aplikacji internetowej. (4a) Zaimplementuj ten wzorzec w głównej aplikacji internetowej. (4b) Ponadto zaimplementuj ją w oddzielonej usłudze w celu śledzenia kondycji punktów końcowych.

  5. Wzorzec ponawiania: wzorzec ponawiania obsługuje błędy przejściowe, ponawiając próby operacji, które mogą sporadycznie zakończyć się niepowodzeniem. (5a) Zaimplementuj ten wzorzec dla wszystkich wywołań wychodzących do innych usług platformy Azure w głównej aplikacji internetowej, takich jak wywołania kolejki komunikatów i prywatnych punktów końcowych. (5b) Ponadto zaimplementuj ten wzorzec w oddzielonej usłudze, aby obsługiwać błędy przejściowe w wywołaniach prywatnych punktów końcowych.

Każdy wzorzec projektu zapewnia korzyści, które są zgodne z co najmniej jednym filarem dobrze zaprojektowanej struktury (zobacz poniższą tabelę).

Wzorzec projektowania Lokalizacja implementacji Niezawodność (RE) Zabezpieczenia (SE) Optymalizacja kosztów (CO) Doskonałość operacyjna (OE) Wydajność (PE) Obsługa dobrze zaprojektowanych zasad struktury
Wzorzec figowy stranglera Główna aplikacja internetowa RE:08
CO:07
CO:08
OE:06
OE:11
Wzorzec wyrównywania obciążeń przy użyciu kolejki Producent usługi oddzielonej RE:06
RE:07
CO:12
PE:05
Wzorzec konkurujących odbiorców Odłączona usługa RE:05
RE:07
CO:05
CO:07
PE:05
PE:07
Wzorzec monitorowania punktu końcowego kondycji Główna aplikacja internetowa i odłączona usługa RE:07
RE:10
OE:07
PE:05
Wzorzec ponawiania prób Główna aplikacja internetowa i odłączona usługa RE:07

Implementowanie wzorca figowego stranglera

Użyj wzorca Strangler Fig, aby stopniowo migrować funkcje z monolitycznej bazy kodu do nowych niezależnych usług. Wyodrębnij nowe usługi z istniejącej bazy kodu monolitycznego i powoli modernizuj krytyczne części aplikacji internetowej. Aby zaimplementować wzorzec Fig stranglera, wykonaj następujące zalecenia:

  • Konfigurowanie warstwy routingu. W bazie kodu monolitycznej aplikacji internetowej zaimplementuj warstwę routingu, która kieruje ruch na podstawie punktów końcowych. Użyj niestandardowej logiki routingu zgodnie z potrzebami, aby obsługiwać określone reguły biznesowe na potrzeby kierowania ruchem. Jeśli na przykład masz /users punkt końcowy w aplikacji monolitycznej i przeniesiono te funkcje do usługi oddzielonej, warstwa routingu kieruje wszystkie żądania do /users nowej usługi.

  • Zarządzanie wdrażaniem funkcji. Użyj bibliotek zarządzania funkcjami platformy .NET, aby zaimplementować flagi funkcji i wdrożenie etapowe, aby stopniowo wdrażać oddzielone usługi. Istniejący routing aplikacji monolitycznych powinien kontrolować liczbę żądań odbieranych przez oddzielone usługi. Zacznij od niewielkiej liczby żądań i zwiększ użycie w miarę upływu czasu, gdy zyskujesz pewność co do jego stabilności i wydajności. Na przykład implementacja referencyjna wyodrębnia funkcję renderowania biletów do autonomicznej usługi, która może być stopniowo wprowadzana w celu obsługi większej części żądań renderowania biletów. Ponieważ nowa usługa udowodni swoją niezawodność i wydajność, może ostatecznie przejąć całą funkcję renderowania biletów z monolitu, kończąc przejście.

  • Użyj usługi fasady (w razie potrzeby). Usługa fasady jest przydatna, gdy pojedyncze żądanie musi wchodzić w interakcje z wieloma usługami lub gdy chcesz ukryć złożoność systemu bazowego od klienta. Jeśli jednak oddzielona usługa nie ma żadnych publicznych interfejsów API, usługa fasady może nie być konieczna. W monolitycznej bazie kodu aplikacji internetowej zaimplementuj usługę fasady w celu kierowania żądań do odpowiedniego zaplecza (monolitycznego lub mikrousługi). W nowej odłączonej usłudze upewnij się, że nowa usługa może obsługiwać żądania niezależnie po korzystaniu z fasady.

Implementowanie wzorca bilansowania obciążenia opartego na kolejce

Zaimplementuj wzorzec bilansowania obciążenia opartego na kolejce w części producenta usługi oddzielonej do asynchronicznego obsługi zadań, które nie wymagają natychmiastowych odpowiedzi. Ten wzorzec zwiększa ogólną szybkość reakcji i skalowalność systemu przy użyciu kolejki do zarządzania dystrybucją obciążeń. Umożliwia ona oddzielenie usługi do przetwarzania żądań z stałą szybkością. Aby skutecznie zaimplementować ten wzorzec, postępuj zgodnie z następującymi zaleceniami:

  • Użyj funkcji kolejkowania komunikatów nieblokujących. Upewnij się, że proces, który wysyła komunikaty do kolejki, nie blokuje innych procesów podczas oczekiwania na oddzielenie usługi do obsługi komunikatów w kolejce. Jeśli proces wymaga wyniku operacji odłączenia usługi, możesz skorzystać z alternatywnego sposobu obsługi sytuacji podczas oczekiwania na ukończenie operacji w kolejce. Na przykład implementacja referencyjna używa usługi Service Bus i słowa kluczowego await z messageSender.PublishAsync() poleceniem do asynchronicznego publikowania komunikatów w kolejce bez blokowania wątku, który uruchamia ten kod:

    // Asynchronously publish a message without blocking the calling thread
    await messageSender.PublishAsync(new TicketRenderRequestMessage(Guid.NewGuid(), ticket, null, DateTime.Now), CancellationToken.None);
    

    Takie podejście zapewnia, że główna aplikacja pozostaje elastyczna i może obsługiwać inne zadania jednocześnie, podczas gdy oddzielona usługa przetwarza żądania w kolejce z możliwością zarządzania.

  • Zaimplementuj ponawianie i usuwanie komunikatów. Zaimplementuj mechanizm ponawiania próby przetworzenia komunikatów w kolejce, których nie można pomyślnie przetworzyć. Jeśli awarie będą się powtarzać, te komunikaty powinny zostać usunięte z kolejki. Na przykład usługa Service Bus ma wbudowane funkcje kolejki ponawiania prób i utraconych komunikatów.

  • Konfigurowanie przetwarzania komunikatów idempotentnych. Logika, która przetwarza komunikaty z kolejki, musi być idempotentna w celu obsługi przypadków, w których komunikat może być przetwarzany więcej niż raz. Na przykład implementacja referencyjna używa polecenia ServiceBusClient.CreateProcessor AutoCompleteMessages = true i ReceiveMode = ServiceBusReceiveMode.PeekLock w celu zapewnienia, że komunikaty są przetwarzane tylko raz i mogą być ponownie przetwarzane po awarii (zobacz następujący kod).

    // Create a processor for idempotent message processing
    var processor = serviceBusClient.CreateProcessor(path, new ServiceBusProcessorOptions
    {
        // Allow the messages to be auto-completed
        // if processing finishes without failure.
        AutoCompleteMessages = true,
    
        // PeekLock mode provides reliability in that unsettled messages
        // will be redelivered on failure.
        ReceiveMode = ServiceBusReceiveMode.PeekLock,
    
        // Containerized processors can scale at the container level
        // and need not scale via the processor options.
        MaxConcurrentCalls = 1,
        PrefetchCount = 0
    });
    
  • Zarządzanie zmianami w środowisku. Przetwarzanie asynchroniczne może prowadzić do braku natychmiastowego ukończenia zadań. Użytkownicy powinni być świadomi, kiedy ich zadanie jest nadal przetwarzane w celu ustawienia prawidłowych oczekiwań i uniknięcia nieporozumień. Użyj wizualnych wskazówek lub komunikatów, aby wskazać, że zadanie jest w toku. Nadaj użytkownikom możliwość otrzymywania powiadomień po zakończeniu zadania, takiego jak wiadomość e-mail lub powiadomienie wypychane.

Implementowanie wzorca konkurujących odbiorców

Zaimplementuj wzorzec konkurujących odbiorców w usługach oddzielonych, aby zarządzać zadaniami przychodzącymi z kolejki komunikatów. Ten wzorzec obejmuje dystrybucję zadań w wielu wystąpieniach usług oddzielonych. Te usługi przetwarzają komunikaty z kolejki, zwiększając równoważenie obciążenia i zwiększając pojemność systemu w celu obsługi równoczesnych żądań. Wzorzec konkurujących odbiorców jest skuteczny, gdy:

  • Sekwencja przetwarzania komunikatów nie ma kluczowego znaczenia.
  • Kolejka pozostaje nienaruszona przez źle sformułowane komunikaty.
  • Operacja przetwarzania jest idempotentna, co oznacza, że można ją stosować wiele razy bez zmiany wyniku poza początkową aplikacją.

Aby zaimplementować wzorzec konkurujących odbiorców, postępuj zgodnie z następującymi zaleceniami:

  • Obsługa współbieżnych komunikatów. Podczas odbierania komunikatów z kolejki upewnij się, że system jest przeznaczony do obsługi wielu komunikatów jednocześnie. Ustaw maksymalną liczbę współbieżnych wywołań na 1, aby oddzielny odbiorca obsłużył każdy komunikat.

  • Wyłącz pobieranie wstępne. Wyłącz wstępne pobieranie komunikatów, aby użytkownicy pobierali komunikaty tylko wtedy, gdy są gotowe.

  • Używaj niezawodnych trybów przetwarzania komunikatów. Użyj niezawodnego trybu przetwarzania, takiego jak PeekLock (lub jego odpowiednik), który automatycznie ponawia próby komunikatów, które kończą się niepowodzeniem. Ten tryb zwiększa niezawodność w przypadku metod najpierw usuwania. Jeśli jeden proces roboczy nie obsługuje komunikatu, inny musi być w stanie przetworzyć go bez błędów, nawet jeśli komunikat jest przetwarzany wiele razy.

  • Implementowanie obsługi błędów. Kierowanie nieprawidłowo sformułowanych lub nieprzetworzonych komunikatów do oddzielnej kolejki utraconych komunikatów. Ten projekt uniemożliwia powtarzalne przetwarzanie. Można na przykład przechwytywać wyjątki podczas przetwarzania komunikatów i przenosić problematyczny komunikat do oddzielnej kolejki.

  • Obsługa komunikatów poza kolejnością. Zaprojektuj użytkowników, aby przetwarzali komunikaty wychodzące z sekwencji. Wielu odbiorców równoległych oznacza, że mogą przetwarzać komunikaty poza kolejnością.

  • Skalowanie na podstawie długości kolejki. Usługi korzystające z komunikatów z kolejki powinny być skalowane automatycznie na podstawie długości kolejki. Skalowanie automatyczne oparte na skali umożliwia wydajne przetwarzanie skoków przychodzących komunikatów.

  • Użyj kolejki odpowiedzi z komunikatami. Jeśli system wymaga powiadomień dotyczących przetwarzania po komunikatach, skonfiguruj dedykowaną odpowiedź lub kolejkę odpowiedzi. Ta konfiguracja dzieli komunikaty operacyjne z procesów powiadomień.

  • Korzystanie z usług bezstanowych. Rozważ użycie usług bezstanowych do przetwarzania żądań z kolejki. Umożliwia łatwe skalowanie i efektywne użycie zasobów.

  • Konfigurowanie rejestrowania. Integrowanie rejestrowania i obsługi określonych wyjątków w przepływie pracy przetwarzania komunikatów. Skoncentruj się na przechwytywaniu błędów serializacji i kierowaniu tych problematycznych komunikatów do mechanizmu utraconych komunikatów. Te dzienniki zapewniają cenne szczegółowe informacje dotyczące rozwiązywania problemów.

Na przykład implementacja referencyjna używa wzorca konkurujących odbiorców w usłudze bezstanowej uruchomionej w usłudze Container Apps do przetwarzania żądań renderowania biletów z kolejki usługi Service Bus. Konfiguruje procesor kolejek za pomocą:

  • AutouzupełnianieKomunikaty: automatycznie kończy komunikaty, jeśli są przetwarzane bez awarii.
  • ReceiveMode: używa trybu PeekLock i ponownie pobiera komunikaty, jeśli nie są rozliczane.
  • MaxConcurrentCalls: ustaw wartość na 1, aby obsłużyć jeden komunikat naraz.
  • PrefetchCount: ustaw wartość 0, aby uniknąć wstępnego pobierania komunikatów.

Procesor rejestruje szczegóły przetwarzania komunikatów, które ułatwiają rozwiązywanie problemów i monitorowanie. Przechwytuje błędy deserializacji i kieruje nieprawidłowe komunikaty do kolejki utraconych komunikatów, uniemożliwiając powtarzalne przetwarzanie błędów komunikatów. Usługa jest skalowana na poziomie kontenera, co pozwala na wydajną obsługę skoków komunikatów na podstawie długości kolejki.

// Create a processor for the given queue that will process
// incoming messages.
var processor = serviceBusClient.CreateProcessor(path, new ServiceBusProcessorOptions
{
    // Allow the messages to be auto-completed
    // if processing finishes without failure.
    AutoCompleteMessages = true,
    // PeekLock mode provides reliability in that unsettled messages
    // are redelivered on failure.
    ReceiveMode = ServiceBusReceiveMode.PeekLock,
    // Containerized processors can scale at the container level
    // and need not scale via the processor options.
    MaxConcurrentCalls = 1,
    PrefetchCount = 0
});

// Called for each message received by the processor.
processor.ProcessMessageAsync += async args =>
{
    logger.LogInformation("Processing message {MessageId} from {ServiceBusNamespace}/{Path}", args.Message.MessageId, args.FullyQualifiedNamespace, args.EntityPath);
    // Unhandled exceptions in the handler will be caught by
    // the processor and result in abandoning and dead-lettering the message.
    try
    {
        var message = args.Message.Body.ToObjectFromJson<T>();
        await messageHandler(message, args.CancellationToken);
        logger.LogInformation("Successfully processed message {MessageId} from {ServiceBusNamespace}/{Path}",args.Message.MessageId, args.FullyQualifiedNamespace, args.EntityPath);
    }
    catch (JsonException)
    {
        logger.LogError("Invalid message body; could not be deserialized to {Type}", typeof(T));
        await args.DeadLetterMessageAsync(args.Message, $"Invalid message body; could not be deserialized to {typeof(T)}",cancellationToken: args.CancellationToken);
    }
};

Implementowanie wzorca monitorowania punktu końcowego kondycji

Zaimplementuj wzorzec monitorowania punktu końcowego kondycji w kodzie głównej aplikacji i odłączony kod usługi w celu śledzenia kondycji punktów końcowych aplikacji. Koordynatorzy, tacy jak AKS lub Container Apps, mogą sondować te punkty końcowe, aby zweryfikować kondycję usługi i ponownie uruchomić wystąpienia w złej kondycji. aplikacje ASP.NET Core mogą dodawać dedykowane oprogramowanie pośredniczące kontroli kondycji, aby efektywnie obsługiwać dane kondycji punktu końcowego i kluczowe zależności. Aby zaimplementować wzorzec monitorowania punktu końcowego kondycji, wykonaj następujące zalecenia:

  • Implementowanie kontroli kondycji. Użyj oprogramowania pośredniczącego ASP.NET Core health checks, aby zapewnić punkty końcowe sprawdzania kondycji.

  • Zweryfikuj zależności. Upewnij się, że testy kondycji sprawdzają dostępność kluczowych zależności, takich jak baza danych, magazyn i system obsługi komunikatów. Pakiet innych niż Microsoft, AspNetCore.Diagnostics.HealthChecks, może zaimplementować sprawdzanie zależności kontroli kondycji dla wielu typowych zależności aplikacji.

    Na przykład implementacja referencyjna używa oprogramowania pośredniczącego ASP.NET Core health check, aby uwidocznić punkty końcowe sprawdzania kondycji przy użyciu AddHealthChecks() metody w builder.Services obiekcie . Kod weryfikuje dostępność kluczowych zależności, usługi Azure Blob Storage i kolejki usługi Service Bus za pomocą AddAzureBlobStorage() metod i AddAzureServiceBusQueue() , które są częścią AspNetCore.Diagnostics.HealthChecks pakietu. Usługa Container Apps umożliwia skonfigurowanie monitorowanych sond kondycji w celu oceny, czy aplikacje są w dobrej kondycji, czy wymagają recyklingu.

    // Add health checks, including health checks for Azure services
    // that are used by this service.
    // The Blob Storage and Service Bus health checks are provided by
    // AspNetCore.Diagnostics.HealthChecks
    // (a popular open source project) rather than by Microsoft. 
    // https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks
    builder.Services.AddHealthChecks()
    .AddAzureBlobStorage(options =>
    {
        // AddAzureBlobStorage will use the BlobServiceClient registered in DI
        // We just need to specify the container name
        options.ContainerName = builder.Configuration.GetRequiredConfigurationValue("App:StorageAccount:Container");
    })
    .AddAzureServiceBusQueue(
        builder.Configuration.GetRequiredConfigurationValue("App:ServiceBus:Host"),
        builder.Configuration.GetRequiredConfigurationValue("App:ServiceBus:RenderRequestQueueName"),
        azureCredentials);
    
    // Further app configuration omitted for brevity
    app.MapHealthChecks("/health");
    
  • Konfigurowanie zasobów platformy Azure. Skonfiguruj zasoby platformy Azure, aby używać adresów URL kontroli kondycji aplikacji w celu potwierdzenia aktualności i gotowości. Na przykład implementacja referencyjna używa Bicep do skonfigurowania adresów URL kontroli kondycji w celu potwierdzenia aktualności i gotowości zasobu platformy Azure. Sonda aktualności, która ma trafić do punktu końcowego /health co 10 sekund po początkowym opóźnieniu 2 sekund.

    probes: [
      {
        type: 'liveness'
        httpGet: {
          path: '/health'
          port: 8080
        }
        initialDelaySeconds: 2
        periodSeconds: 10
      }
    ]
    

Implementowanie wzorca ponawiania prób

Wzorzec ponawiania umożliwia aplikacjom odzyskiwanie po błędach przejściowych. Wzorzec ponawiania jest kluczowy dla wzorca Niezawodnej aplikacji internetowej, więc aplikacja internetowa powinna już używać wzorca ponawiania. Zastosuj wzorzec ponawiania prób do żądań do systemów obsługi komunikatów i żądań wystawionych przez oddzielone usługi wyodrębnione z aplikacji internetowej. Aby zaimplementować wzorzec ponawiania prób, wykonaj następujące zalecenia:

  • Skonfiguruj opcje ponawiania prób. Podczas integracji z kolejką komunikatów należy skonfigurować klienta odpowiedzialnego za interakcje z kolejką z odpowiednimi ustawieniami ponawiania prób. Określ parametry, takie jak maksymalna liczba ponownych prób, opóźnienie między ponowną próbą i maksymalnym opóźnieniem.

  • Użyj wycofywania wykładniczego. Zaimplementuj strategię wycofywania wykładniczego na potrzeby ponownych prób. Oznacza to zwiększenie czasu między poszczególnymi ponownymi próbami wykładniczo, co pomaga zmniejszyć obciążenie systemu w okresach wysokich współczynników awarii.

  • Użyj funkcji ponawiania prób zestawu SDK. W przypadku usług z wyspecjalizowanymi zestawami SDK, takimi jak Service Bus lub Blob Storage, użyj wbudowanych mechanizmów ponawiania prób. Wbudowane mechanizmy ponawiania prób są zoptymalizowane pod kątem typowych przypadków użycia usługi i mogą efektywniej obsługiwać ponawianie prób przy mniejszej wymaganej konfiguracji. Na przykład implementacja referencyjna korzysta z wbudowanych funkcji ponawiania prób zestawu SDK usługi Service Bus (ServiceBusClient i ServiceBusRetryOptions). Obiekt ServiceBusRetryOptions pobiera ustawienia z MessageBusOptions programu , aby skonfigurować ustawienia ponawiania prób, takie jak MaxRetries, Delay, MaxDelay i TryTimeout.

    // ServiceBusClient is thread-safe and can be reused for the lifetime
    // of the application.
    services.AddSingleton(sp =>
    {
        var options = sp.GetRequiredService<IOptions<MessageBusOptions>>().Value;
        var clientOptions = new ServiceBusClientOptions
        {
            RetryOptions = new ServiceBusRetryOptions
            {
                Mode = ServiceBusRetryMode.Exponential,
                MaxRetries = options.MaxRetries,
                Delay = TimeSpan.FromSeconds(options.BaseDelaySecondsBetweenRetries),
                MaxDelay = TimeSpan.FromSeconds(options.MaxDelaySeconds),
                TryTimeout = TimeSpan.FromSeconds(options.TryTimeoutSeconds)
            }
        };
        return new ServiceBusClient(options.Host, azureCredential ?? new DefaultAzureCredential(), clientOptions);
    });
    
  • Wdrażanie standardowych bibliotek odporności dla klientów HTTP. W przypadku komunikacji HTTP należy zintegrować standardową bibliotekę odporności, taką jak Polly lub Microsoft.Extensions.Http.Resilience. Te biblioteki oferują kompleksowe mechanizmy ponawiania prób, które mają kluczowe znaczenie dla zarządzania komunikacją z zewnętrznymi usługami internetowymi.

  • Obsługa blokowania komunikatów. W przypadku systemów opartych na komunikatach zaimplementuj strategie obsługi komunikatów, które obsługują ponawianie prób bez utraty danych, takie jak używanie trybów "peek-lock", jeśli są dostępne. Upewnij się, że komunikaty, które zakończyły się niepowodzeniem, są skutecznie ponawiane i przenoszone do kolejki utraconych komunikatów po powtarzających się awariach.

Implementowanie śledzenia rozproszonego

Ponieważ aplikacje stają się bardziej zorientowane na usługę, a ich składniki są oddzielone, monitorowanie przepływu wykonywania między usługami ma kluczowe znaczenie. Wzorzec nowoczesnej aplikacji internetowej używa usług Application Insights i Azure Monitor do wglądu w kondycję i wydajność aplikacji za pośrednictwem interfejsów API openTelemetry, które obsługują śledzenie rozproszone.

Śledzenie rozproszone śledzi żądanie użytkownika podczas przechodzenia przez wiele usług. Gdy żądanie zostanie odebrane, zostanie oznaczone identyfikatorem śledzenia, który jest przekazywany do innych składników za pośrednictwem nagłówków HTTP i właściwości usługi Service Bus podczas wywołania zależności. Następnie ślady i dzienniki zawierają zarówno identyfikator śledzenia, jak i identyfikator działania (lub identyfikator zakresu), który odpowiada konkretnemu składnikowi i jego działaniu nadrzędnej. Narzędzia do monitorowania, takie jak Application Insights, używają ich do wyświetlania drzewa działań i dzienników w różnych usługach, co ma kluczowe znaczenie dla monitorowania aplikacji rozproszonych.

  • Zainstaluj biblioteki OpenTelemetry. Użyj bibliotek instrumentacji, aby włączyć śledzenie i metryki z typowych składników. Dodaj instrumentację niestandardową za pomocą System.Diagnostics.ActivitySource polecenia i System.Diagnostics.Activity w razie potrzeby. Użyj bibliotek eksportera, aby nasłuchiwać diagnostyki OpenTelemetry i rejestrować je w magazynach trwałych. Skorzystaj z istniejących eksporterów lub utwórz własne za pomocą polecenia System.Diagnostics.ActivityListener.

  • Skonfiguruj usługę OpenTelemetry. Użyj dystrybucji usługi Azure Monitor usługi OpenTelemetry (Azure.Monitor.OpenTelemetry.AspNetCore). Upewnij się, że eksportuje diagnostykę do usługi Application Insights i obejmuje wbudowaną instrumentację dla typowych metryk, śladów, dzienników i wyjątków z środowiska uruchomieniowego platformy .NET i ASP.NET Core. Uwzględnij inne pakiety instrumentacji OpenTelemetry dla klientów SQL, Redis i Azure SDK.

  • Monitorowanie i analizowanie. Po skonfigurowaniu upewnij się, że dzienniki, ślady, metryki i wyjątki są przechwytywane i wysyłane do usługi Application Insights. Sprawdź, czy uwzględniane są identyfikatory śledzenia, aktywności i działań nadrzędnych, co umożliwia usłudze Application Insights zapewnienie kompleksowej widoczności śledzenia w granicach protokołu HTTP i usługi Service Bus. Ta konfiguracja służy do efektywnego monitorowania i analizowania działań aplikacji w usługach.

Przykład nowoczesnej aplikacji internetowej korzysta z dystrybucji usługi Azure Monitor usługi OpenTelemetry (Azure.Monitor.OpenTelemetry.AspNetCore). Więcej pakietów instrumentacji jest używanych dla klientów SQL, Redis i Azure SDK. Funkcja OpenTelemetry jest skonfigurowana w przykładowej usłudze renderowania biletów nowoczesnej aplikacji internetowej w następujący sposób:

builder.Logging.AddOpenTelemetry(o => 
{ 
    o.IncludeFormattedMessage = true; 
    o.IncludeScopes = true; 
}); 

builder.Services.AddOpenTelemetry() 
    .UseAzureMonitor(o => o.ConnectionString = appInsightsConnectionString) 
    .WithMetrics(metrics => 
    { 
        metrics.AddAspNetCoreInstrumentation() 
                .AddHttpClientInstrumentation() 
                .AddRuntimeInstrumentation(); 
    }) 
    .WithTracing(tracing => 
    { 
        tracing.AddAspNetCoreInstrumentation() 
                .AddHttpClientInstrumentation() 
                .AddSource("Azure.*"); 
    }); 

Metoda builder.Logging.AddOpenTelemetry kieruje wszystkie rejestrowanie za pośrednictwem technologii OpenTelemetry, zapewniając spójne śledzenie i rejestrowanie w aplikacji. Rejestrując usługi builder.Services.AddOpenTelemetryOpenTelemetry w usłudze , aplikacja jest skonfigurowana do zbierania i eksportowania diagnostyki, które następnie są wysyłane do usługi Application Insights za pośrednictwem usługi UseAzureMonitor. Ponadto instrumentacja klienta dla składników, takich jak usługa Service Bus i klienci HTTP, jest konfigurowana za pomocą WithMetrics poleceń i WithTracing, umożliwiając automatyczne metryki i zbieranie śladów bez konieczności wprowadzania zmian w istniejącym użyciu klienta, tylko aktualizacji konfiguracji.

Wskazówki dotyczące konfiguracji

Poniższe sekcje zawierają wskazówki dotyczące implementowania aktualizacji konfiguracji. Każda sekcja jest zgodna z co najmniej jednym filarem dobrze zaprojektowanej struktury.

Konfigurowanie Niezawodność (RE) Zabezpieczenia (SE) Optymalizacja kosztów (CO) Doskonałość operacyjna (OE) Wydajność (PE) Obsługa dobrze zaprojektowanych zasad struktury
Konfigurowanie uwierzytelniania i autoryzacji SE:05
OE:10
Implementowanie niezależnego skalowania automatycznego RE:06
CO:12
PE:05
Konteneryzowanie wdrożenia usługi CO:13
PE:09
PE:03

Konfigurowanie uwierzytelniania i autoryzacji

Aby skonfigurować uwierzytelnianie i autoryzację dla wszystkich nowych usług platformy Azure (tożsamości obciążeń) dodanych do aplikacji internetowej, postępuj zgodnie z następującymi zaleceniami:

  • Użyj tożsamości zarządzanych dla każdej nowej usługi. Każda niezależna usługa powinna mieć własną tożsamość i używać tożsamości zarządzanych do uwierzytelniania między usługami. Tożsamości zarządzane eliminują konieczność zarządzania poświadczeniami w kodzie i zmniejszają ryzyko wycieku poświadczeń. Pomagają one uniknąć umieszczania poufnych informacji, takich jak parametry połączenia w kodzie lub plikach konfiguracji.

  • Przyznaj każdemu nowemu usłudze najmniej uprawnień. Przypisz tylko niezbędne uprawnienia do każdej nowej tożsamości usługi. Jeśli na przykład tożsamość musi być wypychana tylko do rejestru kontenerów, nie daj jej uprawnień ściągnięcia. Regularnie przeglądaj te uprawnienia i dostosuj je w razie potrzeby. Użyj różnych tożsamości dla różnych ról, takich jak wdrażanie i aplikacja. Ogranicza to potencjalne szkody w przypadku naruszenia zabezpieczeń jednej tożsamości.

  • Wdrażanie infrastruktury jako kodu (IaC). Użyj narzędzi Bicep lub podobnych narzędzi IaC, aby zdefiniować zasoby w chmurze i zarządzać nimi. Infrastruktura IaC zapewnia spójne stosowanie konfiguracji zabezpieczeń we wdrożeniach i umożliwia kontrolowanie wersji konfiguracji infrastruktury.

Aby skonfigurować uwierzytelnianie i autoryzację dla użytkowników (tożsamości użytkowników), wykonaj następujące zalecenia:

  • Przyznawanie użytkownikom najniższych uprawnień. Podobnie jak w przypadku usług, upewnij się, że użytkownicy otrzymują tylko uprawnienia, których potrzebują do wykonywania swoich zadań. Regularnie sprawdzaj i dostosowuj te uprawnienia.

  • Przeprowadzanie regularnych inspekcji zabezpieczeń. Regularnie sprawdzaj i przeprowadzaj inspekcję konfiguracji zabezpieczeń. Poszukaj wszelkich błędów konfiguracji lub niepotrzebnych uprawnień i natychmiast je sprostuj.

Implementacja referencyjna używa usługi IaC do przypisywania tożsamości zarządzanych do dodanych usług i określonych ról do każdej tożsamości. Definiuje role i uprawnienia dostępu do wdrożenia (containerRegistryPushRoleId), właściciela aplikacji (containerRegistryPushRoleId) i aplikacji usługi Container Apps (containerRegistryPullRoleId) (zobacz następujący kod).

roleAssignments: \[
    {
    principalId: deploymentSettings.principalId
    principalType: deploymentSettings.principalType
    roleDefinitionIdOrName: containerRegistryPushRoleId
    }
    {
    principalId: ownerManagedIdentity.outputs.principal_id
    principalType: 'ServicePrincipal'
    roleDefinitionIdOrName: containerRegistryPushRoleId
    }
    {
    principalId: appManagedIdentity.outputs.principal_id
    principalType: 'ServicePrincipal'
    roleDefinitionIdOrName: containerRegistryPullRoleId
    }
\]

Implementacja referencyjna przypisuje tożsamość zarządzaną jako nową tożsamość usługi Container Apps we wdrożeniu (zobacz następujący kod).

module renderingServiceContainerApp 'br/public:avm/res/app/container-app:0.1.0' = {
  name: 'application-rendering-service-container-app'
  scope: resourceGroup()
  params: {
    // Other parameters omitted for brevity
    managedIdentities: {
      userAssignedResourceIds: [
        managedIdentity.id
      ]
    }
  }
}

Konfigurowanie niezależnego skalowania automatycznego

Wzorzec nowoczesnej aplikacji internetowej zaczyna rozpadać architekturę monolityczną i wprowadza oddzielenie usług. W przypadku oddzielenia architektury aplikacji internetowej można niezależnie skalować oddzielone usługi. Skalowanie usług platformy Azure w celu obsługi niezależnej usługi aplikacji internetowej, a nie całej aplikacji internetowej, optymalizuje skalowanie kosztów przy jednoczesnym spełnieniu wymagań. Aby automatycznie skalować kontenery, wykonaj następujące zalecenia:

  • Korzystanie z usług bezstanowych. Upewnij się, że usługi są bezstanowe. Jeśli aplikacja platformy .NET zawiera stan sesji procesu, należy ją zewnętrznie połączyć z rozproszoną pamięcią podręczną, na przykład Redis lub bazą danych, na przykład SQL Server.

  • Konfigurowanie reguł skalowania automatycznego. Użyj konfiguracji skalowania automatycznego, które zapewniają najbardziej ekonomiczną kontrolę nad usługami. W przypadku usług konteneryzowanych skalowanie oparte na zdarzeniach, takie jak narzędzie Kubernetes Event-Driven Autoscaler (KEDA), często zapewnia szczegółową kontrolę, umożliwiając skalowanie na podstawie metryk zdarzeń. Usługa Container Apps i usługa AKS obsługują usługę KEDA. W przypadku usług, które nie obsługują usługi KEDA, takich jak usługa App Service, użyj funkcji skalowania automatycznego udostępnianych przez samą platformę. Te funkcje często obejmują skalowanie na podstawie reguł opartych na metrykach lub ruchu HTTP.

  • Skonfiguruj minimalną liczbę replik. Aby zapobiec zimnemu startowi, skonfiguruj ustawienia skalowania automatycznego, aby zachować co najmniej jedną replikę. Zimny start polega na zainicjowaniu usługi ze stanu zatrzymania, co często powoduje opóźnienie odpowiedzi. Jeśli minimalizacja kosztów jest priorytetem i można tolerować opóźnienia uruchamiania zimnego, ustaw minimalną liczbę replik na 0 podczas konfigurowania skalowania automatycznego.

  • Skonfiguruj okres ochładzania. Zastosuj odpowiedni okres ochładzania, aby wprowadzić opóźnienie między zdarzeniami skalowania. Celem jest zapobieganie nadmiernym skalowaniu działań wyzwalanych przez tymczasowe skoki obciążenia.

  • Konfigurowanie skalowania opartego na kolejce. Jeśli aplikacja używa kolejki komunikatów, takiej jak Service Bus, skonfiguruj ustawienia skalowania automatycznego w celu skalowania na podstawie długości kolejki z komunikatami żądania. Program scaler ma na celu utrzymanie jednej repliki usługi dla każdego N komunikatów w kolejce (zaokrąglone w górę).

Na przykład implementacja referencyjna używa modułu skalowania KEDA usługi Service Bus do skalowania aplikacji kontenera na podstawie długości kolejki. Usługa service-bus-queue-length-rule skaluje usługę na podstawie długości określonej kolejki usługi Service Bus. Parametr messageCount jest ustawiony na 10, więc skalowanie ma jedną replikę usługi dla każdego 10 komunikatów w kolejce. Parametry scaleMaxReplicas i scaleMinReplicas ustawiają maksymalną i minimalną liczbę replik dla usługi. Wpis queue-connection-string tajny zawierający parametry połączenia kolejki usługi Service Bus jest pobierany z usługi Azure Key Vault. Ten wpis tajny służy do uwierzytelniania narzędzia scaler w usłudze Service Bus.

scaleRules: [
  {
    name: 'service-bus-queue-length-rule'
    custom: {
      type: 'azure-servicebus'
      metadata: {
        messageCount: '10'
        namespace: renderRequestServiceBusNamespace
        queueName: renderRequestServiceBusQueueName
      }
      auth: [
        {
          secretRef: 'render-request-queue-connection-string'
          triggerParameter: 'connection'
        }
      ]
    }
  }
]

scaleMaxReplicas: 5
scaleMinReplicas: 0

Konteneryzowanie wdrożenia usługi

Konteneryzacja oznacza, że wszystkie zależności aplikacji do działania są hermetyzowane w uproszczonym obrazie, który można niezawodnie wdrożyć na wielu hostach. Aby konteneryzować wdrożenie, wykonaj następujące zalecenia:

  • Zidentyfikuj granice domeny. Zacznij od zidentyfikowania granic domeny w aplikacji monolitycznej. Pomaga to określić, które części aplikacji można wyodrębnić do oddzielnych usług.

  • Tworzenie obrazów platformy Docker. Podczas tworzenia obrazów platformy Docker dla usług platformy .NET użyj rozdrobnionych obrazów bazowych. Te obrazy zawierają tylko minimalny zestaw pakietów potrzebnych do uruchomienia platformy .NET, co minimalizuje zarówno rozmiar pakietu, jak i obszar powierzchni podatnej na ataki.

  • Użyj wieloetapowych plików Dockerfile. Zaimplementuj wieloetapowe pliki Dockerfile, aby oddzielić zasoby czasu kompilacji od obrazu kontenera środowiska uruchomieniowego. Pomaga to zachować małe i bezpieczne obrazy produkcyjne.

  • Uruchom polecenie jako użytkownik niebędący użytkownikiem głównym. Uruchom kontenery platformy .NET jako użytkownik niebędący użytkownikiem głównym (za pośrednictwem nazwy użytkownika lub identyfikatora UID, $APP_UID), aby dopasować się do zasady najniższych uprawnień. Ogranicza ona potencjalne skutki naruszenia zabezpieczeń kontenera.

  • Nasłuchiwanie na porcie 8080. W przypadku uruchamiania jako użytkownik niebędący użytkownikiem głównym skonfiguruj aplikację do nasłuchiwania na porcie 8080. Jest to powszechna konwencja dla użytkowników niebędących użytkownikami głównymi.

  • Hermetyzowanie zależności. Upewnij się, że wszystkie zależności aplikacji do działania są hermetyzowane w obrazie kontenera platformy Docker. Hermetyzacja umożliwia niezawodne wdrażanie aplikacji na wielu hostach.

  • Wybierz odpowiednie obrazy podstawowe. Wybrany obraz podstawowy zależy od środowiska wdrażania. Jeśli wdrażasz na przykład w usłudze Container Apps, musisz użyć obrazów platformy Docker systemu Linux.

Na przykład implementacja referencyjna używa wieloetapowego procesu kompilacji. Początkowe etapy kompilują i kompilują aplikację przy użyciu pełnego obrazu zestawu SDK (mcr.microsoft.com/dotnet/sdk:8.0-jammy). Końcowy obraz środowiska uruchomieniowego jest tworzony na podstawie obrazu podstawowego chiseled , który wyklucza zestaw SDK i artefakty kompilacji. Usługa działa jako użytkownik niebędący użytkownikiem głównym (USER $APP_UID) i uwidacznia port 8080. Zależności wymagane do działania aplikacji są uwzględniane w obrazie platformy Docker, co jest dowodem poleceń do kopiowania plików projektu i przywracania pakietów. Użycie obrazów opartych na systemie Linux (mcr.microsoft.com/dotnet/aspnet:8.0-jammy-chiseled) zapewnia zgodność z usługą Container Apps, która wymaga kontenerów systemu Linux do wdrożenia.

# Build in a separate stage to avoid copying the SDK into the final image
FROM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src

# Restore packages
COPY ["Relecloud.TicketRenderer/Relecloud.TicketRenderer.csproj", "Relecloud.TicketRenderer/"]
COPY ["Relecloud.Messaging/Relecloud.Messaging.csproj", "Relecloud.Messaging/"]
COPY ["Relecloud.Models/Relecloud.Models.csproj", "Relecloud.Models/"]
RUN dotnet restore "./Relecloud.TicketRenderer/Relecloud.TicketRenderer.csproj"

# Build and publish
COPY . .
WORKDIR "/src/Relecloud.TicketRenderer"
RUN dotnet publish "./Relecloud.TicketRenderer.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

# Chiseled images contain only the minimal set of packages needed for .NET 8.0
FROM mcr.microsoft.com/dotnet/aspnet:8.0-jammy-chiseled AS final
WORKDIR /app
EXPOSE 8080

# Copy the published app from the build stage
COPY --from=build /app/publish .

# Run as non-root user
USER $APP_UID
ENTRYPOINT ["dotnet", "./Relecloud.TicketRenderer.dll"]

Wdrażanie implementacji referencyjnej

Wdróż implementację referencyjną wzorca nowoczesnej aplikacji internetowej dla platformy .NET. W repozytorium znajdują się instrukcje dotyczące wdrażania programistycznego i produkcyjnego. Po wdrożeniu można symulować i obserwować wzorce projektowe.

Diagram przedstawiający architekturę implementacji referencyjnej.Rysunek 3. Architektura implementacji referencyjnej. Pobierz plik programu Visio tej architektury.