Cześć! To krótki artykuł, który odpowiada na pytania: „Czym jest envoy?”, „Dlaczego go potrzebuję?” i „Od czego zacząć?”.
Co to jest?
Envoy to moduł równoważenia obciążenia L4-L7 napisany w C++, skoncentrowany na wysokiej wydajności i dostępności. Z jednej strony jest nieco analogiczny do nginx i haproxy, porównywalny pod względem wydajności. Z drugiej strony jest bardziej skoncentrowany na architekturze mikrousług i ma funkcjonalność nie gorszą niż moduły równoważenia obciążenia w Javie i Go, takie jak zuul lub traefik.
Tabela porównawcza haproxy/nginx/envoy nie podaje absolutnej prawdy, ale daje ogólny obraz.
nginx
haproxy
wysłannik
Traefik
gwiazdki na githubie
11.2 tys./lustro
1.1 tys./lustro
12.4k
27.6k
napisane w
C
C
C + +
go
API
nie
tylko gniazdo/wtyk
płaszczyzna danych/pull
Ciągnąć
aktywna kontrola stanu zdrowia
nie
tak
tak
tak
Otwórz ś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 wielu rzeczy, niektóre są na wczesnym etapie alfa. Ale wysłannik, również z uwagi na swoją młodość, rozwija się bardzo szybko i już teraz posiada wiele ciekawych funkcji: dynamiczną konfigurację, wiele gotowych filtrów, prosty interfejs do pisania własnych filtrów.
Z tego wynikają obszary zastosowań, ale najpierw omówimy 2 antywzorce:
- Odrzut statyczny.
Rzecz w tym, że w tej chwili w wysłannik brak obsługi buforowania. Ludzie z Google próbują Pomysł jest taki, żeby to wdrażać od czasu do czasu wysłannik wszystkie subtelności (zoo nagłówków) zgodności z RFC i dla konkretnych implementacji, aby utworzyć interfejs. Ale jak dotąd nie jest to nawet alfa, architektura jest w trakcie dyskusji, otwarte (podczas gdy pisałem artykuł, PR został scalony, ale ten punkt jest nadal aktualny).
W międzyczasie użyj nginx do statystyk.
- Konfiguracja statyczna.
Możesz go użyć, ale wysłannik nie został stworzony do tego. Możliwości w konfiguracji statycznej nie zostaną ujawnione. Jest wiele punktów:
Podczas edycji konfiguracji w yaml popełnisz błędy, przeklniesz programistów za rozwlekłość i pomyślisz, że konfiguracje nginx/haproxy, mimo że mniej ustrukturyzowane, są bardziej zwięzłe. O to właśnie chodzi. Konfiguracje Nginx i Haproxy zostały stworzone do ręcznej edycji, a wysłannik do generowania z kodu. Cała konfiguracja jest opisana w generowanie go z plików proto znacznie utrudnia popełnienie błędu.
Scenariusze kanarkowe, wdrożenie b/g i wiele innych są zazwyczaj implementowane tylko w konfiguracji dynamicznej. Nie mówię, że nie można tego zrobić w statyce, wszyscy to robimy. Ale w tym celu musisz otoczyć się kulami, w dowolnym z balanserów, w wysłannik włącznie z.
Zadania, w których Envoy jest niezastąpiony:
- Równoważenie ruchu w złożonych i dynamicznych systemach. Obejmuje to siatkę usług, ale niekoniecznie jest jedyną.
- Potrzeba rozproszonego śledzenia, złożonej autoryzacji lub innej funkcjonalności dostępnej w wysłannik gotowe do użycia lub wygodnie zaimplementowane, natomiast w przypadku nginx/haproxy trzeba otaczać się lua i wątpliwymi wtyczkami.
Oba rozwiązania zapewniają wysoką wydajność w razie potrzeby.
Jak to działa
Envoy jest dystrybuowany w plikach binarnych wyłącznie jako obraz dokera. Obraz zawiera już przykład konfiguracji statycznej. Ale nas interesuje tylko zrozumienie 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.comDynamiczna konfiguracja
Jakiego problemu szukamy? Nie możesz po prostu zrestartować konfiguracji balancera pod obciążeniem, pojawią się „drobne” problemy:
- Walidacja konfiguracji.
Konfiguracja może być duża, może być bardzo duża, jeśli przeciążymy ją całą naraz, prawdopodobieństwo, że gdzieś wystąpi błąd, wzrasta.
- Trwałe połączenia.
Podczas inicjowania nowego nasłuchiwacza musisz zadbać o połączenia działające na starym, jeśli zmiany występują często i istnieją długotrwałe połączenia, będziesz musiał znaleźć kompromis. Cześć, kubernetes ingress na nginx.
- Aktywne kontrole stanu zdrowia.
Jeśli mamy aktywne kontrole kondycji, powinniśmy sprawdzić je wszystkie ponownie w nowej konfiguracji przed wysłaniem ruchu. Jeśli jest wiele upstreamów, to zajmuje trochę czasu. Cześć, haproxy.
Jak to jest rozwiązane w wysłannik, ładując konfigurację dynamicznie, zgodnie z pulą modeli, możesz podzielić ją na oddzielne części i nie inicjalizować ponownie części, która się nie zmieniła. Na przykład, nasłuchiwacz, którego ponowne inicjalizowanie jest kosztowne i zmienia się rzadko.
Konfiguracja wysłannik (z pliku powyżej) zawiera 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ównowagi
- grupa — grupa upstreamów z parametrami równoważącymi
- Punkt końcowy — adres instancji nadrzędnej
Każdy z tych bytów plus kilka innych może być wypełniany dynamicznie, w tym celu adres usługi, z której zostanie odebrana konfiguracja, jest określony w konfiguracji. Usługa może być REST lub gRPC, preferowane jest użycie gRPC.
Usługi są nazwane odpowiednio: LDS, VHDS, RDS, CDS i EDS. Możliwe jest łączenie konfiguracji statycznej i dynamicznej, z ograniczeniem, że zasób dynamiczny nie może być określony w zasobie statycznym.
Do większości zadań wystarczy wdrożenie trzech ostatnich usług, nazywanych ADS (Aggregated Discovery Service), and go ma gotową implementację płaszczyzny danych gRPC, w której wystarczy tylko wypełnić obiekty ze źródła.
Konfiguracja wygląda następująco:
dynamiczna konfiguracja 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: 6565Podczas uruchamiania wysłannik z tą konfiguracją połączy się z płaszczyzną sterowania i spróbuje zażądać konfiguracji RDS, CDS i EDS. Opisano, jak przebiega proces interakcji .
Krótko mówiąc, wysłannik wysyła żądanie, wskazując typ żądanego zasobu, wersję i parametry węzła. W odpowiedzi otrzymuje zasób i wersję; jeśli wersja na płaszczyźnie sterowania nie uległa zmianie, nie odpowiada.
Istnieją 4 możliwości interakcji:
- Jeden strumień gRPC dla wszystkich typów zasobów. Wysyłany jest pełny stan zasobu.
- Oddzielne strumienie, stan kompletny.
- Jeden strumień, stan przyrostowy.
- Oddzielne strumienie, stan przyrostowy.
Przyrostowy xDS pozwala na zmniejszenie ruchu pomiędzy płaszczyzną sterowania a wysłannik, jest to istotne dla dużych konfiguracji. Ale komplikuje interakcję, żądanie przesyła listę zasobów do anulowania subskrypcji i subskrypcji.
W naszym przykładzie używamy ADS - jednego strumienia dla RDS, CDS, EDS i trybu nieinkrementalnego. Aby włączyć tryb inkrementalny, należy określić api_type: DELTA_GRPC
Ponieważ żądanie zawiera parametry węzła, możemy wysłać różne zasoby do płaszczyzny sterowania dla różnych instancji. wysłannik, jest to wygodne przy budowaniu siatki usług.
Rozgrzewka
Na wysłannik podczas uruchamiania lub po otrzymaniu nowej konfiguracji z płaszczyzny sterowania uruchamiany jest proces rozgrzewania zasobów. Jest on podzielony na rozgrzewanie słuchacza i rozgrzewanie klastra. Pierwszy uruchamiany jest, gdy zachodzą zmiany w RDS/LDS, drugi, gdy zachodzą zmiany w CDS/EDS. Oznacza to, że jeśli zmieniają się tylko strumienie nadrzędne, słuchacz nie jest tworzony ponownie.
Podczas rozgrzewki, zasoby zależne z płaszczyzny sterowania są oczekiwane podczas limitu czasu. Jeśli limit czasu zostanie osiągnięty, inicjalizacja nie powiedzie się, nowy nasłuchujący nie rozpocznie nasłuchiwania portu.
Kolejność inicjalizacji: EDS, CDS, aktywna kontrola kondycji, RDS, LDS. Przy włączonej aktywnej kontroli kondycji ruch będzie kierowany w górę strumienia dopiero po jednej udanej kontroli kondycji.
Jeśli obiekt nasłuchujący zostanie utworzony ponownie, stary przejdzie 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
