Lembro-me de ler sobre uma empresa que se recusou a enviar um recurso para a produção, a menos que ele estivesse ligado às suas estatísticas de backend e registrado em seus padrões de uso e outros indicadores de desempenho importantes de negócios e de tecnologia. Na época, eu pensei que era uma ideia muito legal. O problema: como podemos implementar isso com o mínimo de esforço?
O problema
Precisávamos de uma maneira de armazenar o contador de dados históricos para o nosso serviço Filer Progstr com valores diários e mensais. A estatística diária iria manter os valores do contador (digamos, downloads) dos últimos 30 dias. Uma estatística mensal faria o mesmo, porém para os últimos 12 meses. E nós também queremos uma solução genérica que funcione para todos os tipos de dados: logins de usuários, uso do aplicativo demo, largura de banda.
Por que Redis
Já fiz as implementações mencionadas acima usando bancos de dados SQL (MySQL) e não foi nem um pouco divertido. O mecanismo de armazenamento é estranho – ponha todos os valores em uma única tabela e alinhe-os de acordo com estatísticas de nome e de período. Isso torna a consulta para os dados estranha também. Entretanto, isso não é um empecilho – eu poderia fazer. O verdadeiro problema é atingir seu banco de dados principal algumas vezes em um pedido web, e que é definitivamente um não-não. Depois de ir por esse caminho, a sua solução começa manifestando estatísticas de background writes/increments. Feio, feio, feio.
Redis ao resgate! Ele mantém todos os seus dados na memória e é ridicularmente rápido. Dessa forma, você pode ter duas ou três gravações completas em pouco tempo sem a necessidade de trabalhadores no background.
A abordagem Hashes
Acontece que você não precisa de nada super complicado para implementar uma série de tempo e armazená-la em Redis. A ideia mais simples realmente funciona – usar hashes com o tempo (dia ou mês) como a chave e um valor. O valor pode ser qualquer coisa numérica. Com o Filer Progstr, é principalmente uma contagem de algo, mas pode ser outra coisa, como uma soma de alguns valores (por exemplo, o tamanho dos arquivos). O Redis oferece uma maneira de modificar o valor de forma atômica usando o comando HINCRBY. Quando precisamos contar eventos, incrementamos com um, e por tamanhos de arquivo ou de largura de banda, usamos o valor específico.
Agora, o truque aqui é como fazer ambas as estatísticas diárias e mensais. Bem, temos dois hashes e incrementamos o valor de ambos. Aqui está como uma de nossas séries diárias de download de largura de banda fica a partir do console Redis:
Nós armazenamos os valores de data/hora como timestamps do Unix, mas isso não é realmente uma exigência. Você pode escolher uma representação diferente. Note que eu também estou usando o comando HGETALL para buscar todos os dados.
Registrando eventos
Com a nossa abordagem de armazenamento baseado em hash, tudo o que precisamos fazer ao registrar um download é a emissão de algumas ligações HINCRBY. Nesse caso, precisamos incrementar o valor de hoje no hash diário de contagem de download e o valor deste mês no hash mensal de download de contagem. Novamente, se você está acostumado a trabalhar com bancos de dados SQL, ter muitas gravações pode parecer muito, mas eu estou dizendo a você – está tudo na memória e Redis lida com isso muito rapidamente.
Limpeza
O mecanismo acima precisa de alguns retoques. O primeiro é expiração de dados. Se você não precisa de dados diários de mais de 30 dias atrás, você mesmo precisa excluí-los. O mesmo vale para expirar dados mensais – no nosso caso, o material com mais de 12 meses. Fazemos isso em um trabalho cron que roda uma vez por dia. A gente faz um loop em todas as séries e arruma os elementos expirados a partir das hashes.
Falando em looping, iremos precisar provavelmente de algum tipo de registro para manter todas as chaves de séries de tempo. Usamos um conjunto classificado para Filer Progstr, para que possamos ter nomes de séries Redis quando ele repassa-os de volta para nós. Ter um registro central te oferece outro benefício – você pode criar rapidamente uma interface de usuário simples na sua aplicação backend que pode buscar uma série aleatória e plotar em um gráfico Flot.
Retoques finais e algumas dicas
- Você deve ter notado a longa chave hash na imagem acima. Estamos sendo inteligentes ao codificar o tipo de série e o proprietário no nome na chave hash. Você pode facilmente chegar a um esquema próprio que lhe permite manter o controle de outras propriedades também.
- Observe que, se acontecer de você tiver um dia ou um mês sem eventos, você não vai ter uma entrada no seu hash. Buscar todos os valores com HGETALL também não garante que você vai tê-los classificados de acordo com o dia. Felizmente, os conjuntos de dados são pequenos (~ 30 registros), e você pode classificá-los dentro do prazo e preencher entradas em falta com zeros se necessário.
Mas ele escala?
O Redis mantém todos os dados na memória, por isso é melhor ter certeza de que esse recurso não acabe. Medir a utilização da memória hash pode ser um pouco complicado, já que todas as chaves hash e os valores são armazenados como strings (não números de tamanho fixo), mas há uma maneira de fazê-lo. Eu gerei um hash com 42 valores (30 entradas diárias e 12 mensais) que simula a sua típica série de tempo diária e mensal. Gravei o uso de memória Redis antes e depois usando o comando INFO. A diferença que consegui foi cerca de 1100 bytes em uma máquina de 64 bits. Eu repeti o experimento algumas vezes e obtive os mesmos resultados, o que me deixou confiante de que meus números estão corretos.
Como usamos?
Nós fizemos do deploy de nossa ferramenta de análise em duas etapas. Na primeira fase, nós começamos a acompanhar um monte de estatísticas internas sobre como as pessoas usam o nosso serviço e vários negócios relacionados a métricas.
Na fase dois, expusemos algumas das métricas para nossos clientes.
?
Texto original disponível em http://filer.progstr.com/1/post/2012/03/effective-web-app-analytics-with-redis.html