Netramesh - solución lixeira de malla de servizo

A medida que pasamos dunha aplicación monolítica a unha arquitectura de microservizos, afrontamos novos retos.

Nunha aplicación monolítica, adoita ser bastante sinxelo determinar en que parte do sistema se produciu o erro. O máis probable é que o problema estea no propio código do monolito ou na base de datos. Pero cando comezamos a buscar un problema nunha arquitectura de microservizos, todo xa non é tan obvio. Necesitamos atopar o camiño completo que tomou a solicitude de principio a fin e seleccionalo entre centos de microservizos. Ademais, moitos deles tamén teñen as súas propias instalacións de almacenamento, o que tamén pode causar erros lóxicos, así como problemas de rendemento e tolerancia a fallos.

Netramesh - solución lixeira de malla de servizo

Levo moito tempo buscando unha ferramenta que axude a facer fronte a tales problemas (escribín sobre isto en Habré: 1, 2), pero ao final fixen a miña propia solución de código aberto. Neste artigo falo dos beneficios do enfoque de malla de servizo e comparto unha nova ferramenta para a súa implementación.

O rastrexo distribuído é unha solución común ao problema de atopar erros en sistemas distribuídos. Pero que pasa se este enfoque para recoller información sobre as interaccións de rede aínda non foi implementado no sistema, ou, peor aínda, en parte do sistema xa funciona correctamente, pero en parte non, xa que non foi engadido aos servizos antigos. ? Para determinar a causa raíz exacta dun problema, é necesario ter unha imaxe completa do que está a suceder no sistema. É especialmente importante comprender cales son os microservizos que interveñen nas rutas clave para a empresa.

Aquí pode vir na nosa axuda o enfoque de malla de servizos, que se ocupará de toda a maquinaria de recollida de información da rede a un nivel inferior ao que operan os propios servizos. Este enfoque permítenos interceptar todo o tráfico e analizalo sobre a marcha. Ademais, as aplicacións nin sequera teñen que saber nada sobre iso.

Enfoque de malla de servizo

A idea principal do enfoque de malla de servizos é engadir outra capa de infraestrutura á rede, que nos permitirá facer calquera cousa coa interacción entre servizos. A maioría das implementacións funcionan do seguinte xeito: engádese un contedor sidecar adicional cun proxy transparente a cada microservizo, polo cal se pasa todo o tráfico entrante e saínte do servizo. E este é o mesmo lugar onde podemos facer o balance de clientes, aplicar políticas de seguridade, impoñer restricións ao número de solicitudes e recoller información importante sobre a interacción dos servizos en produción.

Netramesh - solución lixeira de malla de servizo

Solucións

Xa hai varias implementacións deste enfoque: Istio и linkerd2. Ofrecen moitas funcións fóra da caixa. Pero ao mesmo tempo, hai unha gran sobrecarga de recursos. Ademais, canto maior sexa o clúster no que este sistema opera, máis recursos serán necesarios para manter a nova infraestrutura. En Avito, operamos clusters de kubernetes que conteñen miles de instancias de servizo (e o seu número segue crecendo rapidamente). Na súa implementación actual, Istio consume ~ 300 Mb de RAM por instancia de servizo. Debido ao gran número de posibilidades, o equilibrio transparente tamén afecta ao tempo de resposta global dos servizos (ata 10 ms).

Como resultado, analizamos exactamente que capacidades necesitabamos agora mesmo e decidimos que o principal motivo polo que comezamos a implementar tales solucións era a capacidade de recoller información de rastrexo de todo o sistema de forma transparente. Tamén queriamos ter control sobre a interacción dos servizos e facer diversas manipulacións coas cabeceiras que se transfiren entre servizos.

Como resultado, chegamos á nosa decisión:  Netramesh.

Netramesh

Netramesh é unha solución lixeira de malla de servizos con capacidade de escalar infinitamente, independentemente do número de servizos no sistema.

Os obxectivos principais da nova solución eran baixos recursos xerais e alto rendemento. Entre as principais características, quixemos inmediatamente poder enviar de forma transparente tramos de trazado ao noso sistema Jaeger.

Hoxe, a maioría das solucións na nube están implementadas en Golang. E, por suposto, hai razóns para iso. Escribir aplicacións de rede en Golang que funcionen de forma asíncrona con E/S e escalan a través dos núcleos segundo sexa necesario é conveniente e bastante sinxelo. E, o que tamén é moi importante, o rendemento é suficiente para solucionar este problema. Por iso tamén escollemos Golang.

Produtividade

