Em aplicações de ultra-baixa latência, a medição e a coleta de estatísticas são essenciais, mas apresentam desafios significativos devido à sua natureza. O problema fundamental com o registro de logs e os cálculos estatísticos é que ambos são processos lentos. O registro de logs envolve operações de I/O em disco, que são as mais lentas, e os cálculos estatísticos podem ser complexos e onerosos, especialmente quando envolvem janelas deslizantes de observações passadas. Essas características tornam esses processos inadequados para threads críticas, que exigem um desempenho rápido e consistente.

Para contornar essas limitações, a arquitetura de registro e cálculo de estatísticas em sistemas de ultra-baixa latência precisa ser cuidadosamente projetada. O primeiro passo é mover as threads de registro e cálculo de estatísticas para fora das threads críticas, o que permite maior controle sobre a frequência de ativação desses processos. Isso deve ser feito de acordo com as características e o uso esperado da aplicação, além de levar em conta o consumo de recursos do sistema e o tempo real necessário para a coleta de dados. Para evitar bloqueios, é recomendado o uso de estruturas de dados livres de bloqueio e arquivos mapeados na memória não persistente para transferir dados das threads críticas para as threads de registro.

Além disso, é ideal fixar as threads de registro e cálculo de estatísticas em núcleos de CPU dedicados para evitar mudanças de contexto nas rotas críticas. Isso garante que o tempo gasto nas operações de I/O em disco seja minimizado e que os registros sejam feitos apenas quando necessário. A utilização de memória persistente mapeada também reduz o impacto das operações de gravação no desempenho geral da aplicação.

Em aplicações de ultra-baixa latência, a medição de desempenho de cada componente é crucial. Esses sistemas operam em escalas de tempo de nanossegundos e microssegundos, o que exige que as ferramentas de medição de desempenho sejam extremamente rápidas e precisas. As ferramentas de medição devem, portanto, ter um impacto mínimo na latência do sistema e frequentemente utilizar instruções de CPU específicas para garantir eficiência no uso da arquitetura. Métodos avançados, como espelhamento de tráfego de rede, inserção de campos nos pacotes de saída para relacioná-los com os pacotes de entrada, e carimbos de data/hora de hardware em NICs e switches, são usados para obter medições precisas sem comprometer o desempenho.

Para garantir que a otimização de desempenho seja eficaz, é importante que certas seções do código, que são executadas com pouca frequência, não sejam alvo de otimização, enquanto outras, que são frequentemente chamadas, devem receber atenção especial. A chave para identificar esses "hot paths" ou blocos de código críticos é realizar medições de desempenho de maneira regular, eficiente e precisa. Essas medições ajudam a identificar quais áreas do sistema impactam diretamente a latência e permitem ajustes rápidos e informados.

Além disso, a rede é outro componente essencial nas aplicações de ultra-baixa latência. A performance da rede, que envolve largura de banda, throughput e velocidade/tamanho dos pacotes, tem um grande impacto no desempenho geral do sistema. A largura de banda é o número teórico de pacotes que podem ser trocados entre dois hosts, enquanto o throughput mede a quantidade real de pacotes transferidos com sucesso. O desempenho da rede depende de diversos parâmetros, como o tamanho do pacote e a taxa de pacotes. Ao aumentar o tamanho dos pacotes, o throughput também tende a aumentar, mas somente até atingir um ponto de saturação. A chave para otimizar a rede é garantir que a quantidade de pacotes não cause congestionamento ou perda de dados, o que poderia aumentar a latência.

Ao analisar o caminho de transmissão e recepção de pacotes, deve-se entender as várias etapas pelas quais um pacote passa. A partir do momento em que o NIC recebe o pacote e verifica seu endereço MAC, até o processamento final no buffer de rede, todas essas etapas devem ser otimizadas para garantir que os pacotes cheguem ao seu destino de maneira eficiente. A utilização de buffers de recepção e técnicas de acesso direto à memória (DMA) aceleram o processo, permitindo que os dispositivos de I/O troquem dados diretamente com a memória principal, sem sobrecarregar a CPU.

Outro fator importante a ser observado é o problema do bloqueio na linha de frente (Head-of-Line Blocking - HOL), que ocorre quando um pacote na frente da fila de saída bloqueia vários pacotes subsequentes, aumentando a latência ou até mesmo desordenando a chegada dos pacotes. Esse problema pode ser atenuado com técnicas adequadas de gerenciamento de buffers e controle de fluxo, evitando que o congestionamento da fila cause atrasos significativos.

