A cache que vive na memória
Perto de um quinto das imagens de contador que este serviço desenha já não muda nada. Um programa de seguimento do rato da geração anterior recarrega a imagem a cada movimento, e desde que esses pedidos deixaram de incrementar seja o que for, dois seguidos produzem a mesma imagem, byte a byte.
Um candidato óbvio a cache. As decisões interessantes foram onde pô-la e sobre o que fazer incidir a chave.
No disco não
Isto corre num Raspberry Pi, e o disco é um cartão SD. Guardar aí as imagens desenhadas teria significado uns 70 MB de escrita por dia, em troca de uma poupança medida de 1,6 minutos de processador por dia.
É uma má troca. Os cartões SD morrem de escrever, e o que se compra é um erro de arredondamento numa máquina que não está limitada pelo processador. A cache vive por isso em /dev/shm, que é tmpfs, que é RAM. Medido ali: 0,027 ms a ler, 0,036 ms a escrever, 1,9 GB livres.
Tudo desaparece ao reiniciar. Para uma cache isso não é uma perda, é o caso normal.
No mesmo Pi corre o Redis. Não foi usado, por uma razão que nada tem de técnica: pertence a outra aplicação e está protegido com palavra-passe para ela. Partilhar uma instância ligaria dois serviços sem relação, de modo que um dia mau de um se tornasse um dia mau do outro.
A chave contém os números
A chave de cache habitual é uma identidade mais um prazo, e o prazo é uma aposta: nos últimos cinco minutos nada de importante mudou. Num contador, aquilo que muda é exatamente aquilo que se mostra.
Os valores mostrados vão então para dentro da chave. Se um número muda, é outra chave, e a imagem é desenhada de novo. A aposta desaparece em vez de ser feita com cuidado. Cada visita contada incrementa pelo menos o total de sempre, portanto nenhuma visita contada pode receber uma imagem desatualizada. O prazo que resta é apenas um limite superior para os valores que não estão na chave — os números semanais, mensais e anuais.
O que houve que verificar primeiro
Uma cache só é segura se aquilo que guarda for função da sua chave. Isso é uma afirmação sobre cada modelo, e foi verificada em vez de presumida:
- nenhum modelo usa
rand(),mt_rand(),shuffle()ouuniqid() - nenhum modelo lê o relógio com mais finura do que à hora
- os parâmetros de seguimento do programa antigo não são lidos em lado nenhum da árvore
Este último ponto produziu o melhor fracasso de todo o exercício. Enquanto esses parâmetros faziam parte da chave, cada pedido trazia coordenadas do rato ligeiramente diferentes, portanto cada chave era única. A cache correu um dia inteiro e registou 13 acertos. Funcionava na perfeição e não fazia nada, que é o tipo de avaria mais difícil de notar.
E se aqui alguma coisa falhar — diretório ilegível, disco cheio, entrada corrompida — a imagem é desenhada da forma normal. Uma cache nunca pode ser a razão de um contador não aparecer.