¡Saludos! Este es un breve artículo que responde a las preguntas: “¿qué es un enviado?”, “¿por qué es necesario?” y "¿por dónde empezar?".
¿Qué es eso
Envoy es un equilibrador L4-L7 escrito en C++, enfocado en alto rendimiento y disponibilidad. Por un lado, esto es de alguna manera un análogo de nginx y haproxy, comparable en rendimiento a ellos. Por otro lado, está más orientado a la arquitectura de microservicios y tiene una funcionalidad no peor que la de los balanceadores de java y go, como zuul o traefik.
La tabla comparativa de haproxy/nginx/envoy no pretende ser la verdad absoluta, pero ofrece una imagen general.
nginx
haproxy
enviado
traefik
estrellas en github
11.2k/espejo
1.1k/espejo
12.4k
27.6k
escrito en
C
C
C + +
go
API
no
solo enchufe/empuje
plano de datos/tirar
recogida
control de salud activo
no
sí
sí
sí
rastreo abierto
complemento externo
no
sí
sí
JWT
complemento externo
no
sí
no
extensión
Lua/C
Lua/C
Lua/C++
no
¿Por qué
Este es un proyecto joven, faltan muchas cosas, algunas en fase alfa temprana. Pero enviado, también debido a su juventud, se está desarrollando rápidamente y ya tiene muchas características interesantes: configuración dinámica, muchos filtros listos para usar, una interfaz simple para escribir sus propios filtros.
De esto se desprenden áreas de aplicación, pero primero hay 2 antipatrones:
- Retroceso estático.
El caso es que en este momento en enviado sin soporte de almacenamiento en caché. Los chicos de Google están intentando esto.
Por ahora, use nginx para estática.
- Configuración estática.
Puedes usarlo, pero enviado Para eso no fue creado. Las funciones en una configuración estática no estarán expuestas. Hay muchos momentos:
Al editar la configuración en yaml, se equivocará, regañará a los desarrolladores por su verbosidad y pensará que las configuraciones de nginx/haproxy, aunque menos estructuradas, son más concisas. Ese es el punto. La configuración de Nginx y Haproxy se creó para editarla a mano y enviado para generación a partir de código. Toda la configuración se describe en
Los escenarios de implementación Canary, b/g y mucho más normalmente se implementan solo en una configuración dinámica. No digo que esto no se pueda hacer de forma estática, lo hacemos todos. Pero para ello es necesario ponerse muletas, en cualquiera de los equilibradores, en enviado incluyendo
Tareas para las que Envoy es indispensable:
- Equilibrio de tráfico en sistemas complejos y dinámicos. Esto incluye la malla de servicios, pero no necesariamente es la única.
- La necesidad de una funcionalidad de seguimiento distribuido, una autorización compleja u otra funcionalidad que esté disponible en enviado listo para usar o implementado convenientemente, pero en nginx/haproxy necesita estar rodeado de lua y complementos dudosos.
Ambos, si es necesario, proporcionan un alto rendimiento.
¿Cómo funciona esto
Envoy se distribuye en binarios solo como una imagen acoplable. La imagen ya contiene un ejemplo de una configuración estática. Pero sólo nos interesa para comprender la estructura.
configuración estática de enviado.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
Configuración dinámica
¿A qué problema buscamos solución? No puedes simplemente recargar la configuración del balanceador de carga bajo carga; surgirán "pequeños" problemas:
- Validación de configuración.
La configuración puede ser grande, puede ser muy grande, si la sobrecargamos toda a la vez, aumentan las posibilidades de que se produzca un error en alguna parte.
- Conexiones duraderas.
Al inicializar un nuevo oyente, debe cuidar las conexiones que se ejecutan en el antiguo; si se producen cambios con frecuencia y hay conexiones de larga duración, tendrá que buscar un compromiso. Hola, ingreso de kubernetes en nginx.
- Controles de salud activos.
Si tenemos comprobaciones de estado activas, debemos verificarlas todas en la nueva configuración antes de enviar tráfico. Si hay muchos flujos ascendentes, esto lleva tiempo. Hola haproxy.
¿Cómo se resuelve esto en enviadoAl cargar la configuración dinámicamente, según el modelo del grupo, puede dividirla en partes separadas y no reinicializar la parte que no ha cambiado. Por ejemplo, un oyente, cuyo reinicio es costoso y rara vez cambia.
Configuración enviado (del archivo anterior) tiene las siguientes entidades:
- oyente — oyente colgado en una IP/puerto específico
- anfitrión virtual - host virtual por nombre de dominio
- ruta - regla de equilibrio
- grupo — un grupo de aguas arriba con parámetros de equilibrio
- punto final — dirección de instancia ascendente
Cada una de estas entidades más algunas otras se pueden completar dinámicamente; para esto, la configuración especifica la dirección del servicio desde donde se recibirá la configuración. El servicio puede ser REST o gRPC, es preferible gRPC.
Los servicios se denominan respectivamente: LDS, VHDS, RDS, CDS y EDS. Puede combinar configuración estática y dinámica, con la limitación de que no se puede especificar un recurso dinámico en uno estático.
Para la mayoría de las tareas, basta con implementar los últimos tres servicios, se denominan ADS (Aggregated Discovery Service), para
La configuración toma la siguiente forma:
configuración dinámica de enviado.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
Cuando se ejecuta enviado con esta configuración, se conectará al plano de control e intentará solicitar la configuración de RDS, CDS y EDS. Se describe cómo ocurre el proceso de interacción.
En resumen enviado envía una solicitud indicando el tipo de recurso que se solicita, la versión y los parámetros del nodo. En respuesta, recibe un recurso y una versión; si la versión en el plano de control no ha cambiado, no responde.
Hay 4 opciones de interacción:
- Una secuencia gRPC para todos los tipos de recursos, se envía el estado completo del recurso.
- Arroyos separados, pleno estado.
- Una corriente, estado incremental.
- Corrientes separadas, estado incremental.
xDS incremental le permite reducir el tráfico entre el plano de control y enviado, esto es relevante para configuraciones grandes. Pero complica la interacción: la solicitud contiene una lista de recursos para darse de baja y suscribirse.
Nuestro ejemplo utiliza ADS: una secuencia para RDS, CDS, EDS y modo no incremental. Para habilitar el modo incremental, debe especificar api_type: DELTA_GRPC
Dado que la solicitud contiene parámetros de nodo, podemos enviar diferentes recursos al plano de control para diferentes instancias. enviado, esto es conveniente para construir una malla de servicios.
Calentar
En enviado Al inicio o al recibir una nueva configuración del plano de control, se inicia el proceso de calentamiento de recursos. Se divide en calentamiento del oyente y calentamiento del grupo. El primero se lanza cuando hay cambios en RDS/LDS, el segundo cuando hay cambios en CDS/EDS. Esto significa que si solo cambian las aguas arriba, el oyente no se vuelve a crear.
Durante el proceso de calentamiento, se esperan recursos dependientes del plano de control durante el tiempo de espera. Si se agota el tiempo de espera, la inicialización no será exitosa y el nuevo oyente no comenzará a escuchar en el puerto.
Orden de inicialización: EDS, CDS, control de salud activo, RDS, LDS. Con las comprobaciones de estado activas habilitadas, el tráfico aumentará solo después de una verificación de estado exitosa.
Si se volvió a crear el oyente, el anterior pasa al estado DRENAR y se eliminará después de que se cierren todas las conexiones o expire el tiempo de espera. --drain-time-s
, por defecto 10 minutos.
Esta historia continuará.
Fuente: habr.com