Em resumo, para garantir um desempenho ideal em sistemas de ultra-baixa latência, é necessário uma abordagem holística que envolva a otimização de cada componente do sistema, desde a coleta eficiente de estatísticas até a gestão de rede e buffers. Medições precisas e a redução de latências adicionais são fundamentais para garantir que o desempenho do sistema não seja afetado pela própria infraestrutura de monitoramento.

Como a Congestão e o Processamento de Pacotes Impactam a Latência na Rede

A latência de rede é um aspecto crucial do desempenho dos sistemas distribuídos. Ela pode ser causada por diversos fatores ao longo da cadeia de transmissão de dados, desde o código do usuário até os sistemas de rede, e é essencial compreendê-la para otimizar o tempo de resposta e melhorar a eficiência do tráfego de dados. Em sistemas de rede, os pacotes de dados percorrem um caminho complexo, passando por diferentes camadas de software e hardware antes de chegarem ao seu destino. Essa cadeia envolve tanto a parte de transmissão quanto a de recepção, e ambos os processos podem ser afetados pela congestão e pelos mecanismos de interrupção que buscam equilibrar a carga de trabalho do processador.

O primeiro ponto a ser entendido é que a congestão de rede ocorre quando o tráfego de dados excede a largura de banda disponível de um link Ethernet, o que resulta em atrasos consideráveis. Embora a congestão seja mais comumente associada à rede, ela também pode ser influenciada por fatores no código do kernel ou nos próprios dispositivos de hardware da rede. Esses atrasos não acontecem apenas durante a transmissão, mas também na recepção de pacotes, onde o tráfego excessivo pode causar reordenação de pacotes, retransmissões e até perda de dados.

Por exemplo, a transmissão de pacotes na rede enfrenta um atraso de aproximadamente 200 microsegundos antes de uma interrupção de Ethernet ser gerada. Esse atraso ocorre porque o manipulador de interrupção BH:tx está tentando inserir mais pacotes no buffer de anel, aguardando o momento ideal para enviar as informações ao processador. Se o tráfego de rede no cliente for baixo, não deverá haver atraso significativo antes do envio de um pacote. No entanto, pode haver um pequeno atraso até que o pacote chegue ao servidor e o NIC (Controlador de Interface de Rede) consiga emitir uma interrupção ao processador.

Além disso, a maneira como as interrupções são manipuladas pode contribuir substancialmente para a latência. Em vez de permitir que as interrupções ocorram a uma taxa que o processador não pode acompanhar, elas são frequentemente mescladas, o que ajuda a reduzir o número de interrupções frequentes e a evitar sobrecarga do processador. Essa técnica permite que os pacotes sejam empilhados e processados de maneira mais eficiente, minimizando o impacto de atrasos em sistemas de produção.

Porém, essa abordagem não elimina completamente a possibilidade de atrasos. O tempo de latência pode ser medido desde o momento em que um programa do espaço do usuário envia um pedido até o momento em que o servidor retorna uma resposta. Esse processo envolve várias etapas, como a inserção de pacotes na fila de transferência, a passagem de pacotes pelo buffer de memória principal e sua entrega através da interface física de rede. Durante esse processo, podem ocorrer diferentes formas de latência, dependendo de onde o atraso ocorre – no código do usuário, no código do kernel, no hardware de rede ou durante a transmissão de pacotes.

Quando se analisa a latência de rede, pode-se utilizar ferramentas como o KUtrace, que permitem observar a sequência de eventos em detalhes. Com o KUtrace, podemos identificar e medir a latência de rede, visualizando a jornada de um pacote desde sua criação até sua recepção. Isso é feito através do registro de carimbos de tempo (timestamps) que marcam os momentos exatos em que os pacotes entram e saem das diferentes camadas do sistema. O tempo de latência pode ser mapeado entre as diferentes máquinas, como no caso de um processo de RPC (Chamada Remota de Procedimento), onde é possível observar o impacto da latência na transmissão de dados entre cliente e servidor.

