Wysłannik. 1. Wstęp

Pozdrowienia! To krótki artykuł, który odpowiada na pytania: „czym jest poseł?”, „do czego jest potrzebny?” i „od czego zacząć?”.

Co to jest?

Envoy to balanser L4-L7 napisany w C++, nastawiony na wysoką wydajność i dostępność. Z jednej strony jest to w pewnym sensie analogia nginx i haproxy, porównywalna z nimi wydajnością. Z drugiej strony jest bardziej zorientowany na architekturę mikroserwisową i ma funkcjonalność nie gorszą od balanserów Java i Go, takich jak zuul czy traefik.

Tabela porównawcza haproxy/nginx/envoy, nie rości sobie prawa do absolutnej prawdy, ale daje ogólny obraz.

nginx
haproxy
wysłannik
Traefik

gwiazdy na githubie
11.2 tys./lustro
1.1 tys./lustro
12.4k
27.6k

napisane w
C
C
C + +
go

API
nie
Tylko gniazdo/wciśnij
dataplane/pull
Ciągnąć

aktywna kontrola stanu
nie
tak
tak
tak

Otwarte śledzenie
wtyczka zewnętrzna
nie
tak
tak

JWT
wtyczka zewnętrzna
nie
tak
nie

rozbudowa
Lua/C
Lua/C
Lua/C++
nie

Po co

To młody projekt, brakuje mu wielu rzeczy, niektóre są w fazie wczesnej alfa. Ale wysłannik, również ze względu na swoją młodość, szybko się rozwija i posiada już wiele ciekawych funkcji: dynamiczną konfigurację, wiele gotowych filtrów, prosty interfejs do pisania własnych filtrów.
Z tego wynikają obszary zastosowań, ale najpierw istnieją 2 antywzorce:

  • Odrzut statyczny.

Fakt jest taki, że w tej chwili w wysłannik brak obsługi buforowania. Pracownicy Google próbują tego naprawić. Pomysł kiedyś zostanie wdrożony wysłannik wszystkie subtelności (nagłówki zoo) zgodności z RFC, a dla konkretnych implementacji utwórz interfejs. Ale na razie to nawet nie alfa, architektura jest w trakcie dyskusji, PR otwarty (kiedy pisałem artykuł PR, PR zamarł, ale ten punkt jest nadal aktualny).

Na razie użyj Nginx do statyki.

  • Konfiguracja statyczna.

Możesz z tego skorzystać, ale wysłannik Nie po to został stworzony. Funkcje w konfiguracji statycznej nie będą widoczne. Jest wiele momentów:

Edytując konfigurację w YAML, popełnisz błąd, zbesztasz programistów za gadatliwość i pomyślisz, że konfiguracje nginx/haproxy, choć mniej uporządkowane, są bardziej zwięzłe. O to chodzi. Konfiguracja Nginx i Haproxy została stworzona do ręcznej edycji i wysłannik do generowania z kodu. Całość konfiguracji opisana jest w protobuf, wygenerowanie go z plików proto jest znacznie trudniejsze do popełnienia błędu.

Scenariusze wdrożeń Canary, b/g i wiele innych są zwykle wdrażane tylko w konfiguracji dynamicznej. Nie twierdzę, że nie można tego zrobić statycznie, wszyscy to robimy. Ale w tym celu musisz założyć kule w dowolnym z balanserów wysłannik włącznie z.

Zadania, do których Envoy jest niezastąpiony:

  • Równoważenie ruchu w systemach złożonych i dynamicznych. Obejmuje to siatkę usług, ale niekoniecznie jest to jedyna.
  • Zapotrzebowanie na funkcjonalność rozproszonego śledzenia, złożoną autoryzację lub inną funkcjonalność dostępną w wysłannik od razu po wyjęciu z pudełka lub wygodnie zaimplementowany, ale w nginx/haproxy musisz być otoczony lua i podejrzanymi wtyczkami.

Oba, jeśli to konieczne, zapewniają wysoką wydajność.

Jak to działa

Envoy jest dystrybuowany w postaci binarnej wyłącznie jako obraz okna dokowanego. Obraz zawiera już przykład konfiguracji statycznej. Ale interesuje nas to tylko w celu zrozumienia struktury.

Konfiguracja statyczna envoy.yaml

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        protocol: TCP
        address: 0.0.0.0
        port_value: 10000
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  host_rewrite: www.google.com
                  cluster: service_google
          http_filters:
          - name: envoy.router
  clusters:
  - name: service_google
    connect_timeout: 0.25s
    type: LOGICAL_DNS
    # Comment out the following line to test on v6 networks
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: service_google
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: www.google.com
                port_value: 443
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.api.v2.auth.UpstreamTlsContext
        sni: www.google.com

Konfiguracja dynamiczna

Na jaki problem szukamy rozwiązania? Nie można po prostu przeładować konfiguracji modułu równoważenia obciążenia pod obciążeniem; pojawią się „małe” problemy:

  • Walidacja konfiguracji.

Konfiguracja może być duża, może być bardzo duża, jeśli przeciążymy ją całą na raz, ryzyko wystąpienia gdzieś błędu wzrasta.

  • Długowieczne połączenia.

Inicjując nowego słuchacza należy zadbać o połączenia działające na starym; jeśli zmiany zachodzą często i połączenia są długotrwałe, trzeba będzie szukać kompromisu. Witam, ingres Kubernetes na Nginx.

  • Aktywne kontrole stanu.

