# Entregar uma biblioteca de vídeos sob demanda

Uma equipe de mídia, de e-learning ou de streaming serve uma biblioteca de vídeos sob demanda, já codificados em HLS. Todo título é um conjunto de playlists e milhares de segmentos, os mesmos arquivos para todo espectador, e um título em alta é requisitado por muitos espectadores ao mesmo tempo. Um segmento nunca muda depois de codificado, enquanto uma playlist pode ser reescrita quando um título é republicado. Esta página armazena a biblioteca codificada no Object Storage e configura uma aplicação que faz cache dos segmentos por muito tempo, com Tiered Cache, e das playlists por um tempo menor. O resultado é medido pela parcela de requisições de playlists e de segmentos respondidas pelo cache e pela parcela de misses que a camada do Tiered Cache responde sem ler o bucket.

Este caso de uso não cobre a codificação dos vídeos, que acontece antes da entrega.

## Pré-requisitos

- Um bucket para a biblioteca, com **Workloads Access** definido como *Read Only*. Para criar um, consulte [Criar um bucket](/pt-br/documentacao/guias/desenvolvimento-de-aplicacoes/dados/criar-e-modificar-um-bucket/).
- Uma aplicação que serve o bucket por um connector do tipo Object Storage com o prefixo `/vod`, e uma regra que envia todos os caminhos a ele. Para criar os dois, consulte [Use um bucket como origem de uma aplicação](/pt-br/documentacao/guias/desenvolvimento-de-aplicacoes/dados/bucket-como-connector/).
- Um hostname para a biblioteca que aponta para o workload da aplicação. Para criar o registro, consulte [Aponte um domínio para um workload](/pt-br/documentacao/guias/plataforma/migracao/apontar-dominio-para-a-azion/).
- Um personal token, para os procedimentos pela API. Para criar um, consulte [Personal tokens](/pt-br/documentacao/guias/plataforma/conta-e-billing/personal-tokens/).
- Os arquivos HLS codificados de cada título, como o seu packager os escreveu: uma playlist principal, uma playlist por rendition e os segmentos.
- Os valores da sua biblioteca. Esta página usa `video-library` para o bucket, `videos.example.com` para o hostname e `course-101` para um título, com os arquivos `master.m3u8`, `720p/index.m3u8` e `720p/segment-00001.ts`. Substitua cada valor pelo seu em todas as etapas.

---

## Produtos necessários

| A biblioteca de vídeos precisa de                                                | O que significa                                                                                         | Produto           | Documentado em                                                                                                                                                                                       |
| -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| As renditions codificadas armazenadas na Azion, sem uma origem própria da equipe | Um bucket que guarda toda playlist e todo segmento sob um prefixo, lido pela aplicação por um connector | Object Storage    | [Upload e download de objetos](/pt-br/documentacao/guias/desenvolvimento-de-aplicacoes/dados/upload-e-download-de-objetos-do-bucket/)                                                                |
| Segmentos que respondem pelo cache perto dos espectadores                        | Uma cache setting com um Max Age longo e Tiered Cache, aplicada por uma regra na extensão `.ts`         | Cache             | [Faça cache de uma biblioteca HLS sob demanda por extensão de arquivo](/pt-br/documentacao/guias/midia-e-streaming/streaming/fazer-cache-de-uma-biblioteca-hls-sob-demanda-por-extensao-de-arquivo/) |
| Playlists que respondem pelo cache e ainda pegam um título republicado           | Uma cache setting com um Max Age menor, aplicada por uma regra na extensão `.m3u8`                      | Cache             | [Real-Time Purge](/pt-br/documentacao/plataforma/applications/cache/real-time-purge/)                                                                                                                |
| Títulos pagos que apenas um espectador com um token válido recebe                | Uma função na frente do bucket que valida um JSON Web Token nos caminhos pagos                          | Functions         | [Autentique requisições com Functions](/pt-br/documentacao/guias/desenvolvimento-de-aplicacoes/dados/camada-autenticacao-object-storage-functions/)                                                  |
| A parcela de requisições respondidas pelo cache                                  | Os gráficos **Requests Offloaded** e **Tiered Cache Offload**, filtrados pelo hostname da biblioteca    | Real-Time Metrics | [Meça o offload de cache de um domínio](/pt-br/documentacao/guias/plataforma/observabilidade/medir-offload-de-cache/)                                                                                |