De modo geral, o rastreamento de pacotes e a análise da latência por meio de ferramentas especializadas oferecem insights profundos sobre como as interrupções, buffers e congestões impactam o desempenho da rede. Através da análise das diferenças de carimbos de tempo entre os diversos pontos de processamento, como o espaço do usuário e o espaço do kernel, é possível realizar uma análise detalhada do tempo que os pacotes gastam em cada etapa da transmissão.

Outro aspecto a ser considerado é a capacidade de otimização da rede em ambientes de produção, onde é comum alocar largura de banda para determinados programas e priorizar as transmissões para reduzir o impacto da congestão. Em redes congestionadas, a redistribuição de pacotes e o ajuste das interrupções podem melhorar o desempenho, permitindo que o processador lide com os dados de forma mais eficaz. A aplicação de técnicas de mesclagem de interrupções, juntamente com ajustes finos nos parâmetros de rede, pode reduzir significativamente a latência e aumentar a eficiência da rede.

É importante ressaltar que a latência não depende apenas dos parâmetros de rede, mas também da maneira como o sistema operacional e o hardware gerenciam os pacotes. A análise detalhada de eventos em sistemas distribuídos, através de ferramentas como o KUtrace, pode revelar insights valiosos, desde a origem até a resolução dos problemas de latência. Dessa forma, o diagnóstico de falhas na rede e a implementação de otimizações podem se tornar mais precisos, melhorando o desempenho global do sistema.

Como os Bancos de Dados Vetoriais Facilitam a Busca Semântica e o Aprendizado de Máquina

Os bancos de dados vetoriais são ferramentas essenciais para manipulação e pesquisa de grandes volumes de dados baseados em embeddings, que representam conceitos ou objetos como vetores numéricos em um espaço multidimensional. Eles possuem uma característica poderosa: a capacidade de realizar buscas rápidas e eficientes por vizinhos mais próximos em um espaço N-dimensional. Esse processo é fundamental para tarefas que envolvem aprendizado de máquina, como buscas semânticas, recomendações e a construção de agentes inteligentes que utilizam modelos generativos de texto.

Para entender como esses bancos de dados operam, é necessário observar o funcionamento do índice k-NN (k-Nearest Neighbors). Em essência, um banco de dados vetorial utiliza algoritmos como HNSW (Hierarchical Navigable Small World) ou IVF (Inverted File System) para indexar os vetores, o que torna as buscas mais rápidas. Esses índices permitem que o sistema compare rapidamente a consulta do usuário com os vetores presentes na base de dados, encontrando os vizinhos mais próximos de acordo com uma medida de distância, como o cosseno ou a Euclidiana.

No entanto, a precisão de uma busca semântica frequentemente vem à custa de um tempo de resposta mais lento. Visto que os vetores no mundo real podem ter centenas de dimensões, a comparação entre milhares deles é computacionalmente intensiva. Para resolver essa questão, os bancos de dados vetoriais operam através de três processos principais: indexação, consulta e pós-processamento.

Na indexação, algoritmos como PQ (Product Quantization), LSH (Locality Sensitive Hashing) ou HNSW são utilizados para mapear os vetores a estruturas de dados que aceleram a busca. Na fase de consulta, o sistema compara o vetor da consulta com os vetores indexados e encontra os vizinhos mais próximos. Se necessário, o pós-processamento é realizado para refinar os resultados, utilizando métricas de similaridade diferentes ou reordenando os vizinhos encontrados.

A integração dos bancos de dados vetoriais com modelos generativos de texto, como os de linguagem natural, pode criar experiências de busca interativas e altamente precisas. Isso é particularmente útil em cenários que exigem uma compreensão semântica da consulta, como no caso de buscas em grandes bases de dados textuais ou quando se necessita de uma interação mais natural com o sistema. A busca semântica, ao contrário da busca por palavras-chave, leva em consideração o significado das palavras dentro de um contexto, oferecendo resultados mais relevantes.

Entretanto, um desafio importante surge ao escalar a busca para grandes volumes de dados. O problema do k-NN é simples: dada uma consulta, encontra-se os k pontos mais próximos dentro de um conjunto de vetores. Contudo, esse processo pode se tornar ineficiente à medida que o número de vetores cresce. O algoritmo k-NN exato tem uma complexidade de tempo O(N log k), onde N é o número de vetores e k é o número de vizinhos mais próximos. Embora essa abordagem funcione bem para conjuntos de dados pequenos, ela se torna ineficaz para conjuntos de dados massivos, como aqueles com milhões de vetores. A solução para isso são os métodos de k-NN aproximado, que reorganizam o índice de maneira mais eficiente, reduzindo a complexidade da pesquisa sem comprometer drasticamente a precisão.

