Recentemente precisei resolver um problema relativamente simples: acompanhar a performance de um servidor Debian durante vários meses, sem instalar uma plataforma inteira de observabilidade só para isso.
A necessidade era bem objetiva:
- registrar CPU, memória, load average, disco e rede;
- acompanhar também os containers Docker;
- manter histórico por alguns meses;
- gerar arquivos pequenos;
- causar o mínimo possível de impacto no servidor;
- permitir que os dados fossem baixados periodicamente para análise;
- ter informação suficiente para justificar posteriormente um dimensionamento de infraestrutura.
A primeira ideia poderia ser instalar Prometheus, Grafana, Netdata, InfluxDB ou alguma solução semelhante.
Mas, para esse cenário, seria exagero.
O próprio Linux já possui uma ferramenta excelente para isso: o sysstat.
A solução ficou baseada em:
sysstat/sarpara telemetria do sistema operacional;docker statspara telemetria dos containers;systemd timerspara execução periódica;- arquivos locais compactados;
- retenção automática;
- exportação semanal em
.tar.gz.
Sem banco de dados.
Sem painel web.
Sem mais uma stack para administrar.
O que é o sysstat?
O pacote sysstat é uma coleção de ferramentas tradicionais de monitoramento do Linux.
Entre elas estão:
sariostatmpstatpidstatsadf
O diferencial é que o sysstat não serve apenas para visualizar o estado atual da máquina.
Ele também pode coletar e armazenar métricas continuamente.
Depois é possível voltar para um determinado dia e perguntar, por exemplo:
Como estava a CPU às 14h de terça-feira?
Ou:
Houve saturação de disco naquele período?
Ou ainda:
Quanto de memória estava sendo utilizada quando o load subiu?
É exatamente o tipo de informação necessária quando queremos analisar capacidade e performance retroativamente.
Arquitetura da coleta
A configuração que utilizei ficou assim:
| Componente | Intervalo |
|---|---|
| CPU, memória, disco, rede etc. | 1 minuto |
| Docker | 5 minutos |
| Retenção | 180 dias |
| Compressão | automática |
| Exportação | manual/semanal |
Os dados do sistema ficam em:
/var/log/sysstat/
Os dados adicionais do Docker ficam em:
/var/log/telemetry/docker/
Também mantemos um pequeno arquivo contendo o baseline da máquina:
/var/log/telemetry/baseline.txt
Isso registra informações como:
- sistema operacional;
- kernel;
- CPU;
- memória;
- discos;
- filesystems;
- interfaces de rede;
- versão do Docker;
- containers existentes no início da coleta.
Esse baseline é importante porque daqui a alguns meses talvez ninguém lembre exatamente qual era a configuração original daquele servidor.
Script completo de instalação
Crie o arquivo:
nano install-telemetry.sh
E coloque:
#!/usr/bin/env bash
set -Eeuo pipefail
SYSSTAT_RETENTION_DAYS=180
DOCKER_RETENTION_DAYS=180
if [[ $EUID -ne 0 ]]; then
echo "Execute como root:"
echo " sudo $0"
exit 1
fi
echo "============================================================"
echo " Instalando telemetria leve"
echo "============================================================"
apt-get update
apt-get install -y sysstat gzip
# ----------------------------------------------------------------------
# SYSSTAT
# ----------------------------------------------------------------------
echo
echo "Configurando sysstat..."
if [[ -f /etc/default/sysstat ]]; then
if grep -q '^ENABLED=' /etc/default/sysstat; then
sed -i 's/^ENABLED=.*/ENABLED="true"/' /etc/default/sysstat
else
echo 'ENABLED="true"' >> /etc/default/sysstat
fi
fi
SYSSTAT_CONFIG="/etc/sysstat/sysstat"
set_sysstat_option() {
local key="$1"
local value="$2"
if grep -qE "^[[:space:]#]*${key}=" "$SYSSTAT_CONFIG"; then
sed -ri "s|^[[:space:]#]*${key}=.*|${key}=${value}|" "$SYSSTAT_CONFIG"
else
echo "${key}=${value}" >> "$SYSSTAT_CONFIG"
fi
}
set_sysstat_option "HISTORY" "${SYSSTAT_RETENTION_DAYS}"
set_sysstat_option "COMPRESSAFTER" "2"
set_sysstat_option "SADC_OPTIONS" '"-S DISK"'
# Desabilita o timer padrão do Debian, normalmente de 10 minutos.
# Será utilizado um timer próprio de 1 minuto.
systemctl disable --now sysstat-collect.timer 2>/dev/null || true
cat >/etc/systemd/system/telemetry-sysstat.service <<'EOF'
[Unit]
Description=Coleta de telemetria sysstat
ConditionPathExists=/usr/lib/sysstat/sa1
[Service]
Type=oneshot
ExecStart=/usr/lib/sysstat/sa1 1 1
EOF
cat >/etc/systemd/system/telemetry-sysstat.timer <<'EOF'
[Unit]
Description=Coleta sysstat a cada minuto
[Timer]
OnCalendar=*-*-* *:*:00
AccuracySec=2s
Persistent=true
[Install]
WantedBy=timers.target
EOF
# Mantém o processamento diário fornecido pelo próprio sysstat.
systemctl enable --now sysstat-summary.timer 2>/dev/null || true
# ----------------------------------------------------------------------
# DIRETÓRIOS
# ----------------------------------------------------------------------
install -d -m 0750 /var/log/telemetry
install -d -m 0750 /var/log/telemetry/docker
# ----------------------------------------------------------------------
# BASELINE DA MÁQUINA
# ----------------------------------------------------------------------
echo
echo "Gravando configuração base da máquina..."
{
echo "================================================================"
echo "TELEMETRY BASELINE"
echo "================================================================"
echo
echo "Timestamp:"
date --iso-8601=seconds
echo
echo "Hostname:"
hostname
echo
echo "Sistema operacional:"
cat /etc/os-release
echo
echo "Kernel:"
uname -a
echo
echo "CPU:"
lscpu
echo
echo "Memória:"
free -h
echo
echo "Discos:"
lsblk -e7 \
-o NAME,TYPE,SIZE,FSTYPE,MOUNTPOINTS,MODEL,ROTA
echo
echo "Filesystems:"
df -hT
echo
echo "Interfaces:"
ip -br link 2>/dev/null || true
echo
if command -v docker >/dev/null 2>&1; then
echo "Docker:"
docker version 2>/dev/null || true
echo
echo "Containers atuais:"
docker ps \
--format 'table {{.Names}}\t{{.Image}}\t{{.Status}}' \
2>/dev/null || true
fi
} >/var/log/telemetry/baseline.txt
chmod 0640 /var/log/telemetry/baseline.txt
# ----------------------------------------------------------------------
# DOCKER STATS
# ----------------------------------------------------------------------
if command -v docker >/dev/null 2>&1; then
echo
echo "Configurando telemetria Docker..."
cat >/usr/local/sbin/telemetry-docker <<'EOF'
#!/usr/bin/env bash
set -Eeuo pipefail
LOGDIR="/var/log/telemetry/docker"
mkdir -p "$LOGDIR"
exec 9>/run/telemetry-docker.lock
if ! flock -n 9; then
exit 0
fi
DATE="$(date +%F)"
TIMESTAMP="$(date --iso-8601=seconds)"
FILE="${LOGDIR}/docker-${DATE}.tsv"
if [[ ! -f "$FILE" ]]; then
printf '%s\n' \
'timestamp container_id name cpu_percent memory_usage memory_percent net_io block_io pids' \
>"$FILE"
fi
timeout 30 docker stats \
--no-stream \
--format '{{.Container}} {{.Name}} {{.CPUPerc}} {{.MemUsage}} {{.MemPerc}} {{.NetIO}} {{.BlockIO}} {{.PIDs}}' \
2>/dev/null |
while IFS= read -r line; do
printf '%s\t%s\n' "$TIMESTAMP" "$line"
done >>"$FILE"
chmod 0640 "$FILE"
EOF
chmod 0755 /usr/local/sbin/telemetry-docker
cat >/etc/systemd/system/telemetry-docker.service <<'EOF'
[Unit]
Description=Coleta de telemetria Docker
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/telemetry-docker
EOF
cat >/etc/systemd/system/telemetry-docker.timer <<'EOF'
[Unit]
Description=Coleta de telemetria Docker a cada 5 minutos
[Timer]
OnCalendar=*-*-* *:0/5:00
AccuracySec=10s
Persistent=true
[Install]
WantedBy=timers.target
EOF
fi
# ----------------------------------------------------------------------
# LIMPEZA E COMPRESSÃO
# ----------------------------------------------------------------------
cat >/usr/local/sbin/telemetry-housekeeping <<EOF
#!/usr/bin/env bash
set -Eeuo pipefail
LOGDIR="/var/log/telemetry/docker"
# Comprime arquivos Docker com mais de um dia.
find "\$LOGDIR" \
-type f \
-name 'docker-*.tsv' \
-mtime +1 \
-exec gzip -6 {} \;
# Remove telemetria Docker além do período de retenção.
find "\$LOGDIR" \
-type f \
\( -name 'docker-*.tsv' -o -name 'docker-*.tsv.gz' \) \
-mtime +${DOCKER_RETENTION_DAYS} \
-delete
EOF
chmod 0755 /usr/local/sbin/telemetry-housekeeping
cat >/etc/systemd/system/telemetry-housekeeping.service <<'EOF'
[Unit]
Description=Compressão e limpeza da telemetria
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/telemetry-housekeeping
EOF
cat >/etc/systemd/system/telemetry-housekeeping.timer <<'EOF'
[Unit]
Description=Manutenção diária da telemetria
[Timer]
OnCalendar=daily
RandomizedDelaySec=10m
Persistent=true
[Install]
WantedBy=timers.target
EOF
# ----------------------------------------------------------------------
# EXPORTAÇÃO
# ----------------------------------------------------------------------
cat >/usr/local/sbin/telemetry-export <<'EOF'
#!/usr/bin/env bash
set -Eeuo pipefail
DAYS="${1:-8}"
if ! [[ "$DAYS" =~ ^[0-9]+$ ]]; then
echo "Uso:"
echo " sudo telemetry-export [dias]"
exit 1
fi
HOST="$(hostname -s)"
NOW="$(date +%Y%m%d-%H%M%S)"
OUTPUT="${PWD}/${HOST}-telemetry-${NOW}.tar.gz"
cd /
FILES=()
while IFS= read -r -d '' file; do
FILES+=("$file")
done < <(
find \
var/log/sysstat \
var/log/telemetry \
-type f \
-mtime "-${DAYS}" \
-print0 2>/dev/null
)
# O baseline sempre entra no pacote.
if [[ -f var/log/telemetry/baseline.txt ]]; then
FILES+=("var/log/telemetry/baseline.txt")
fi
if [[ ${#FILES[@]} -eq 0 ]]; then
echo "Nenhum arquivo de telemetria encontrado."
exit 1
fi
tar -czf "$OUTPUT" "${FILES[@]}"
sha256sum "$OUTPUT" >"${OUTPUT}.sha256"
if [[ -n "${SUDO_USER:-}" && "$SUDO_USER" != "root" ]]; then
USER_GROUP="$(id -gn "$SUDO_USER")"
chown "$SUDO_USER:$USER_GROUP" \
"$OUTPUT" \
"${OUTPUT}.sha256"
fi
echo
echo "Pacote criado:"
echo " $OUTPUT"
echo
echo "Hash:"
cat "${OUTPUT}.sha256"
EOF
chmod 0755 /usr/local/sbin/telemetry-export
# ----------------------------------------------------------------------
# ATIVAÇÃO
# ----------------------------------------------------------------------
systemctl daemon-reload
systemctl enable --now telemetry-sysstat.timer
systemctl enable --now telemetry-housekeeping.timer
if command -v docker >/dev/null 2>&1; then
systemctl enable --now telemetry-docker.timer
fi
echo
echo "============================================================"
echo " Telemetria instalada"
echo "============================================================"
echo
echo "Sysstat:"
echo " /var/log/sysstat/"
echo
echo "Docker:"
echo " /var/log/telemetry/docker/"
echo
echo "Configuração da máquina:"
echo " /var/log/telemetry/baseline.txt"
echo
echo "Exportar os últimos 8 dias:"
echo
echo " sudo telemetry-export 8"
echo
echo "Timers:"
echo
systemctl list-timers \
'telemetry-*' \
--no-pager
Depois:
chmod +x install-telemetry.sh
sudo ./install-telemetry.sh
Verificando se está funcionando
Para conferir os timers:
systemctl list-timers 'telemetry-*'
Também podemos verificar individualmente:
systemctl status telemetry-sysstat.timer
systemctl status telemetry-docker.timer
systemctl status telemetry-housekeeping.timer
Após alguns minutos:
ls -lh /var/log/sysstat/
E:
ls -lh /var/log/telemetry/docker/
Consultando o histórico
É aqui que o sysstat começa a mostrar seu valor.
Supondo que exista:
/var/log/sysstat/sa23
Podemos analisar diversos aspectos daquele dia.
CPU
sar -u ALL -f /var/log/sysstat/sa23
Isso permite analisar utilização de CPU ao longo do dia.
Memória
sar -r ALL -f /var/log/sysstat/sa23
Podemos observar:
- memória utilizada;
- memória disponível;
- cache;
- buffers;
- pressão de memória.
Load average
sar -q -f /var/log/sysstat/sa23
Aqui aparecem informações como:
- quantidade de processos na fila;
- load average de 1 minuto;
- 5 minutos;
- 15 minutos.
Isso é especialmente útil para identificar períodos em que a máquina estava recebendo mais trabalho do que conseguia processar imediatamente.
Disco
sar -d -p -f /var/log/sysstat/sa23
Essa é uma das métricas mais importantes em servidores.
É possível identificar, entre outras coisas:
- quantidade de operações;
- throughput;
- tamanho das requisições;
- tempo médio das operações;
- utilização do dispositivo.
Um servidor com CPU relativamente baixa pode estar lento simplesmente porque o storage está saturado.
Sem telemetria histórica isso costuma passar despercebido.
Rede
sar -n DEV -f /var/log/sysstat/sa23
Podemos acompanhar:
- pacotes recebidos;
- pacotes enviados;
- bytes recebidos;
- bytes enviados;
- utilização das interfaces.
Ver praticamente tudo
Também existe:
sar -A -f /var/log/sysstat/sa23
O -A significa basicamente:
mostre tudo que estiver disponível.
Para investigação rápida é extremamente útil.
Telemetria dos containers Docker
O sysstat mostra muito bem o que aconteceu com a máquina.
Mas em um servidor com Docker existe outra pergunta importante:
Quem causou isso?
É justamente por isso que acrescentei a coleta periódica de docker stats.
A cada cinco minutos é registrado um snapshot dos containers.
O arquivo fica semelhante a:
/var/log/telemetry/docker/docker-2026-08-23.tsv
Exemplo:
timestamp container_id name cpu_percent memory_usage memory_percent net_io block_io pids
2026-08-23T16:00:00-03:00 76d... erlang 19.6% 324.8MiB / 4GiB 7.93% 122MB / 84MB 31MB / 18MB 38
2026-08-23T16:00:00-03:00 7d2... redis 8.0% 41.5MiB / 4GiB 1.01% 45MB / 39MB 8MB / 2MB 6
O formato TSV foi escolhido propositalmente.
É simples, compacto e pode posteriormente ser aberto ou processado facilmente com:
- Excel;
- LibreOffice;
- Python/Pandas;
- shell;
- PostgreSQL;
- DuckDB;
- qualquer ferramenta de análise.
Correlacionando servidor e aplicação
Esse é provavelmente o ponto mais importante de toda a solução.
Sem essa coleta, normalmente temos algo assim:
O servidor estava lento às 14h.
Ou no máximo:
A CPU chegou a 80%.
Com histórico podemos investigar muito melhor:
Entre 14h02 e 14h11 a CPU permaneceu acima de 80%, o load average aumentou, o disco apresentou maior utilização e determinado container estava utilizando grande parte da CPU disponível.
Isso muda completamente a conversa sobre infraestrutura.
Passamos de percepção para evidência.
Exportando os dados toda semana
Criei também o comando:
telemetry-export
Por padrão ele exporta os últimos oito dias.
Execute:
sudo telemetry-export 8
Será gerado algo parecido com:
vps-mvp-01-telemetry-20260830-150000.tar.gz
E também:
vps-mvp-01-telemetry-20260830-150000.tar.gz.sha256
O segundo arquivo contém o hash SHA-256 do pacote.
Assim podemos verificar posteriormente se o arquivo baixado continua exatamente igual ao original.
Baixando o pacote
Por exemplo, usando scp:
scp usuario@servidor:~/vps-mvp-01-telemetry-20260830-150000.tar.gz .
E o hash:
scp usuario@servidor:~/vps-mvp-01-telemetry-20260830-150000.tar.gz.sha256 .
Depois:
sha256sum -c vps-mvp-01-telemetry-20260830-150000.tar.gz.sha256
Se estiver tudo correto:
OK
Quanto espaço isso consome?
Uma das preocupações era justamente deixar a coleta funcionando durante meses sem começar a consumir gigabytes desnecessariamente.
O sysstat é muito eficiente nesse aspecto.
Ele foi desenvolvido justamente para esse tipo de coleta.
O tamanho exato depende de:
- quantidade de CPUs;
- quantidade de discos;
- quantidade de interfaces;
- intervalo da coleta;
- quantidade de containers.
Mas para uma VPS normal estamos falando de um volume bastante pequeno quando comparado a plataformas completas de observabilidade.
Depois de uma semana, podemos conferir o consumo real:
sudo du -sh /var/log/sysstat
E:
sudo du -sh /var/log/telemetry
A partir disso fica muito fácil estimar o consumo para seis meses.
Por exemplo, se uma semana gerar 30 MB:
30 MB × 26 semanas ≈ 780 MB
Ou seja: menos de 1 GB para aproximadamente seis meses de histórico.
O importante é medir na própria máquina, já que cada ambiente possui características diferentes.
Por que não coletar top ou ps continuamente?
Também seria possível executar algo como:
ps aux
a cada minuto.
Ou armazenar repetidamente a saída do top.
Mas preferi não fazer isso.
A quantidade de dados aumentaria consideravelmente e provavelmente guardaríamos muito mais informação do que realmente precisaríamos.
Além disso, linhas de comando de processos podem conter:
- caminhos;
- argumentos;
- parâmetros;
- informações internas da aplicação.
Não havia necessidade disso.
Para análise de capacidade, a combinação:
sysstat + docker stats
já fornece uma relação custo/benefício excelente.
Por que não Prometheus + Grafana?
Prometheus e Grafana são ferramentas excelentes.
Eu utilizaria tranquilamente essa stack se precisasse de:
- dashboards em tempo real;
- alertas;
- observabilidade centralizada;
- dezenas ou centenas de servidores;
- histórico consultável constantemente;
- integração com várias fontes;
- SRE/NOC;
- monitoramento operacional permanente.
Mas esse não era o problema.
O objetivo era:
deixar uma máquina sendo observada durante alguns meses para posteriormente analisar sua utilização e ajudar no dimensionamento.
Adicionar:
Prometheus
Grafana
Exporters
Banco de séries temporais
Containers
Volumes
Configurações
Atualizações
Backups
Segurança
seria criar uma infraestrutura para monitorar outra infraestrutura.
Neste caso, não precisava.
E por que não Netdata?
O Netdata também é excelente e extremamente prático para investigação em tempo real.
Mas novamente existe uma diferença entre:
quero enxergar meu servidor agora
e:
quero coletar dados discretamente durante vários meses para analisá-los posteriormente.
Para a segunda situação, prefiro algo simples e tradicional.
O sysstat existe há décadas justamente porque resolve muito bem esse problema.
O que podemos calcular depois
Depois de acumular algumas semanas ou meses de dados, podemos transformar essa telemetria em números realmente úteis.
Por exemplo:
CPU
- média;
- máximo;
- P50;
- P90;
- P95;
- P99.
Memória
- média;
- máximo utilizado;
- mínimo disponível;
- ocorrência de swap.
Disco
- throughput;
- IOPS;
- latência;
- utilização;
- períodos de saturação.
Rede
- tráfego médio;
- picos;
- volume diário;
- volume por interface.
Containers
- CPU média;
- CPU máxima;
- memória média;
- memória máxima;
- crescimento de memória;
- tráfego;
- I/O;
- quantidade de processos.
E principalmente podemos correlacionar tudo isso.
Média não basta
Esse detalhe merece atenção.
Se um servidor permanecer:
23 horas e 50 minutos com CPU em 10%
e:
10 minutos com CPU em 100%
a média diária provavelmente parecerá excelente.
Mas talvez justamente aqueles dez minutos correspondam ao período em que os usuários reclamam de lentidão.
Por isso métricas como:
P90
P95
P99
são tão importantes.
O percentil 95, por exemplo, ajuda a responder:
Qual utilização não foi excedida durante 95% do período?
Esse tipo de informação é muito mais útil para dimensionamento do que simplesmente olhar a média mensal.
Resultado
No final ficamos com uma solução bastante pequena:
Debian
│
├── sysstat
│ └── CPU / RAM / load / disco / rede
│
├── docker stats
│ └── CPU / RAM / rede / I/O por container
│
├── systemd timers
│
└── arquivos locais
│
├── retenção automática
├── compressão
└── exportação semanal
Sem banco.
Sem aplicação web.
Sem serviço externo.
Sem depender de SaaS.
Sem uma segunda infraestrutura para administrar.
E, principalmente, sem perder a informação que realmente interessa.
Conclusão
Às vezes a solução certa não é instalar mais software.
O Linux já possui ferramentas extremamente maduras que resolvem problemas desse tipo há muitos anos.
Para uma análise de capacidade de médio prazo, o sysstat oferece uma quantidade surpreendente de informação consumindo poucos recursos e pouco espaço.
O complemento com docker stats resolve a outra metade do problema nos ambientes modernos: descobrir não apenas como estava o servidor, mas também qual workload estava utilizando seus recursos.
Agora basta deixar a coleta trabalhar.
Daqui a algumas semanas teremos dados.
Daqui a alguns meses teremos histórico.
E quando chegar a hora de discutir se a máquina precisa de:
- mais CPU;
- mais memória;
- storage mais rápido;
- redistribuição dos containers;
- ou absolutamente nada;
a decisão poderá ser baseada em números — e não em uma screenshot do top.