 Olá, meu nome é Guilherme Hermeto e esse talk é Observing Node.js usando Metrics para melhorar a aplicação de performance. Há muitas formas de melhorar a aplicação de performance. A única forma que a gente se concentra aqui hoje em este talk é como usar Metrics para entender como o seu código impacta a sua saúde de aplicação e como você pode criar um loop de feedback para evoluir o seu código e criar melhores aplicações. Antes de começar, vamos introduz-me. Eu sou um engenheiro de plataforma CINU, com a aplicação Node.js e Netflix. A gente joga uma aplicação Node.js que empurra as aplicações de usuários e interfaces e a UI para o trabalho de produção de conteúdo. Para qualquer aplicação, a gente joga canérias e veja Metrics para garantir que a aplicação permaneça healthy. E por isso, tenho muita experiência usando o que eu chamo Metrics Driven Development para constantemente evoluir o meu código e não ter um impacto negativo na aplicação de Metrics. Isso cria um loop de feedback. Você wrote o código, você joga um load ou um canário, você guarda o Metrics, depois você analisa e avala se você precisa começar. E isso deveria funcionar por qualquer língua. O Metrics que você veja será diferente, mas o processo é o mesmo. Bem, é fácil para mim dizer, usar o Metrics. Mas quais são? Há tantos deles. E, para ser honesto, não é imediatamente obvio como usar o Metrics. E, muitas vezes, você precisa usar uma combinação de duas ou mais Metrics para entender o que você vai fazer com a sua aplicação de saúde. Vamos começar a introduzir você para seu melhor amigo, o processo de utilização de CPU. É o primeiro indicador da aplicação de saúde porque é uma métrica sensível. A utilização de CPUs pode ser causada por muitos patólogos. O sincrono é chamado de bloquear o loop de evento, o processo de restart, isso é interessante. Quando o processo de restart, geralmente spica o CPU. Então, olhando em uma charta de seu fleet e vendo um high-CPU, isso pode significar que algumas das instâncias poderiam ser restartadas. Ele pode também ter pressão para o coletor. Se o scavenger está trabalhando muito por algum motivo, talvez um raio de promoção, o usage de CPU vai aumentar. O loop de evento liga. Pode indicar que há um aumento de círculo sincrono sendo executado. Não é a mais fácil de analisar a charta. Então, é por isso que usamos a utilização de CPU de utilização de utilização. Isso facilita o digesto. Se essas chartas começam a se mover no Y-axis, ela será de maiores novos. Isso significa que você vai mais ou menos para o próximo loop de evento. Isso também significa que a raiva de sucesso vai desbastecar. A utilização de heap, o bom ou o heap. Se ela está crescendo no Y-axis, isso significa que você provavelmente tem uma leak de memória. Normalmente, isso faz um tempo para manifestar, então não é tão fácil de achar Apesar de monitorar e alertar metricks. E entendemos a questão que causou a charta, que você vê agora na sua screen, em alguns minutos. Request Rate. Isso é tudo sobre quantas regras muitas regras sua app pode receber em um período de tempo. Bem, não é surpresa que gostaríamos de bugging em um segundo intervalo, que nos dê regras por segundo, ou RPS. Você pode também usar labels ou tags, como status codes ou paths. Isso nos permitirá filtrar ou criar regras por aquele given label. Então, como exemplo, podemos ver quantas regras são retornadas, quantas regras são retornadas, quantas regras são retornadas, quantas regras são retornadas, e quantas regras são retornadas, e quantas regras são retornadas. É importante ver que essa regras também afecta a utilização de CPU. Um aumento em essa regras significa um aumento na utilização de CPU. E isso é esperado. Mais regras significa que você vai precisar mais de CPU. E porque é direto relacionado, isso significa que, para receber mais regras, você vai precisar mais de CPU. Isso significa que, eventualmente, você vai precisar mais de instâncias. Regras latens. Bem, isso é uma boa. Então, muitas pessoas pensam imediatamente sobre essa regras, quando falamos sobre a performance de aplicação. Isso é o que elas entendem sobre a performance de aplicação. O que essa regras vai dizer é quanto tempo as regras estão tomando. Que, eventualmente, pode transmitir quanto tempo os seus clientes estão esperando. É importante que essa regras esteja empurrada em centímetros, porque você quer saber quanto tempo os seus regras average estão tomando e quanto tempo os seus regras longas estão tomando. O que é o 99% do 99.9% que você quer saber sobre o outlier. Inflator. Isso é um interessante. Então, essa regras measures como muitas regras concorrentes as suas regras estão tomando. Não como muitas regras as suas regras estão tomando. Regras sendo tomadas, as regras que têm sido recebidas, que estão tomadas e que estão tomadas pela sua aplicação. É também muito útil uma regras para indicar quando você tem um regras ou um leak. Porque se você faz, isso significa que a sua aplicação não pode ser enviada a respostas para o usuário, o que significa que os regras eventualmente estão tomando tempo. O processo começa. Ah, não há controversias nisso. Se a sua aplicação está tomando, você precisa saber sobre isso. É muito fácil ver isso e saber que você tem um bug na sua cota. Mas não sempre é um bug. Então, para o bug e as regras, você tem que resortar os tools diagnósticos, como log, tracing e até analisar os quadrões. Você vai pensar, wow, isso é ótimo. Eu aprendi muito. Mas agora o que? Agora eu vou mostrar alguns exemplos no caso real que eu vi na produção e vou mostrar para você como podem afetar suas métricas. Eu criei uma aplicação simples usando apenas software open-source que você pode encontrar no GitHub. É o repo que você vê lá no seu screen. Tem um script que pode ser setado para Prometheus, Grafana e Postgres usando o desktop docker. Ok, então vamos fazer isso. O primeiro exemplo vai mostrar para você como identificar problemas de performance não são causados por um bug ou per se. Mas com um style de coding que não pode ser setado para Node.js mesmo que seja bem para outras línguas, não é para Node. E não cresce o app, é só muito ineficiente. Esse é o nosso file ralt-handler e nesse file temos uma classe que tem um builder estético e retorna um builder class aqui. Esse builder class é um builder class que você veria em uma língua como Java que tem metades chenable e um build method e eventualmente retorna um percentile preconfigurado. E aqui embaixo temos esse ralt-handler que usa o builder para construir esse percentile e eventualmente usa o percentile e finalmente retorna ok. Agora, se você olhar os charts para o metrics ok quando eu começo a testar eu started um baseline sendo load com 4k request esse ralt-baseline é um echo que retorna os request headers e você pode ver que é muito stabilizante. Aqui, nesse local eu começo o call para esse particular endpoint e você pode ver que eu added um pouco mais do 10% quando eu load eu added 10% e você pode ver um pouco mais aqui mas você pode ver um 25% crescimento de CPU não sabemos se isso é resumido ou não porque se você tem um ralt-handler que não faz nada você pode ter mais CPU então você realmente não sabe se isso é certo ou não isso é resumido ou não nesse particular ponto você pode ver aqui que a lateness é stabilizante tudo certo então isso não é um problema você vê que você tem mais event loop lag mas é esperto que se você incri a dcp você usa um code sincrono você é esperto ter um incri no event loop lag aqui você também vê que você pode trair o heap bastante horizontal não devia muito mesmo com os requestes de flight você tem um pouco de bump aqui é normal, não é nada se você olhar o scavenger, o minor gc você vê que ele kind of follows o request rate então isso é esperto certo ir aqui o que eu fiz foi ok, então 10% bom, vamos ver o que acontece se eu mudou todo o trafico todo o load que aconteceu na base para esse ponto é o que eu fiz aqui tinha um 60% incri no cpu neste ponto do original base 1 e você vê aqui nada realmente muda em qualquer lugar ok, então vamos voltar então aqui eu fiz um pequeno change é o exacto mesmo cold que o outro trouxe o outro fio mas neste caso eu defini o builder como um top level e você vê aqui que eu retornei o builder o builder referência o pessoal o builder referência e isso é ok temos este gather aqui e você vê que é o exacto mesmo route handler neste ponto aqui eu mudei o trafico para este novo ponto então neste ponto 100% do trafico começam a ir para o novo ponto onde a classe é definida e você vê aqui que se você average este, vai ser um 5% incri 4% incri 5% sobre o original em vez de um 60% incri é um muito significativo e a performance pode mostrar que se você se encroca de uma maneira que é bonita para um Node.js você vai precisar ter as suas issueis de performance neste caso eu tenho um clínio contraversal clínico fete um gato grandeeless de uma repo de GitHub e ele sinta cada vez em vez de um requerimento, certo? Vamos com isso por agora. Então, se você olha aqui, isso é, de novo, a mesma base que eu tinha antes. Eu chamava o Equoroute, que é apenas dentro dos pedaços ricos, e aqui eu comecei a chamar isso. Você pode ver que, imediatamente, a CPU começa a agir, e vai para 150, e isso é o que o topo está mostrando. Você pode ver que o Event Loop Black, ele cresce, o número de requerimentos, você vê aqui, ele decreases, e você vê aqui, é um bom exemplo, que mostra que a 99.9% começa a agir e depois agir a 99.9%. E se o processo não tinha crescido, neste ponto aqui, que é um crescimento, que é, na verdade, o que foi irresponsável, mas se isso aconteceu, você veria que a 95% iria crescer, e depois você veria que a 75% iria crescer. Mas, neste caso aqui, ele apenas se tornou responsável e cresceu. Então, você vê aqui que o Usage HIP é muito maior do que antes, e porque os requerimentos ficam mais longos, então os requerimentos ficam crescendo. Você também vê grandes pontos de bumbum, mas isso está completamente em linha com o Usage CPU. Então, isso é para mostrar você como a Starvation CPU vai causar problemas. Se a sua instância não responde, ela coloca muito mais pressão no outro instante, no fleet, e assim e assim, e isso se torna um bumbum, né? Então, se você quer fixar isso, e esse é meio obvio, então se você quer fixar isso, você não quer chamar isso a cada vez que no Request Life cycle, o JSON é estatico, não vai mudar, e vamos supor que isso change, é tão grande que você provavelmente quer ter algum tipo de cache aqui, né? Então, se você achar um tempo, o próximo, talvez, 5, 100, 1.000 requerimentos, ele vem do cache, e mesmo se você cache por apenas alguns segundos, é suficiente para você reduzir o load que você tem. Para entender esse exemplo, eu gostaria de entender essa classe registrada, que é uma metade de evento, então ela tem todas as metades de uma metade de evento, ela extende isso. Essa registrada é algo que vai bater, é como se você crie um objeto que vai bater, enviar métodos para um server remoto, né? É um exemplo, ele tem a frequência, e quando você começa, ele cria esse intervalo que, naquela frequência, ele vai publicar essas metodas. Então, você pode registrar as metodas, e, então, para publicar, a metodas é um objeto que tem um data gatherer, e aí um mapa, e aí você envia, né? É importante entender uma coisa, como uma decisão de design nesta classe, a registrada decidiu emitir um evento de data-send aqui, quando ele publica. Ok? É isso. Então, aqui, no fio da mão, temos uma metade de contraria, né? A metade de contraria ocorre a registrada, e aí ela registra, na construção, e essa é a parte importante, ela vai colocar um ouvintes para o evento de data-send para provar o seu data, né? E começar frio, cada vez que ele envia para remoto, não tem motivo para continuar acumulando mais. Então, aqui, temos um exemplo da metade de contraria, e nesta metade de contraria, nós recebemos o caminho, e com o caminho, nós vamos criar uma nova metade de contraria. Ok, então, aqui, eu comecei com a mesma base, a base que tem o ecorre-handler, e é, é, apenas retorna o Request Headers. Então, imediatamente aqui, eu comecei um 10% aumento, você pode ver aqui que é um pouco mais, mas isso é, na verdade, o que eu disse, tudo o que pode fazer, é começar um 10% aumento nos rios, e, em este particular evento-send ponto, e você vê que o uso de CPU começa a crescer. Ele não cresce absurdamente, mas, sim, eu só deixei por alguns horas jogando, você pode ver que ele cresceu, mas não é muito, o evento parece um pouco mais, mas nada notável. Você pode ver algo estranho, então, você vê que o 99.9% aqui, cresceu, e aqui, mesmo quando eu parou, ele continuou crescendo, certo? Então, vamos tentar entrar no botão deste, e eu acho que eu encontrei, certo? É definitivamente não sobre o Request Fly 2, porque parece que é apenas uma linha horizontal aqui, não devia, mas se você olhar aqui, deste ponto, é sobre 33 megabytes no Heap, e no topo deste bairro aqui, é sobre 1.35 gigabytes. Esta é uma linha de memória, claro que está acontecendo aqui, e esta vai continuar afetando o 99.9% aqui. Então, vamos voltar para o botão e ver uma das coisas que você poderia ter feito aqui é, bem, ao invés de deixar o metrico, ouvir aquele evento que foi emitido em Prune, seu data, e o registro aqui, ao invés de emitir esse evento, vai ser chamado de Prune. Ok, então, neste último exemplo, vamos olhar as promessas líquidas, e como elas afetam, ou metrics. Então, aqui eu tenho este ótimo módulo que me permite criar e trabalhar, criar um botão e trabalhar com databases, e então eu coloquei um botão, eu coloquei um query, e aqui eu vou fazer uma conexão dentro do meu botão, meu botão, disconnect state, sinc função, e aqui eu vou fazer um query que vai query todas as US estates da base de database, então eu retornei e coloquei. Então, vamos ver como isso funciona com metrics. Ok, então aqui, de novo, temos a base linha chamando de echo, de cerca de 4K RPS, e aqui eu começo chamando, 10% aumento para as promessas, o endpoint do Db. Você vê que há um grande spike no CPU, então, isso não é uma preocupação, porque o Db access é algo que vai ser slow, em um dos casos, e no outro rote, o echo rote não está fazendo nada, então, sim, você vai ver um lote de utilização de CPU nesse ponto. Não é realmente, não é a verdadeira preocupação nesse ponto. Idealmente, você quer reutilizar a conexão. Da event loop lag, a heap, está tudo bem, você vai ver que o 99.9% continua indo, então você provavelmente quer olhar as outras metrics, e aí você finalmente vê que quando você começa, o requesto de inflight começa a ligar. O que isso significa? Que, basicamente, as promessas não estão resolvendo, ou elas estão rejeitando nesse ponto, e quando elas estão rejeitando, isso significa que você não está sentando a resposta, certo? O REST.JSON, se você está procurando aqui, não fica aqui, é apenas algo acontece. Eu sei que, porque isso nunca vai até o final, e nunca senta a resposta, meu requesto de inflight começa a ligar. Então, isso mostra como o requesto de inflight é um bom indicador quando temos esses tipos de coisas líquidas acontecendo. Nesse ponto aqui, eu coloquei os calls, certo? Você vê, voltando para o todo echo endpoint, certo? 100%. E aí, eu começo a chamar a outra rota. Vamos mostrar o código. Esse é um code exacto, a única diferença é que eu coloquei o próximo, e eu coloquei aqui. Então, o que acontece? Por que? É porque, bem, nós não estamos enxerrando, e porque eu estava usando a promessa e eu não estava enxerrando, eu nunca estava terminando, esse requesto não estava sobretanto terminando. Agora, é isso. Então, se você olhar aqui, ok, é um pq usado, até mais que antes, mas isso é ok, certo? Isso é esperado. O que acontece aqui, a diferença que você vai ver aqui, é que agora você tem um instable de inflight para o requesto, certo? Agora você sabe um pouco mais como usar metrics para melhorar o code, usar o seu julgamento em cada commit. São as mudanças no metrics em linha com o code que você está cometendo? O que outras metrics são importantes? São metrics que eu não tive tempo para cobrar, como uma utilização de gc de tipo e preço de promoção. Um pouco de pesquisa sobre isso vai um longo caminho. Metrics pode dizer que o seu code tem um problema, mas não sempre como encontrar. Para isso, você precisa usar tools diagnósticos, como grafes de flamês, profissionais de profissionais, lojas e outras. Obrigado muito, e eu espero que o estoque tenha sido útil para você.