---

## Arquitetura de referência

Esta página monta a *Biblioteca de vídeos hospedada no Object Storage*: a biblioteca codificada passa para Object Storage, e uma aplicação a serve pelo Cache e pelo Tiered Cache.

```mermaid
%%{init: {"layout": "dagre", "themeVariables": {"fontSize": "13px"}, "flowchart": {"nodeSpacing": 12, "rankSpacing": 12, "padding": 6, "wrappingWidth": 70, "minNodeWidth": 40, "useMaxWidth": true}}}%%
flowchart TD
  Team["Renditions codificadas"] -->|"upload pela API ou pelo protocolo S3"| Bucket["bucket do Object Storage"]
  Viewer["Player do espectador"] -->|"requisição HTTPS"| App["aplicação"]
  App -->|"título gratuito"| Cache["Cache"]
  App -->|"título pago"| Fn["Functions: validação de token"]
  Fn -->|"token válido"| Bucket
  Cache -->|"miss"| Tiered["Tiered Cache"]
  Tiered -->|"miss"| Connector["connector do tipo Object Storage"]
  Connector --> Bucket
  App -->|"tráfego"| RTM["Real-Time Metrics"]
```

O diagrama traz dois fluxos. O fluxo de upload vai da equipe até o bucket, e só se move quando um título é adicionado ou recodificado: a biblioteca fica na Azion, então o fluxo de controle carrega essa etapa em vez de uma origem do cliente. O fluxo de requisições vai do player do espectador pela aplicação, onde as camadas de cache respondem a maioria das requisições, e apenas um miss nas duas camadas lê o bucket. Um título pago segue o caminho da função, que lê o bucket apenas para uma requisição com um token válido.

### Fluxo de dados

1. A equipe envia as playlists e os segmentos codificados de cada título ao bucket, sob o prefixo `vod/`, com o content type de cada arquivo.
2. O player de um espectador requisita a playlist principal de um título ao workload em `videos.example.com`, que entrega a requisição à aplicação.
3. Uma regra corresponde à extensão do arquivo e aplica uma cache setting: um Max Age longo com Tiered Cache para os segmentos, um menor para as playlists.
4. Cache responde com a cópia dele. Um segmento ausente no Cache é pedido à camada do Tiered Cache, e apenas um miss em todas as camadas é lido do bucket pelo connector e colocado em cache para o próximo espectador.
5. Para um título pago, uma função valida o token do espectador e lê o objeto do bucket apenas quando o token é válido.
6. O player lê a playlist da rendition e busca os segmentos dela da mesma forma, e Real-Time Metrics informa as requisições e os dados que cada camada de cache respondeu.

### Componentes

- **Object Storage**: guarda a biblioteca, toda playlist e todo segmento sob um prefixo de um bucket. O bucket dá à plataforma acesso somente leitura, e a equipe escreve nele pela API ou pelo protocolo S3.
- **aplicação**: o Platform Resource que entrega a biblioteca. Um connector para o bucket e uma regra com *Set Connector* fazem do bucket a fonte dela, e regras por extensão de arquivo aplicam uma cache setting a cada tipo de arquivo.
- **Cache**: mantém os segmentos e as playlists perto dos espectadores. Um segmento sob a key dele nunca muda, então pode ficar em cache por muito tempo, enquanto uma playlist que pode ser reescrita recebe um Max Age menor.
- **Tiered Cache**: a Feature que adiciona uma segunda camada de cache, compartilhada por todos os data centers, entre Cache e o bucket. Ela concentra os misses de todos os data centers, então o bucket é lido raramente para cada segmento.
- **Functions**: validam um token de acesso antes que um título pago saia do bucket, uma opção de design para conteúdo restrito. Uma requisição sem um token válido nunca lê o bucket.
- **Real-Time Metrics**: informa as requisições e os dados que Cache e a camada do Tiered Cache responderam, filtrados pelo hostname da biblioteca.

### Outros designs para este caso de uso

- *Biblioteca de vídeos hospedada na origem*: para equipes que mantêm a biblioteca no próprio bucket de nuvem ou na própria origem de mídia. A aplicação busca cada segmento por um connector em um miss e faz cache dele com um TTL longo e Tiered Cache, então a origem serve cada segmento raramente, enquanto o egress e a disponibilidade dela permanecem no fluxo de dados e no fluxo de falhas.