Entre os algoritmos de k-NN aproximado mais utilizados estão o HNSW e o IVF. O HNSW constrói um grafo onde os vetores próximos são conectados por arestas, permitindo uma busca mais rápida ao percorrer parcialmente esse grafo. Já o IVF divide o índice em subconjuntos (buckets) e realiza a busca apenas em uma parte desses buckets, reduzindo o tempo de processamento.

Dentro desse contexto, ferramentas como o OpenSearch tornam-se cruciais. O OpenSearch, com seu plugin k-NN, possibilita a implementação de buscas semânticas de forma eficiente em grandes volumes de dados. O plugin permite que o OpenSearch utilize o algoritmo k-NN para realizar buscas de vizinhos mais próximos dentro do cluster. Com o OpenSearch, os vetores podem ser armazenados em documentos indexados, onde os mapeamentos informam ao sistema qual algoritmo e parâmetros devem ser usados. Ele suporta várias estratégias de busca, como a k-NN aproximada para grandes índices, o uso de scripts de pontuação para consultas menores e pré-filtradas, e a utilização de scripts "painless" para calcular a distância entre os vetores.

É importante notar que a implementação de uma busca vetorial em OpenSearch pode ser feita utilizando três diferentes bibliotecas que oferecem algoritmos k-NN: NMSLIB, FAISS e Lucene. Cada uma dessas bibliotecas tem características próprias que as tornam mais adequadas a diferentes cenários. Por exemplo, o NMSLIB e o FAISS são recomendados para grandes volumes de dados, enquanto o Lucene, por ser mais simples, é mais indicado para implementações menores, mas oferece recursos como filtragem inteligente, o que pode ser vantajoso dependendo do caso de uso.

Na prática, ao configurar o OpenSearch para utilizar o plugin k-NN, o primeiro passo é criar um índice e definir os parâmetros e mapeamentos para os vetores. A criação de um índice no OpenSearch permite que os documentos com vetores sejam armazenados de forma eficiente, facilitando as buscas subsequentes. Após a criação do índice, os dados podem ser indexados, e a busca por vizinhos mais próximos pode ser realizada através dos algoritmos mencionados, como o HNSW ou o IVF, dependendo do caso de uso.

Outro ponto relevante é que, ao lidar com grandes quantidades de vetores e dimensões altas, é fundamental ajustar os parâmetros dos algoritmos, como o "ef_construction" e "m", que impactam diretamente na precisão e no uso de memória durante o processo de indexação. Para uma maior precisão, esses valores podem ser ajustados, mas é importante balanceá-los, pois valores mais altos podem desacelerar o processo de indexação.

Para melhorar a busca, muitas implementações utilizam uma busca híbrida, que combina a busca por palavras-chave com a busca semântica. Essa abordagem tem o objetivo de maximizar a relevância dos resultados, aproveitando as vantagens de ambos os métodos: a precisão da busca por palavras-chave e a profundidade contextual da busca semântica.

Ao explorar essas tecnologias, é crucial compreender que a eficiência das buscas depende de como os dados são indexados e de como o sistema é configurado para lidar com diferentes tipos de consultas. As técnicas de k-NN aproximado, como o HNSW e o IVF, são poderosas ferramentas para lidar com grandes volumes de dados e garantir que as buscas sejam realizadas de forma eficiente, mesmo em espaços vetoriais de alta dimensão.

Como Integrar Ferramentas e Fluxos de Trabalho para Análise de Causa Raiz e Automação no Contexto de AIOps

No mundo atual da automação e inteligência artificial, a análise de causa raiz (RCA) desempenha um papel crucial na manutenção da continuidade e confiabilidade dos sistemas. As ferramentas envolvidas em AIOps, como agentes, bancos de conhecimento, e servidores MCP, precisam ser integradas de maneira eficaz para melhorar a eficiência e garantir uma resposta rápida aos incidentes. A configuração de um agente e a automação de fluxos de trabalho são essenciais para resolver problemas antes que eles afetem gravemente a operação. Uma análise cuidadosa de cada ferramenta e sua interação com os fluxos de trabalho pode resultar em uma operação mais ágil, precisa e resiliente.

