Cache do arquivo num nó edge¶
Um nó que serve o arquivo alheio em vez do seu — por remotes ou por uma fonte legacy — vai à fonte por absolutamente cada fragmento. O cache do arquivo muda isso: o fragmento lido assenta num disco de cache local, e a solicitação seguinte da mesma parte do arquivo é servida localmente, sem vai-e-vem pela rede.
É assim que se monta um edge de CDN: o origin guarda o arquivo, os edges guardam o que os espectadores de fato assistem.
O cache é transparente. Ele muda de onde vêm os bytes, não o que é servido: as URL dos fragmentos, as playlists e as bordas do arquivo continuam exatamente as mesmas para o espectador.
O que distingue um disco de cache de um disco de arquivo¶
O disco de cache é um papel do disco, não uma flag nele:
- a gravação ao vivo nunca o escolhe — o arquivo é gravado apenas nos discos listados em
disks; - a retenção do stream não o governa —
max_depthemax_bytesdo stream não se aplicam ao cache; - o espaço é liberado pelo despejo — pelo tempo desde o último acesso a um blob, não pela idade do conteúdo dele;
- ele é isolado no catálogo — os blobs de cache vivem em suas próprias tabelas, e as varreduras do arquivo (limpeza, backfill, a divisão do espaço ocupado em baldes) não os vêem em absoluto.
É por isso que o cache de um edge não aparece no console como um arquivo órfão, e por isso o despejo do cache não compete com a gravação do arquivo pelo mesmo mutex.
Configuração¶
O cache é configurado em dois lugares: os discos no nó, o interruptor no stream.
dvr:
root: /storage
cache_disks:
- path: ssd1 # relativo a root, como um disco de arquivo
max_bytes: 536870912000 # teto do cache neste disco, bytes
min_free_bytes: 10737418240
- path: ssd2
streams:
- name: cam1
remotes:
- url: http://origin:5080
cache: {} # liga o cache das leituras do arquivo
Parâmetros do disco de cache:
| Parâmetro | Descrição |
|---|---|
path |
caminho do disco relativo a root |
max_bytes |
quanto o cache pode ocupar neste disco; vazio — limitado só pelo espaço livre |
min_free_bytes |
quanto espaço livre deixar no volume |
Os limites são independentes: o despejo roda até o disco caber nos dois. O disco de cache não tem mode — Degraded descreve um membro do RAID do arquivo, e o cache não replica nada.
A seção cache do stream é uma seção de nível superior do documento, irmã da dvr, não um campo dentro dela: cache e gravação são propriedades independentes. Um edge faz cache do arquivo alheio sem gravar o seu. A seção ainda não tem campos — a mera presença dela liga o cache.
A validação da configuração rejeita:
- um caminho listado ao mesmo tempo em
diskse emcache_disks; - uma duplicata dentro de
cache_disks; - um disco de cache cujo caminho seja igual a
root— o despejo apagaria a casa do catálogo.
Caminhos diferentes no mesmo volume físico são uma configuração válida, mas na partida é registrado um aviso: o despejo libera espaço que o arquivo toma de volta na hora.
Uma seção cache num nó sem discos de cache é um no-op válido com um aviso no log. Isso é normal num cluster, onde um mesmo documento de stream se espalha por nós diferentes.
Um edge puro¶
Um armazenamento feito de root e discos de cache apenas, sem discos de arquivo, é uma configuração válida: há catálogo, não há gravação ao vivo, e o arquivo vai sendo trazido dos remotes.
dvr:
root: /storage
cache_disks:
- path: ssd1
max_bytes: 536870912000
streams:
- name: cam1
remotes:
- url: http://origin:5080
cache: {}
Warning
A root é a casa do catálogo, não um disco de gravação. Uma lista disks vazia costumava significar «gravar direto na root»; hoje é um erro de gravação visível nas estatísticas, em vez de uma gravação silenciosa por fora do RAID. Se o nó deve gravar um arquivo, liste os discos explicitamente em disks.
Admissão no cache¶
Pôr no cache tudo na primeira solicitação significa expulsar o popular em favor do aleatório: um único salto para o fundo do arquivo empurraria para fora do disco o que todos estão assistindo. Por isso a admissão tem dois eixos, e são configurados no nó, para o cache inteiro:
| Parâmetro | Descrição |
|---|---|
cache_fresh_age_secs |
um fragmento mais novo que essa profundidade (segundos para trás a partir de agora) vai para o cache já na primeira solicitação; por padrão, um dia |
cache_admission_hits |
com qual solicitação repetida começa a ser guardado em cache um fragmento mais velho que o limite de frescor; por padrão, a segunda; 1 desliga a barreira |
dvr:
root: /storage
cache_fresh_age_secs: 86400
cache_admission_hits: 2
cache_disks:
- path: ssd1
Quase todo mundo assiste à cauda fresca do arquivo, então ela entra no cache na hora. O fundo do arquivo interessa a uma minoria — entra no cache só quando é pedido de novo.
Ordem das fontes de leitura¶
Um fragmento do arquivo é procurado ao longo de uma cadeia, e a primeira fonte que responde fecha a solicitação:
- o segmentador do stream ao vivo;
- o cache;
- o arquivo local;
- o cluster (remotes);
- a fonte legacy
old_m4f; - o arquivo legacy em disco.
Um acerto de cache responde sem tocar em nada abaixo dele. Se um fragmento está num disco de arquivo e num disco de cache ao mesmo tempo, a leitura é servida pelo cache: cache em SSD ganha dos discos mecânicos. Um stream sem seção cache não tem nenhum passo de cache na cadeia.
O que uma falha põe no cache¶
Uma leitura bem-sucedida de uma fonte abaixo do cache é gravada num disco de cache junto com o seu fragmento init. As diferenças em relação à gravação do arquivo:
- o corte de
max_depthnão se aplica — no cache entra o que o espectador pediu, mesmo que seja mais fundo que qualquer profundidade de arquivo configurada; - um segmento multipista é guardado inteiro, com todas as pistas — assim a troca de bitrate de um espectador é servida por acertos, e não por falhas;
- a gravação é idempotente — vários espectadores falhando ao mesmo tempo no mesmo fragmento deixam exatamente uma cópia no cache;
- um erro de gravação no cache não afeta a resposta do cliente — ele já tem os bytes; o erro é apenas registrado e contado nas métricas.
O texto cifrado é guardado no cache como está, junto com o seu fragmento init: o edge não tem com o que descriptografá-lo e entrega exatamente os bytes que chegaram. Essa mídia é reconhecida pela descrição da sua trilha — o esquema e o identificador da chave chegam ao MediaInfo pelo fragmento init e fazem parte da identidade da trilha assim como o codec, de modo que uma troca de chave é resolvida pelo mesmo mecanismo que uma troca de codec. O texto cifrado nunca chega ao arquivo: o arquivo alimenta prévias, miniaturas e a linha do tempo, e todas elas leem dentro da amostra.
Leitura antecipada¶
Assistir ao arquivo é sequencial, por isso depois de servir uma leitura o Sapsan busca em segundo plano o próximo fragmento da mesma pista, se ele ainda não está no cache. A leitura antecipada funciona num edge puro e na leitura de uma fonte remota, limita-se a um fragmento à frente e nunca atrasa a resposta ao cliente.
Isso não é aquecimento: aqui não existe encher o cache por agenda nem por EPG.
Despejo¶
O espaço num disco de cache é liberado em blobs horários inteiros, na ordem do último acesso — o menos recentemente usado vai primeiro — até o disco voltar aos dois limites.
- A idade do conteúdo não é critério: o programa popular de ontem sobrevive ao impopular de hoje, e a hora atual é expulsa em igualdade de condições com as demais.
- A única exceção é um blob no qual um escritor está anexando dados agora mesmo: ele fica, e no lugar dele vai o seguinte menos recentemente usado.
- A limpeza do arquivo (
max_depthemax_bytesdo stream) e a proteção de episódios não consideram os discos de cache em absoluto.
A ordem de despejo é mantida por um índice próprio do catálogo e sobrevive a um reinício. A marca de acesso vai para o catálogo de forma diferida — no máximo cerca de uma vez a cada 10 minutos por blob — para que a leitura não vire gravação.
A contabilidade do cache (volume ocupado, tempos de acesso) é restaurada na partida por uma varredura de intervalos do catálogo, sem percorrer os ficheiros de dados. Um disco de cache apagado é um estado frio válido: o servidor parte, o cache se enche do zero, o arquivo fica intacto.
Linha do tempo e profundidade num edge¶
A profundidade do retrocesso e as faixas do arquivo de um stream com o cache ligado são calculadas como a união do catálogo local (arquivo e cache) e de todas as fontes remotas — e são anunciadas nas playlists de retrocesso e nas respostas sobre as faixas do arquivo. Um espectador no edge vê a mesma profundidade que no origin.
As janelas das fontes são unidas em lista, preservando os buracos entre elas: um intervalo sólido do começo ao fim de uma fonte não pode substituir essa lista — caso contrário a linha do tempo pinta de verde trechos sem dados, e um clique neles cai num 404. Buracos não maiores que a resolução pedida continuam sendo unidos pela regra geral.
Se o origin está inacessível mas a faixa pedida está inteira no cache, a playlist é construída a partir do catálogo local e os fragmentos são servidos do cache — a reprodução continua.
Observabilidade¶
Cada leitura do arquivo é atribuída ao elo da cadeia que a serviu:
- cache — serviu o disco de cache do nó (um acerto);
- local — serviu o disco de arquivo do nó;
- remote — foi preciso ir a uma fonte remota (uma falha).
Somente a leitura de um fragmento pelo cliente conta como leitura do arquivo. A saída do segmentador ao vivo e as buscas de leitura antecipada não entram na atribuição — caso contrário, a leitura antecipada inflaria a taxa de acertos quanto melhor funcionasse; as buscas são contadas à parte.
Para o Prometheus e o local-prom vão os contadores cumulativos:
| Métrica | Significado |
|---|---|
dvr_archive_reads_total{source} |
leituras do arquivo pelos eixos cache / local / remote |
dvr_archive_read_bytes_total{source} |
bytes dessas leituras |
dvr_read_ahead_fetches_total |
buscas de leitura antecipada |
dvr_disk_reads_total{disk_id}, dvr_disk_read_bytes_total{disk_id} |
acessos ao disco; num disco de cache são os seus acertos |
dvr_disk_cache_bytes{disk_id} |
volume de cache no disco |
O endpoint local GET /streamer/api-v4/dvr informa o papel, o volume e o limite de cada disco de cache, e as taxas de leitura do nó nos três eixos. Os contadores cumulativos não são expostos na management API: lá vão taxas e gauges.
A taxa de acertos nunca chega como número pronto — é cache / (cache + local + remote), e quem calcula é o consumidor: as taxas se somam, a divisão vem depois. Uma média de médias mente quando os nós têm pesos diferentes.
As telas do console onde isso aparece estão descritas na documentação do Catena: capacidade de DVR no cluster e configurações do nó; a montagem de um edge em um cluster do Catena — Streamers edge.
Em que isso se diferencia da replicação diferida por remotes¶
Os remotes têm um comportamento parecido: um fragmento lido de um servidor remoto é anexado ao arquivo local. A diferença é fundamental:
| Replicação diferida por remotes | Cache do arquivo | |
|---|---|---|
| Onde é gravado | em discos de arquivo | em discos de cache |
| Para quê | trazer para cá para sempre a história alheia | servir localmente as solicitações repetidas |
| Quando é liberado | pela limpeza segundo a retenção do stream | pelo despejo segundo o último acesso |
| Discos de arquivo necessários | sim | não, um edge pode funcionar sem eles |
A replicação consiste em mudar o arquivo de lugar; o cache, em economizar rede no que é popular.