Jeśli mamy aktywne kontrole stanu, musimy je ponownie sprawdzić w nowej konfiguracji przed wysłaniem ruchu. Jeśli jest dużo upstreamów, zajmuje to trochę czasu. Witaj haproxy.

Jak to jest rozwiązane w wysłannikŁadując konfigurację dynamicznie, zgodnie z modelem puli, możesz podzielić ją na osobne części i nie inicjować ponownie części, która się nie zmieniła. Na przykład słuchacz, którego ponowna inicjalizacja jest kosztowna i rzadko się zmienia.

Konfiguracja wysłannik (z pliku powyżej) ma następujące podmioty:

  • słuchacz — słuchacz zawieszony na określonym adresie IP/porcie
  • wirtualny host - wirtualny host według nazwy domeny
  • trasa - zasada równoważenia
  • grupa — grupa upstreamów o parametrach bilansujących
  • Punkt końcowy — adres instancji nadrzędnej

Każdą z tych encji oraz kilka innych można wypełnić dynamicznie, w tym celu konfiguracja określa adres usługi, z której zostanie pobrana konfiguracja. Usługą może być REST lub gRPC, preferowana jest gRPC.

Usługi noszą odpowiednio nazwy: LDS, VHDS, RDS, CDS i EDS. Można łączyć konfigurację statyczną i dynamiczną, z zastrzeżeniem, że zasobu dynamicznego nie można określić w statycznym.

Do większości zadań wystarczy wdrożenie trzech ostatnich usług, nazywane są one ADS (Aggregated Discovery Service), dla Jawa i przejdź tam, jest gotowa implementacja płaszczyzny danych gRPC, w której wystarczy wypełnić obiekty ze źródła.

Konfiguracja ma następującą postać:

Konfiguracja dynamiczna envoy.yaml

dynamic_resources:
  ads_config:
    api_type: GRPC
    grpc_services:
      envoy_grpc:
        cluster_name: xds_clr
  cds_config:
    ads: {}
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        protocol: TCP
        address: 0.0.0.0
        port_value: 10000
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
          stat_prefix: ingress_http
          rds:
            route_config_name: local_route
            config_source:
              ads: {}
          http_filters:
          - name: envoy.router
  clusters:
  - name: xds_clr
    connect_timeout: 0.25s
    type: LOGICAL_DNS
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: xds_clr
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: xds
                port_value: 6565

Podczas uruchamiania wysłannik przy tej konfiguracji połączy się z płaszczyzną sterowania i spróbuje zażądać konfiguracji RDS, CDS i EDS. Opisano, jak zachodzi proces interakcji tutaj.

W skrócie, wysłannik wysyła żądanie wskazujące rodzaj żądanego zasobu, wersję i parametry węzła. W odpowiedzi otrzymuje zasób i wersję; jeśli wersja na płaszczyźnie kontrolnej nie uległa zmianie, nie odpowiada.
Istnieją 4 opcje interakcji:

  • Jeden strumień gRPC dla wszystkich typów zasobów, wysyłany jest pełny status zasobu.
  • Oddzielne strumienie, stan pełny.
  • Jeden strumień, stan przyrostowy.
  • Oddzielne strumienie, stan przyrostowy.

Przyrostowy xDS pozwala zredukować ruch pomiędzy płaszczyzną kontrolną i wysłannik, jest to istotne w przypadku dużych konfiguracji. Ale to komplikuje interakcję, żądanie zawiera listę zasobów do anulowania subskrypcji i subskrypcji.

W naszym przykładzie zastosowano ADS - jeden strumień dla RDS, CDS, EDS i trybu nieprzyrostowego. Aby włączyć tryb przyrostowy, musisz określić api_type: DELTA_GRPC

Ponieważ żądanie zawiera parametry węzła, możemy wysyłać różne zasoby do płaszczyzny kontrolnej dla różnych instancji wysłannikJest to wygodne w przypadku tworzenia siatki usług.

Rozgrzewka

Na wysłannik przy uruchomieniu lub otrzymaniu nowej konfiguracji z płaszczyzny kontrolnej uruchamiany jest proces rozgrzewania zasobów. Dzieli się na rozgrzewkę słuchacza i rozgrzewkę klastra. Pierwsza uruchamia się w przypadku zmian w RDS/LDS, druga w przypadku CDS/EDS. Oznacza to, że jeśli zmienią się tylko kanały nadrzędne, słuchacz nie zostanie odtworzony.

Podczas procesu rozgrzewania oczekuje się zasobów zależnych z płaszczyzny sterującej w czasie przekroczenia limitu czasu. Jeśli nastąpi przekroczenie limitu czasu, inicjalizacja nie powiedzie się i nowy słuchacz nie rozpocznie nasłuchiwania na porcie.
Kolejność inicjalizacji: EDS, CDS, aktywna kontrola stanu, RDS, LDS. Po włączeniu aktywnych kontroli stanu ruch będzie przesyłany w górę dopiero po jednej pomyślnej kontroli stanu.

Jeżeli słuchacz został utworzony od nowa, stary przechodzi w stan DRAIN i zostanie usunięty po zamknięciu wszystkich połączeń lub upłynięciu limitu czasu --drain-time-s, domyślnie 10 minut.

Aby być kontynuowane.

Źródło: www.habr.com

Dodaj komentarz