Um dos primeiros passos para a integração de sistemas é a correta configuração dos agentes. Em uma arquitetura como LangGraph, cada agente pode conter múltiplas ferramentas, sendo essencial que cada um deles desempenhe funções específicas, como análise de causa raiz, detecção de anomalias e observabilidade. A correta configuração de cada agente, por exemplo, um agente de RCA ou de observabilidade, facilita a automação das respostas a incidentes. O uso de uma arquitetura como LangChain permite o desenvolvimento de agentes que executam ações específicas, como a execução de cálculos ou a busca por informações em fontes externas.

Além disso, o uso de ferramentas como RAG (retrieval-augmented generation) é vital para melhorar a acuracidade das respostas e recomendações. Ao conectar agentes com bancos de dados de conhecimento, sistemas de gerenciamento de documentos como o Jira e o Confluence, e integrar com plataformas de comunicação como o Slack, é possível criar um fluxo de informações contínuo, essencial para a tomada de decisões rápidas e fundamentadas. A interação entre esses sistemas precisa ser fluida e otimizada para que as informações certas cheguem aos profissionais da operação no momento adequado.

Os fluxos de trabalho são outra parte fundamental da arquitetura de AIOps. Diversos tipos de profissionais, como engenheiros de infraestrutura, operadores de primeira linha, e desenvolvedores, devem colaborar de maneira organizada. Para isso, é necessário que os fluxos de trabalho sejam configurados de acordo com as necessidades e características de cada função. Por exemplo, o fluxo de trabalho de um engenheiro de infraestrutura envolve análise profunda das causas dos problemas, incluindo falhas em sistemas de rede e segurança, enquanto o fluxo de trabalho de um operador de primeira linha se concentra em detectar falhas de forma proativa para evitar grandes interrupções no serviço.

Cada fluxo de trabalho pode ser composto por diferentes agentes que desempenham funções específicas. O agente de RCA, por exemplo, ajudará a identificar e analisar a causa raiz dos problemas, enquanto o agente de observabilidade será responsável por fornecer dados sobre o status dos sistemas e detectar anomalias. O agente de reranking pode ser utilizado para melhorar a precisão das respostas obtidas, caso os resultados da análise inicial não correspondam às expectativas dos profissionais da operação.

É crucial que os sistemas de AIOps permitam a colaboração entre diferentes áreas, como engenheiros de infraestrutura, operadores de primeira linha, SREs, arquitetos e desenvolvedores. Cada um desses profissionais necessita de um fluxo de trabalho específico para cumprir suas tarefas de maneira eficiente. Por exemplo, os engenheiros de infraestrutura precisam de um fluxo de trabalho que permita uma análise detalhada das falhas no sistema, enquanto os SREs devem ser capazes de responder rapidamente a falhas no serviço, minimizando o impacto para os clientes. Para garantir que isso aconteça de maneira eficaz, é essencial que as ferramentas de análise, detecção e observabilidade sejam bem integradas e otimizadas para o contexto específico de cada função.

A automação desses fluxos de trabalho não só acelera o tempo de resposta, mas também ajuda a melhorar a confiabilidade geral do sistema, reduzindo os erros humanos e tornando o processo mais eficiente. A integração de diferentes agentes e ferramentas também facilita o processo de análise e correção de falhas, permitindo uma intervenção rápida e uma recuperação mais eficiente dos serviços.

Ao configurar esses fluxos de trabalho e ferramentas, deve-se priorizar o uso de dados em tempo real, como informações sobre clima, localização e tráfego, que podem ser acessadas por meio de buscas na internet e incorporadas diretamente aos processos de AIOps. Essas informações são cruciais para garantir que as decisões tomadas pelos profissionais da operação estejam sempre atualizadas e baseadas nas condições atuais do ambiente.

Por fim, a criação de uma estratégia operacional integrada, que contemple diferentes equipes e fluxos de trabalho, deve ser uma prioridade. Isso envolve não só a automação incremental, mas também a definição clara dos objetivos e direções para o uso de ferramentas de AIOps e agentes. A personalização e otimização dos fluxos de trabalho para cada organização e contexto específico são fundamentais para alcançar uma operação mais eficiente e resiliente. A definição de parâmetros claros de desempenho e confiabilidade, como SLOs e MTTR, também ajuda a medir a eficácia das operações e identificar áreas de melhoria contínua.

