Skip to content

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 governamax_depth e max_bytes do 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 modeDegraded 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 disks e em cache_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:

  1. o segmentador do stream ao vivo;
  2. o cache;
  3. o arquivo local;
  4. o cluster (remotes);
  5. a fonte legacy old_m4f;
  6. 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_depth nã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_depth e max_bytes do 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.

O que vem a seguir