Centramos os nosos esforzos en acadar a máxima produtividade. Para unha solución que se desprega xunto a cada instancia do servizo, é necesario un pequeno consumo de RAM e tempo de CPU. E, por suposto, o atraso de resposta tamén debería ser pequeno.

A ver que resultados obtivemos.

RAM

Netramesh consume ~10 Mb sen tráfico e 50 Mb como máximo cunha carga de ata 10000 RPS por instancia.

O proxy Istio Envoy sempre consome ~300 Mb nos nosos clústeres con miles de instancias. Isto non permite escalalo a todo o clúster.

Netramesh - solución lixeira de malla de servizo

Netramesh - solución lixeira de malla de servizo

Con Netramesh conseguimos unha redución de ~10 veces no consumo de memoria.

CPU

O uso da CPU é relativamente igual baixo carga. Depende do número de solicitudes por unidade de tempo ao sidecar. Valores a 3000 solicitudes por segundo no pico:

Netramesh - solución lixeira de malla de servizo

Netramesh - solución lixeira de malla de servizo

Hai un punto máis importante: Netramesh: unha solución sen plano de control e sen carga non consome tempo de CPU. Con Istio, os sidecars sempre actualizan os puntos finais do servizo. Como resultado, podemos ver esta imaxe sen carga:

Netramesh - solución lixeira de malla de servizo

Usamos HTTP/1 para a comunicación entre servizos. O aumento do tempo de resposta de Istio ao enviar un proxy a través de Envoy foi de ata 5-10 ms, o que é bastante para os servizos que están preparados para responder nun milisegundo. Con Netramesh, este tempo diminuíu a 0.5-2 ms.

Escalabilidade

A pouca cantidade de recursos que consume cada proxy fai posible situalo xunto a cada servizo. Netramesh creouse intencionadamente sen un compoñente de plano de control para simplemente manter cada sidecar lixeiro. A miúdo, nas solucións de malla de servizo, o plano de control distribúe información de descubrimento de servizos a cada sidecar. Xunto con ela vén información sobre tempo de espera e configuración de equilibrio. Todo isto permíteche facer moitas cousas útiles, pero, por desgraza, aumenta o tamaño dos sidecars.

Descubrimento do servizo

Netramesh - solución lixeira de malla de servizo

Netramesh non engade ningún mecanismo adicional para o descubrimento de servizos. Todo o tráfico envíase de forma transparente mediante netra sidecar.

Netramesh admite o protocolo de aplicación HTTP/1. Para definilo, utilízase unha lista configurable de portos. Normalmente, o sistema ten varios portos a través dos cales se produce a comunicación HTTP. Por exemplo, usamos 80, 8890, 8080 para a interacción entre servizos e solicitudes externas. Neste caso, pódense configurar mediante unha variable de ambiente NETRA_HTTP_PORTS.

Se utilizas Kubernetes como orquestrador e o seu mecanismo de entidade de servizo para a comunicación dentro do clúster entre servizos, entón o mecanismo segue sendo o mesmo. En primeiro lugar, o microservizo obtén un enderezo IP de servizo mediante kube-dns e abre unha nova conexión con el. Esta conexión establécese primeiro co netra-sidecar local e todos os paquetes TCP chegan inicialmente a netra. A continuación, netra-sidecar establece unha conexión co destino orixinal. O NAT no pod IP do nodo segue sendo exactamente o mesmo que sen netra.

Rastrexo distribuído e reenvío de contexto

Netramesh ofrece a funcionalidade necesaria para enviar intervalos de rastrexo sobre as interaccións HTTP. Netra-sidecar analiza o protocolo HTTP, mide os atrasos das solicitudes e extrae a información necesaria das cabeceiras HTTP. En definitiva, obtemos todos os rastros nun único sistema Jaeger. Para unha configuración precisa, tamén pode usar as variables de ambiente proporcionadas pola biblioteca oficial biblioteca jaeger go.

Netramesh - solución lixeira de malla de servizo

Netramesh - solución lixeira de malla de servizo

Pero hai un problema. Ata que os servizos xeren e envíen un encabezado especial de uber, non veremos espazos de rastrexo conectados no sistema. E isto é o que necesitamos para atopar rapidamente a causa dos problemas. Aquí de novo Netramesh ten unha solución. Os proxies len as cabeceiras HTTP e, se non conteñen o identificador de rastrexo uber, xeran un. Netramesh tamén almacena información sobre as solicitudes entrantes e saíntes nun sidecar e as relaciona enriquecéndoas coas cabeceiras de solicitudes de saída necesarias. Todo o que tes que facer nos servizos é enviar só unha cabeceira X-Request-Id, que se pode configurar mediante unha variable de ambiente NETRA_HTTP_REQUEST_ID_HEADER_NAME. Para controlar o tamaño do contexto en Netramesh, pode establecer as seguintes variables de ambiente: NETRA_TRACING_CONTEXT_EXPIRATION_MILLISECONDS (o tempo durante o que se almacenará o contexto) e NETRA_TRACING_CONTEXT_CLEANUP_INTERVAL (frecuencia de limpeza do contexto).