Como Monitorar e Instrumentar Mensagens com OpenTelemetry em Brokers JMS

A utilização de OpenTelemetry para monitoramento e instrumentação de mensagens em sistemas distribuídos, como brokers JMS, oferece uma visão detalhada sobre o desempenho e as falhas em diferentes pontos de um pipeline de mensagens. Tradicionalmente, a instrumentação de clientes era a única necessária para coletar métricas e spans, mas com a evolução das ferramentas de monitoramento, agora é possível gerar spans e métricas também no servidor, através da instrumentação do servidor. Este avanço permite uma análise mais completa de latências, taxas de erro e throughput, tanto para os clientes quanto para os servidores que compõem a arquitetura.

A instrumentação de servidores é tão crucial quanto a de clientes, pois sem ela, falhas e latências no servidor podem passar despercebidas. No contexto de servidores de mensageria como o Solace JMS, a identificação de latência entre diferentes componentes, como publishers e subscribers, pode revelar problemas que não seriam aparentes caso a instrumentação fosse feita apenas no lado do cliente. Por exemplo, quando se utiliza servidores de mensagens, como o Solace, é possível observar que o subscriber em tempo real terá uma latência menor, enquanto o subscriber em modo batch pode apresentar uma latência muito maior, algo que poderia indicar falhas no processo.

Para garantir uma visão holística do sistema, é necessário monitorar e criar spans em diferentes pontos da mensagem. Isso inclui o broker, que se torna visível com a instrumentação de servidor, e a propagação do contexto de rastreamento entre publisher, broker e subscriber. No exemplo do Solace, a propagação do contexto de rastreamento no cabeçalho da mensagem JMS permite que se acompanhe a trajetória da mensagem por todo o pipeline, desde a publicação até o consumo.

Além disso, a integração com o OpenTelemetry permite a criação de métricas detalhadas sobre o broker, o que antes era restrito aos clientes. Com a instrumentação automatizada, a coleta de dados se torna mais acessível e eficaz, mesmo em sistemas complexos. A possibilidade de adicionar atributos e eventos aos spans gerados pelo OpenTelemetry amplia a riqueza dos dados coletados, fornecendo insights ainda mais precisos sobre o comportamento do sistema.

No cenário descrito com o Solace JMS, tanto o publisher quanto o subscriber geram spans que são transmitidos para o OpenTelemetry Collector, permitindo a visualização e análise dos dados de rastreamento. O uso de agentes Java e extensões específicas do OpenTelemetry para o Solace facilita a coleta e o envio dessas informações. O processo de verificação desses spans envolve a inspeção do contexto de rastreamento presente nos cabeçalhos das mensagens, garantindo que a propagação dos dados ocorra corretamente entre os componentes do sistema.

No caso do TIBCO JMS, o processo de instrumentação é similar, com a necessidade de configurar o cabeçalho das mensagens JMS para propagar corretamente o contexto de rastreamento. A configuração do OpenTelemetry nesse cenário segue um padrão semelhante, e a instrumentação automatizada permite que tanto os publishers quanto os subscribers sejam monitorados em tempo real. O arquivo de configuração do coletor do OpenTelemetry também desempenha um papel fundamental na coleta e exportação dos dados para análise posterior.

Contudo, nem sempre a instrumentação automatizada é perfeita. Existem casos em que falhas na propagação do contexto ou na coleta de dados podem ocorrer, o que exige uma análise cuidadosa dos resultados. Quando isso acontece, é essencial verificar os conteúdos dos cabeçalhos das mensagens e garantir que a propagação está sendo realizada corretamente. Caso contrário, pode ser necessário recorrer à instrumentação manual, caso a instrumentação automatizada não seja suportada.

Além disso, para uma visão completa e precisa do sistema, é fundamental monitorar não apenas as métricas tradicionais, mas também a latência de ponta a ponta (E2E), a taxa de erros e o throughput, abrangendo todos os pontos do sistema, incluindo o broker, o servidor de mensagens e os clientes. Essa abordagem permite uma identificação mais rápida de falhas e problemas de desempenho, que podem afetar a operação do sistema como um todo.