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.
Levo moito tempo buscando unha ferramenta que axude a facer fronte a tales problemas (escribín sobre isto en Habré:
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.
Solucións
Xa hai varias implementacións deste enfoque:
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
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.
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:
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:
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 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
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 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:
Se estás a usar Elasticsearch para almacenar intervalos de rastrexo, podes usar
Como usar Netramesh
Netra pódese engadir facilmente a calquera servizo que execute calquera orquestrador. Podes ver un exemplo
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
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