Tamén é posible combinar varias rutas no seu sistema marcándoas cun token de sesión especial. Netra permítelle instalar HTTP_HEADER_TAG_MAP para converter as cabeceiras HTTP en etiquetas de trazado correspondentes. Isto pode ser especialmente útil para probas. Despois de pasar a proba funcional, podes ver que parte do sistema se viu afectada mediante o filtrado pola clave de sesión correspondente.

Determinación da fonte da solicitude

Para determinar de onde procede a solicitude, pode usar a funcionalidade de engadir automaticamente unha cabeceira coa fonte. Usando unha variable de ambiente NETRA_HTTP_X_SOURCE_HEADER_NAME Podes especificar un nome de cabeceira que se instalará automaticamente. Mediante o uso NETRA_HTTP_X_SOURCE_VALUE pode establecer o valor ao que se establecerá a cabeceira X-Source para todas as solicitudes saíntes.

Isto permite que a distribución desta cabeceira útil se distribúa uniformemente por toda a rede. Despois podes usalo nos servizos e engadilo aos rexistros e métricas.

Enrutamento de tráfico e elementos internos de Netramesh

Netramesh consta de dous compoñentes principais. O primeiro, netra-init, establece regras de rede para interceptar o tráfico. El usa regras de redirección de iptables para interceptar todo ou parte do tráfico en sidecar, que é o segundo compoñente principal de Netramesh. Pode configurar cales son os portos que se deben interceptar para as sesións TCP entrantes e saíntes: INBOUND_INTERCEPT_PORTS, OUTBOUND_INTERCEPT_PORTS.

A ferramenta tamén ten unha característica interesante: o enrutamento probabilístico. Se usa Netramesh exclusivamente para recoller intervalos de rastrexo, nun ambiente de produción pode aforrar recursos e activar o enrutamento probabilístico mediante variables. NETRA_INBOUND_PROBABILITY и NETRA_OUTBOUND_PROBABILITY (de 0 a 1). O valor predeterminado é 1 (intercéptase todo o tráfico).

Despois da interceptación exitosa, netra sidecar acepta a nova conexión e utiliza SO_ORIGINAL_DST opción de socket para obter o destino orixinal. Netra abre entón unha nova conexión ao enderezo IP orixinal e establece unha comunicación TCP bidireccional entre as partes, escoitando todo o tráfico que pasa. Se o porto se define como HTTP, Netra tenta analizalo e rastrexalo. Se a análise HTTP falla, Netra recorre a TCP e proxy os bytes de forma transparente.

Construír un gráfico de dependencia

Despois de recibir unha gran cantidade de información de rastrexo en Jaeger, quero obter un gráfico completo das interaccións no sistema. Pero se o teu sistema está bastante cargado e acumúlanse miles de millóns de espazos de rastrexo ao día, agregalos non é unha tarefa tan sinxela. Hai unha forma oficial de facelo: dependencias de faíscas. Non obstante, a creación dun gráfico completo levará horas e obrigará a descargar todo o conxunto de datos de Jaeger durante as últimas XNUMX horas.

Se estás a usar Elasticsearch para almacenar intervalos de rastrexo, podes usar unha sinxela utilidade Golang, que creará o mesmo gráfico en minutos utilizando as funcións e capacidades de Elasticsearch.

Netramesh - solución lixeira de malla de servizo

Como usar Netramesh

Netra pódese engadir facilmente a calquera servizo que execute calquera orquestrador. Podes ver un exemplo aquí.

Polo momento, Netra non ten a capacidade de implementar automaticamente sidecars para os servizos, pero hai plans de implementación.

O futuro de Netramesh

O obxectivo principal Netramesh é acadar uns custos de recursos mínimos e un alto rendemento, proporcionando capacidades básicas para a observabilidade e o control da comunicación entre servizos.

No futuro, Netramesh admitirá outros protocolos de capa de aplicación ademais de HTTP. O enrutamento L7 estará dispoñible nun futuro próximo.

Use Netramesh se atopa problemas similares e escríbanos con preguntas e suxestións.

Fonte: www.habr.com

Engadir un comentario