Así que recolles métricas. Como somos. Tamén recollemos métricas. Por suposto, necesario para o negocio. Hoxe falaremos da primeira ligazón do noso sistema de monitorización: un servidor de agregación compatible con statsd
Dos nosos artigos anteriores (
Reclamación 1. Github, o desenvolvedor do proxecto, deixou de apoialo: publicando parches e correccións, aceptando o noso e (non só o noso) PR. Nos últimos meses (algún lugar de febreiro a marzo de 2018), a actividade retomouse, pero antes había case 2 anos de total calma. Ademais, o proxecto estase a desenvolver
Reclamación 2. Exactitude dos cálculos. Brubeck recolle un total de 65536 valores para a agregación. No noso caso, para algunhas métricas, durante o período de agregación (30 segundos), poden chegar moitos máis valores (1 no pico). Como resultado desta mostraxe, os valores máximos e mínimos parecen inútiles. Por exemplo, así:
Como foi
Como debería ser
Polo mesmo motivo, as cantidades adoitan calcularse incorrectamente. Engade aquí un erro cun desbordamento flotante de 32 bits, que xeralmente envía o servidor a un fallo secundario cando recibe unha métrica aparentemente inocente, e todo se fai xenial. O erro, por certo, non foi corrixido.
E, finalmente, Reclamación X. No momento de escribir este artigo, estamos preparados para presentalo ás 14 implementacións de statsd máis ou menos funcionantes que puidemos atopar. Imaxinemos que unha única infraestrutura medrou tanto que aceptar 4 millóns de MPS xa non é suficiente. Ou aínda que aínda non medrou, pero as métricas xa son tan importantes para ti que incluso baixas curtas de 2-3 minutos nos gráficos xa poden chegar a ser críticas e provocar ataques de depresión insuperable entre os xestores. Dado que tratar a depresión é unha tarefa ingrata, son necesarias solucións técnicas.
En primeiro lugar, a tolerancia ás fallas, para que un problema repentino no servidor non provoque un apocalipse psiquiátrico zombie na oficina. En segundo lugar, escalar para poder aceptar máis de 4 millóns de MPS, sen afondar na pila de rede de Linux e crecer con calma "en amplitude" ata o tamaño necesario.
Como tiñamos espazo para escalar, decidimos comezar coa tolerancia a fallos. "Sobre! Tolerancia a fallos! É sinxelo, podemos facelo", pensamos e lanzamos 2 servidores, levantando unha copia de brubeck en cada un. Para iso, tivemos que copiar o tráfico con métricas a ambos os servidores e mesmo escribir para iso
Se pensas un pouco sobre o problema e ao mesmo tempo desenterras a neve cunha pa, entón podes vir a túa mente a seguinte idea obvia: necesitas un statsd que poida funcionar en modo distribuído. É dicir, aquel que implementa a sincronización entre nodos en tempo e métricas. "Por suposto, tal solución probablemente xa exista", dixemos e fomos a Google... E non atoparon nada. Despois de revisar a documentación de diferentes estatísticas (
E entón lembramos sobre o "xoguete" statsd - bioyino, que foi escrito no hackathon Just for Fun (o nome do proxecto foi xerado polo guión antes do inicio do hackathon) e decatámonos de que necesitabamos urxentemente as nosas propias estatísticas. Para qué?
- porque hai moi poucos clons de estatísticas no mundo,
- porque é posible proporcionar a tolerancia a fallos e escalabilidade desexadas ou próximas á desexada (incluída a sincronización de métricas agregadas entre servidores e a resolución do problema do envío de conflitos),
- porque é posible calcular métricas con máis precisión que Brubeck,
- porque pode recoller estatísticas máis detalladas, que Brubeck practicamente non nos proporcionou,
- porque tiven a oportunidade de programar a miña propia aplicación a escala distribuída de hiperperformance, que non repetirá completamente a arquitectura doutra hiperperformance similar para... ben, iso é todo.
En que escribir? Por suposto, en Rust. Por que?
- porque xa había un prototipo de solución,
- porque o autor do artigo xa coñecía a Rust nese momento e estaba ansioso por escribir algo nel para a súa produción coa oportunidade de poñelo en código aberto,
- porque os idiomas con GC non son axeitados para nós debido á natureza do tráfico recibido (case en tempo real) e as pausas GC son practicamente inaceptables,
- porque necesitas un rendemento máximo comparable ao C
- porque Rust ofrécenos simultaneidade sen medo, e se comezamos a escribilo en C/C++, teríamos aínda máis vulnerabilidades, desbordamentos de búfer, condicións de carreira e outras palabras de medo que brubeck.
Tamén houbo un argumento contra Rust. A empresa non tiña experiencia na creación de proxectos en Rust, e agora tampouco pensamos usalo no proxecto principal. Polo tanto, había serios temores de que nada funcionase, pero decidimos arriscar e intentámolo.
O tempo pasou...
Finalmente, despois de varios intentos fallidos, a primeira versión de traballo estaba lista. Que pasou? Isto foi o que pasou.
Cada nodo recibe o seu propio conxunto de métricas e acumúlaas, e non agrega métricas para aqueles tipos onde o seu conxunto completo é necesario para a agregación final. Os nodos están conectados entre si por algún tipo de protocolo de bloqueo distribuído, que permite seleccionar entre eles o único (aquí choramos) que é digno de enviar métricas ao Grande. Este problema está sendo resolto actualmente por
Os paquetes UDP con métricas están desequilibrados entre os nodos dos equipos de rede mediante un simple Round Robin. Por suposto, o hardware da rede non analiza o contido dos paquetes e, polo tanto, pode extraer moito máis de 4 millóns de paquetes por segundo, sen esquecer métricas das que non sabe nada. Se temos en conta que as métricas non veñen unha por vez en cada paquete, non prevemos ningún problema de rendemento neste lugar. Se un servidor falla, o dispositivo de rede detecta este feito rapidamente (dentro de 1-2 segundos) e elimina da rotación o servidor accidentado. Como resultado diso, os nós pasivos (é dicir, que non son líderes) pódense activar e desactivar practicamente sen notar caídas nos gráficos. O máximo que perdemos é parte das métricas que entraron no último segundo. Unha perda/apagada/cambio repentinos dun líder aínda creará unha pequena anomalía (o intervalo de 30 segundos aínda está dessincronizado), pero se hai comunicación entre os nodos, estes problemas pódense minimizar, por exemplo, enviando paquetes de sincronización. .
Un pouco sobre a estrutura interna. A aplicación é, por suposto, multiproceso, pero a arquitectura de fíos é diferente da usada en Brubeck. Os fíos de brubeck son os mesmos: cada un deles é responsable tanto da recollida de información como da agregación. En bioyino, os traballadores divídense en dous grupos: os responsables da rede e os responsables da agregación. Esta división permítelle xestionar a aplicación de forma máis flexible dependendo do tipo de métricas: onde se require unha agregación intensiva, pode engadir agregadores, onde hai moito tráfico de rede, pode engadir o número de fluxos de rede. Neste momento, nos nosos servidores traballamos en 8 fluxos de rede e 4 de agregación.
A parte do reconto (responsable da agregación) é bastante aburrida. Os búfers enchidos por fluxos de rede distribúense entre os fluxos de reconto, onde posteriormente son analizados e agregados. A solicitude, ofrécense métricas para enviar a outros nodos. Todo isto, incluído o envío de datos entre nodos e o traballo con Consul, realízase de forma asíncrona, executándose no marco.
Moitos máis problemas durante o desenvolvemento foron causados pola parte da rede responsable de recibir métricas. O obxectivo principal de separar os fluxos de rede en entidades separadas era o desexo de reducir o tempo que pasa un fluxo non para ler datos do socket. As opcións que usaban UDP asíncrono e recvmsg regulares desapareceron rapidamente: a primeira consome demasiado espazo de CPU para o procesamento de eventos, a segunda require demasiados cambios de contexto. Polo tanto, agora úsase
Nota
Na configuración predeterminada, o tamaño do búfer está configurado para ser bastante grande. Se de súpeto decides probar o servidor ti mesmo, podes atoparte co feito de que despois de enviar un pequeno número de métricas, estas non chegarán en Graphite, permanecendo no búfer de fluxo de rede. Para traballar cun pequeno número de métricas, cómpre configurar o tamaño da cola de tarefas e o tamaño da cola de tarefas en valores máis pequenos na configuración.
Para rematar, algúns gráficos para os amantes das cartas.
Estatísticas sobre o número de métricas de entrada para cada servidor: máis de 2 millóns de MPS.
Desactivando un dos nós e redistribuíndo as métricas entrantes.
Estatísticas sobre as métricas de saída: un só nodo sempre envía: o xefe da incursión.
Estatísticas do funcionamento de cada nodo, tendo en conta os erros en varios módulos do sistema.
Detalle das métricas entrantes (os nomes das métricas están ocultos).
Que pensamos facer a continuación con todo isto? Por suposto, escribe código, carallo...! O proxecto foi orixinalmente planeado para ser de código aberto e seguirá sendo así ao longo da súa vida. Os nosos plans inmediatos inclúen cambiar á nosa propia versión de Raft, cambiar o protocolo par a outro máis portátil, introducir estatísticas internas adicionais, novos tipos de métricas, corrección de erros e outras melloras.
Por suposto, todos poden axudar no desenvolvemento do proxecto: crear PR, Problemas, se é posible responderemos, melloraremos, etc.
Dito isto, iso é todo, cómpre os nosos elefantes!
Fonte: www.habr.com