Здравейте! Това е кратка статия, отговаряща на въпросите: "какво е envoy?", "защо е необходим?" и "от къде да започнем?".
Какво е това
Envoy е L4-L7 балансировач, написан на C++, насочен към висока производителност и наличност. От една страна, той е подобен на nginx и haproxy, съизмерим с тях по производителност. От друга страна, е повече ориентиран към микросервисна архитектура и предлага функции, които не отстъпват на балансировачите на java и go, като zuul или traefik.
Таблица за сравнение на haproxy/nginx/envoy, която не претендира за абсолютна истина, но дава общо представа.
nginx
haproxy
envoy
traefik
звезди в github
11.2k/огледало
1.1k/огледало
12.4k
27.6k
написан на
C
C
C++
go
API
недостъпен
само сокет/пуш
dataplane/пул
pull
активен healthcheck
недостъпен
да
да
да
Open tracing
външен плъгин
недостъпен
да
да
JWT
външен плъгин
недостъпен
да
недостъпен
Разширение
Lua/C
Lua/C
Lua/C++
недостъпен
Защо
Това е млад проект, в него няма много функции, нещо е в ранна алфа. Но envoy, включително и благодарение на младостта, бързо се развива и вече има много интересни възможности: динамична конфигурация, много готови филтри, прост интерфейс за създаване на собствени филтри.
Това определя сферата на приложение, но за начало две антипатерна:
- Предаване на статични файлове.
Факт е, че в момента в envoy няма поддръжка за кеширане. Хората от google се опитват да . Идеята е веднъж да се реализира в на envoy всички тънкости (зоопарк заглавия) на съответствието с RFC, а за конкретни реализации да се създаде интерфейс. Но засега това дори не е алфа, архитектурата е в обсъждане, отворен (докато пишех статията, PR беше вмерзен, но този пункт все още е актуален).
А засега използвайте nginx за статични файлове.
- Статична конфигурация.
Можете да я използвате, но envoy не е създадена за това. Възможностите в статичната конфигурация няма да се разкрият. Има много моменти:
Редактирайки конфигурацията в yaml, ще имате грешки, ще ругаете разработчиците за многословие и ще си мислите, че конфигурациите на nginx/haproxy, макар и по-малко структурирани, са по-лаконични. В това е същността. Конфигурацията на Nginx и Haproxy е изработена за ръчно редактиране, а в envoy е създадена за генериране от код. Цялата конфигурация е описана в , генерирайки я от proto файлове, е много по-трудно да се сбърка.
Сценарии за canary, b/g деплой и много други, се реализират нормално само в динамичната конфигурация. Не казвам, че не може да се направи в статична, ние всичко това правим. Но за това е нужно да се увират в костилки, във всеки от балансировачите, включително. envoy в това число.
Задачи, в които Envoy е незаменим:
- Балансировката на трафика в сложни и динамични системи. Тук попада service mesh, но не е задължително само той.
- Необходимостта от функционалността на разпределеното проследяване, сложната авторизация или друго, което е налично в envoy из коробки или удобно реализируемо, а в nginx/haproxy е нужно да се обгърне с lua и съмнителни плъгини.
И двете трябва да осигурят висока производителност, ако е необходимо.
Как работи това
Envoy се разпространява в бинарници единствено като docker образ. В образа вече има примерна статична конфигурация. Но ни интересува само за разбиране на структурата.
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
# Коментар към следния ред, за да се тестват мрежи v6
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Динамична конфигурация
Коя проблема търсим да решим? Не може просто да се рестартира конфигурацията на балансировчика под натоварване, ще възникнат "малки" проблеми:
- Валидация на конфигурацията.
Конфигурацията може да е голяма, може да бъде много голяма, ако я презаредим изцяло, шансовете за грешка на някое място се увеличават.
- Дългоживеещи връзки.
При инициализиране на нов слушател, трябва да се погрижим за връзките, работещи на стария, ако промените се случват често и има дългоживеещи връзки, ще се наложи да намерим компромис. Здравей, kubernetes ingress на nginx.
- Активни хелсчеки.
Ако имаме активни хелсчеки, трябва да ги проверим всички на новата конфигурация преди да изпратим трафика. Ако има много upstream-и, това изисква време. Здравей, haproxy.
Как се решава в envoy, зареждайки конфигурацията динамично, по модел на пул, може да я разделите на отделни части и да не пренастройвате онази част, която не се е променила. Например, слушателя, който е скъп за пренастройване, а се променя рядко.
Конфигурация envoy (от горния файл) има следните entidades:
- listener — слушател, който е свързан на определен ip/порт
- virtual host — виртуален хост по име на домейн
- route — правило за балансировка
- cluster — група от upstream-и с параметри за балансировка
- endpoint — адрес на инстанса на upstream
Всяка от тези сущности плюс някои други могат да бъдат заредени динамично, за това в конфигурацията се посочва адреса на услугата, от която ще бъде получена конфигурацията. Услугата може да бъде REST или gRPC, за предпочитане е да се използва gRPC.
Услугите се наричат съответно: LDS, VHDS, RDS, CDS и EDS. Може да се комбинира статична и динамична конфигурация, с ограничение, че динамичният ресурс не може да бъде посочен в статичния.
За повечето задачи е достатъчно да реализирате последните три услуги, които се наричат ADS (Aggregated Discovery Service), за и go има готова имплементация на gRPC dataplane, в която е достатъчно само да запълните обектите от собствения си източник.
Конфигурацията придобива следния вид:
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При стартиране envoy с тази конфигурация, той ще се свърже с control-plane и ще се опита да запита конфигурацията RDS, CDS и EDS. Как протича взаимодействието е описано .
Ако накратко, envoy изпраща заявка, указвайки типа на искания ресурс, версия и параметри на нодата. В отговор получава ресурса и версията, ако на control-plane версията не е променена, той не отговаря.
Има 4 варианта на взаимодействие:
- Един gRPC стрийм за всички типове ресурси, изпраща се пълното състояние на ресурса.
- Разделени потоци, пълно състояние.
- Един поток, инкрементално състояние.
- Разделени потоци, инкрементално състояние.
Инкременталният xDS позволява да се намали трафикът между контролния план и envoy, това е актуално за големи конфигурации. Но усложнява взаимодействието, в заявката се предава списък с ресурси за отписване и абонамент.
В нашия пример се използва ADS – един поток за RDS, CDS, EDS и неинкрементален режим. За да включите инкременталния режим, трябва да зададете api_type: DELTA_GRPC
Тъй като в заявката има параметри на нодата, можем на контролния план да изпращаме различни ресурси за различни инстанции envoy, което е удобно за изграждане на service mesh.
Затопляне
На envoy при стартиране или при получаване на нова конфигурация от контролния план започва процесът на затопляне на ресурсите. Той е разделен на затопляне на слушателя и затопляне на клъстера. Първото се стартира при промени в RDS/LDS, второто при CDS/EDS. Това означава, че ако се променят само апстримите, слушателят не се създава отново.
В процеса на затопляне, се очакват зависими ресурси от контролния план в течение на таймаута. Ако таймаутът изтече, инициализацията няма да бъде успешна, новият слушател няма да започне да слуша порта.
Редът на инициализация: EDS, CDS, активна проверка на състоянието, RDS, LDS. При включени активни проверки на състоянието, трафикът ще премине към апстрима, само след като бъде успешен един проверка.
Ако слушателят е бил създаден отново, старият преминава в състояние DRAIN и ще бъде премахнат след закриването на всички връзки или изтичането на таймаута --drain-time-s, по подразбиране 10 минути.
Продължението следва.
Източник: habr.com