---

## Configure o upload da biblioteca

O upload da biblioteca coloca cada título no bucket sob keys que o connector serve sem alteração. O prefixo do connector é `/vod`, então o objeto `vod/course-101/master.m3u8` responde em `/course-101/master.m3u8`. Envie cada arquivo sob o mesmo caminho relativo que o packager escreveu, para que os caminhos dentro de cada playlist continuem apontando para os arquivos que ela lista.

Cada upload envia `Content-Type`, porque o tipo armazenado é o que esse header carrega, e ele é retornado em toda leitura. Sem o header, a Azion detecta o tipo, o que não é garantido para todo arquivo. Esta página usa `application/vnd.apple.mpegurl` para as playlists, o tipo que a [especificação do HLS](https://datatracker.ietf.org/doc/html/rfc8216#section-4) define para elas, e `video/mp2t` para os segmentos MPEG-2 transport stream.

Envie cada arquivo ao bucket `video-library` como [Upload e download de objetos](/pt-br/documentacao/guias/desenvolvimento-de-aplicacoes/dados/upload-e-download-de-objetos-do-bucket/#faca-upload-de-um-objeto-pela-api) descreve, com estes valores:

| Arquivo               | Key do objeto                          | `Content-Type`                  |
| --------------------- | -------------------------------------- | ------------------------------- |
| Playlist principal    | `vod/course-101/master.m3u8`           | `application/vnd.apple.mpegurl` |
| Playlist da rendition | `vod/course-101/720p/index.m3u8`       | `application/vnd.apple.mpegurl` |
| Segmento              | `vod/course-101/720p/segment-00001.ts` | `video/mp2t`                    |

A API responde `201` com a key de cada objeto em `object_key`, como `vod/course-101/master.m3u8`. Envie todos os outros segmentos do título da mesma forma. Para uma biblioteca com muitos arquivos, um cliente S3 como o s3cmd os envia com uma credencial limitada a `video-library`, como [Use ferramentas compatíveis com S3 com Object Storage](/pt-br/documentacao/guias/desenvolvimento-de-aplicacoes/dados/protocolo-s3-para-object-storage/) mostra. Azion Console recusa um único arquivo maior que 300 MB, um limite que a API e o protocolo S3 não têm.

Quando um título for recodificado, envie-o sob uma nova key, como `vod/course-101-v2/`, em vez de substituir os arquivos no lugar. Um upload para uma key em uso substitui o objeto sem histórico de versões, e uma key que nunca serve um conteúdo diferente é o que permite que os segmentos dela fiquem em cache por muito tempo.

O bucket guarda todos os arquivos de `course-101` sob `vod/course-101/`, e a aplicação pode servi-lo em `https://videos.example.com/course-101/master.m3u8`.

---

## Configure o cache para playlists e segmentos

O cache da biblioteca são duas cache settings e duas regras que as aplicam por extensão de arquivo, porque um segmento e uma playlist mudam em ritmos diferentes.

- **Segmentos**: **Max Age** é `31536000` segundos, o maior valor que o campo aceita. Um segmento sob a key dele nunca muda, já que um título recodificado recebe novas keys, então nada o força a sair do cache. Tiered Cache fica ativado, com a topologia `nearest-region`, então um segmento ausente em um data center é respondido pela segunda camada em vez do bucket.
- **Playlists**: **Max Age** é `3600` segundos. Uma playlist principal pode ser reescrita no lugar para apontar para um título recodificado, então uma hora limita por quanto tempo um espectador pode receber a antiga. Tiered Cache fica desativado para as playlists, porque um purge por URL não chega à camada do Tiered Cache, e uma playlist reescrita deve sair do cache com um purge por URL.
- **Os dois**: o cache do navegador é sobrescrito para `0` segundos. Uma cópia no cache do navegador do espectador não pode ser purgada, então um título retirado continuaria reproduzível ali até expirar.

```mermaid
%%{init: {"layout": "dagre", "themeVariables": {"fontSize": "13px"}, "flowchart": {"nodeSpacing": 12, "rankSpacing": 12, "padding": 6, "wrappingWidth": 70, "minNodeWidth": 40, "useMaxWidth": true}}}%%
flowchart TD
  Req["Requisição em videos.example.com"] --> Ext{"O caminho termina em"}
  Ext -->|".ts"| Seg["vod-segments: Max Age 31536000, Tiered Cache ativado"]
  Ext -->|".m3u8"| Pl["vod-playlists: Max Age 3600, Tiered Cache desativado"]
  Ext -->|"qualquer outra coisa"| Other["as outras regras da aplicação"]
  Seg --> Bucket["bucket, em um miss nas duas camadas"]
  Pl --> Bucket2["bucket, em um miss"]
```

1. Um caminho que termina em `.ts` recebe a cache setting `vod-segments`.
2. Um caminho que termina em `.m3u8` recebe a cache setting `vod-playlists`.
3. Qualquer outro caminho fica com as outras regras da aplicação.
4. Um miss chega ao bucket pelo connector, e a resposta é colocada em cache sob a configuração que o caminho dela recebeu.

Crie as duas cache settings e as duas regras como [Faça cache de uma biblioteca HLS sob demanda por extensão de arquivo](/pt-br/documentacao/guias/midia-e-streaming/streaming/fazer-cache-de-uma-biblioteca-hls-sob-demanda-por-extensao-de-arquivo/) descreve, com estes valores:

| Tipo de arquivo | Cache setting   | Max Age    | Tiered Cache              | Cache do navegador | Regra                   | Argumento de `${uri}` *matches* |
| --------------- | --------------- | ---------- | ------------------------- | ------------------ | ----------------------- | ------------------------------- |
| Segmentos       | `vod-segments`  | `31536000` | Ativado, `nearest-region` | Override, `0`      | `vod - cache segments`  | `\.ts$`                         |
| Playlists       | `vod-playlists` | `3600`     | Desativado                | Override, `0`      | `vod - cache playlists` | `\.m3u8$`                       |

Em um corpo JSON, para a API ou a CLI, os argumentos são escritos `"\\.ts$"` e `"\\.m3u8$"`.

Os segmentos ficam em cache por 31.536.000 segundos no Cache e na camada do Tiered Cache, e as playlists por 3.600 segundos no Cache. Os navegadores não guardam nenhum dos dois. Uma regra nova leva alguns minutos para se propagar.

---

## Verifique a configuração

Cada verificação de cache envia uma requisição com o header `Pragma: azion-debug-cache`, que faz a resposta trazer o header `x-cache`. Para saber como lê-lo, consulte [Verifique o status de cache de uma resposta](/pt-br/documentacao/guias/performance-e-confiabilidade/cache-e-purge/verificar-tempo-de-cache-da-pagina/).

- **A biblioteca é servida pelo bucket com o tipo dela.** Requisite a playlist principal:

  ```bash
  curl -sI https://videos.example.com/course-101/master.m3u8
  ```

  A resposta traz `200` e `content-type: application/vnd.apple.mpegurl`, o tipo armazenado no upload.

- **Os segmentos respondem pelo cache.** Requisite um segmento duas vezes:

  ```bash
  curl -sI -H "Pragma: azion-debug-cache" https://videos.example.com/course-101/720p/segment-00001.ts
  ```

  A segunda resposta traz `x-cache: HIT`. A primeira pode trazer `MISS`, enquanto a aplicação lê o segmento do bucket.

- **As playlists respondem pelo cache.** Requisite a playlist principal duas vezes com o mesmo header. A segunda resposta traz `x-cache: HIT`.

- **Uma playlist reescrita sai do cache.** Envie um purge por URL para `https://videos.example.com/course-101/master.m3u8`, como [Purgue conteúdo em cache](/pt-br/documentacao/guias/performance-e-confiabilidade/cache-e-purge/purgar-conteudo-em-cache/) mostra. Quando ele aparecer no histórico de purge, a próxima requisição traz `x-cache: MISS`.

- **Os títulos pagos recusam uma requisição sem token.** Quando uma função protege os caminhos pagos, uma requisição sem token recebe HTTP `401`, como [Autentique requisições com Functions](/pt-br/documentacao/guias/desenvolvimento-de-aplicacoes/dados/camada-autenticacao-object-storage-functions/) mostra.

Uma regra que parece não ter efeito ainda pode estar se propagando. Quando isso persistir depois de alguns minutos, ative [Debug Rules](/pt-br/documentacao/plataforma/applications/main-settings/#debug-rules) para ver quais regras foram executadas na requisição.

---

## Medindo resultados

| Métrica                                        | Onde ler                                                                                                                                                                                                           | Como é o funcionamento correto                                                                                           |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
| Parcela de requisições respondidas pelo cache  | **Requests Offloaded** no Real-Time Metrics, filtrado por `videos.example.com`. Consulte [Meça o offload de cache de um domínio](/pt-br/documentacao/guias/plataforma/observabilidade/medir-offload-de-cache/)     | Aumenta conforme cada título é assistido, porque um segmento só é lido do bucket quando nenhuma camada de cache o guarda |
| Parcela de dados entregues pelo cache          | **Edge Offload** no dashboard **Data Transferred**, filtrado por `videos.example.com`                                                                                                                              | Acompanha o Requests Offloaded, ponderado pelo tamanho dos segmentos                                                     |
| Misses respondidos pela camada do Tiered Cache | O gráfico **Tiered Cache Offload** da aba **Tiered Cache**. Consulte [Descubra o que chegou à origem](/pt-br/documentacao/guias/plataforma/observabilidade/medir-offload-de-cache/#descubra-o-que-chegou-a-origem) | A maioria dos misses de segmentos em um data center é respondida pela segunda camada, não pelo bucket                    |

---

## Boas práticas

- **Versione um título recodificado em vez de substituí-lo.** Uma key que nunca serve um conteúdo diferente pode ficar em cache pelo **Max Age** completo, e as duas versões existem enquanto os espectadores passam para a nova. Apenas a playlist principal, que o site incorpora, é reescrita no lugar:

  ```text
  vod/course-101/master.m3u8
  vod/course-101/720p/segment-00001.ts
  vod/course-101-v2/720p/segment-00001.ts
  ```

  O custo é que as keys antigas se acumulam, então remova as que nenhuma playlist referencia.
- **Faça o purge do Tiered Cache primeiro quando retirar um título.** Excluir um objeto do bucket não remove as cópias em cache dele. Faça o purge de cada segmento da camada do Tiered Cache pela cache key, depois do Cache, ou a primeira camada se reabastece a partir da segunda. Para a ordem do purge, consulte [Tiered Cache](/pt-br/documentacao/plataforma/applications/cache/tiered-cache/#purge).
- **Mantenha os espectadores fora do endpoint S3.** Uma URL pré-assinada entregue a um player envia toda requisição a uma interface de gerenciamento, sem cache, e as requisições que chegam aos objetos sem uma aplicação estão sujeitas a rate limits. Sirva a biblioteca apenas pela aplicação. Para o raciocínio, consulte [Sirva objetos aos usuários finais por meio de uma aplicação](/pt-br/documentacao/plataforma/object-storage/boas-praticas/#sirva-objetos-aos-usuarios-finais-por-meio-de-uma-aplicacao).
- **Limite a credencial de upload ao bucket da biblioteca.** Uma credencial criada sem `buckets` alcança todos os buckets da conta, e a secret key dela é retornada apenas uma vez. Nomeie `video-library` em `buckets` e conceda apenas as capabilities que o upload usa. Para os campos, consulte [Limite uma credencial S3 aos buckets e às capabilities de que ela precisa](/pt-br/documentacao/plataforma/object-storage/boas-praticas/#limite-uma-credencial-s3-aos-buckets-e-as-capabilities-de-que-ela-precisa).

---

## Guias deste caso de uso

- [Faça cache de uma biblioteca HLS sob demanda por extensão de arquivo](/pt-br/documentacao/guias/midia-e-streaming/streaming/fazer-cache-de-uma-biblioteca-hls-sob-demanda-por-extensao-de-arquivo.md): Cria as cache settings vod-segments e vod-playlists e as regras que as aplicam por extensão de arquivo.
- [Upload e download de objetos](/pt-br/documentacao/guias/desenvolvimento-de-aplicacoes/dados/upload-e-download-de-objetos-do-bucket.md): Envia cada playlist e cada segmento de um título a video-library sob o prefixo vod/, com o content type dele.
