Cache e CDN para a distribuição OTT

Apêndice para a operação de instalações de grande porte: como funciona o cache das respostas OTT do Perfect Streamer e como colocar um reverse proxy de cache ou uma CDN à frente do nó. Os modos de distribuição, os formatos de URL e a autorização são descritos na seção principal OTT e DVR.

O servidor forma respostas de três categorias, que diferem no tempo de vida do conteúdo e na aptidão para o cache por nós intermediários (reverse proxy, CDN, cache do cliente).

1. Modelo de cache

1.1. Recursos e cabeçalhos HTTP

Recurso

URL

Content-Type

Cache-Control

Segmento TS (HLS)

/h<sess>/<keyHex>.ts

video/mp2t

public, max-age=60, immutable

Segmento VTT (legendas)

/h<sess>/sub/<pid>/<keyHex>.vtt

text/vtt; charset=utf-8

public, max-age=60, immutable

Segmento fMP4 (DASH / LL-HLS)

/h<sess>/init.mp4, /h<sess>/<key|N>.m4s

video/mp4

public, max-age=60, immutable

DASH MPD

/h<sess>/index.mpd

application/dash+xml; charset=utf-8

public, max-age=1

HLS master

/hls/<stream>/<login>/<pass>/index.m3u8

application/vnd.apple.mpegurl

public, max-age=1

HLS media

/h<sess>/index.m3u8, /h<sess>/sub/<pid>/index.m3u8

application/vnd.apple.mpegurl

public, max-age=1

302 Redirect

/dash/<stream>/<login>/<pass>/index.mpd

no-cache, no-store

Raw TS

/http/<stream>/<login>/<pass>

video/mp2t

não definido; não é armazenado em cache

1.2. Características dos segmentos

O identificador hexadecimal do segmento no URL (<keyHex> nos caminhos /h<sess>/<keyHex>.ts) é formado como o CRC64 do horário inicial do segmento e do ID do fluxo, sendo globalmente único. O URL do segmento endereça um conteúdo imutável — em requisições repetidas do mesmo URL é retornado um fluxo de bytes idêntico (enquanto o segmento permanecer dentro da janela deslizante).

A diretiva immutable suprime a revalidação condicional pelo cliente (If-None-Match, If-Modified-Since). O valor max-age=60 garante a compatibilidade com um timeShiftBufferDepth=40s típico.

Os segmentos fMP4 CMAF (.m4s) e o init.mp4 comum para DASH / Low-Latency HLS são endereçados de forma análoga e armazenados em cache segundo o mesmo modelo (immutable, max-age=60). Os segmentos parciais (parts) do LL-HLS são requisições byte-range dentro do mesmo .m4s e, por isso, não formam uma entrada separada no cache.

1.3. Características dos manifestos

max-age=1 limita a um segundo o limite superior de desatualização do conteúdo no cache. Em uso conjunto com proxy_cache_lock on (nginx), os picos de requisições ao manifesto são coalescidos em uma requisição ao origin por segundo.

1.4. Variabilidade do conteúdo

Com absPath=0 (valor padrão, sem o parâmetro de URL a) os manifestos HLS media e o DASH MPD não contêm o identificador da sessão no corpo. O conteúdo do manifesto é idêntico entre sessões pertencentes à mesma combinação (stream, param). Isso permite ao cache do reverse proxy reutilizar a entrada entre sessões quando a chave de cache é normalizada.

Com absPath=1 (parâmetro de URL a=1) o corpo do manifesto contém URLs absolutos que incluem o esquema, o host e o identificador da sessão. O conteúdo torna-se específico da sessão e a reutilização do cache entre sessões deixa de ser possível.

2. Comportamento dos clientes

Cliente

URL de atualização do manifesto

Efeito sobre a quantidade de sessões

Players HLS pela media playlist

/h<sess>/index.m3u8

Uma sessão por sessão de reprodução

Players DASH pelo URL raiz

/dash/<stream>/.../index.mpd (ciclo de repetição)

Tratado pelo session reuse (ver 3.2)

Players de navegador (MSE)

/h<sess>/... através de <Location> / session URL

Uma sessão por sessão de reprodução

3. Mecanismos especiais

3.1. HTTP 302 Redirect para DASH

Uma requisição da forma /dash/<stream>/<login>/<pass>/index.mpd retorna a resposta 302 Found com o cabeçalho Location: /h<sess>/index.mpd. O corpo da resposta é vazio. A autorização e a alocação da sessão são executadas na etapa de processamento do redirecionamento.

Os clientes que suportam o cache do redirecionamento acessam o session URL diretamente nas requisições subsequentes. Os clientes que não o suportam repetem a requisição de redirecionamento. O custo do reprocessamento do redirecionamento limita-se à verificação de autenticação e às operações de session reuse.

3.2. Session reuse para DASH

Ao processar a requisição /dash/.../index.mpd do mesmo login para o mesmo fluxo (com o mesmo indicador adaptive), o servidor encontra uma sessão DASH já existente e retorna novamente o seu identificador. Nenhuma sessão nova é criada e nenhum slot do limite de conexões simultâneas é consumido. São reutilizadas apenas as sessões no mesmo modo de reprodução: uma sessão ao vivo e uma sessão VOD de arquivo (parâmetros t/d/epg) não são unificadas.

Aplica-se somente ao DASH. Para o HLS não é necessário um mecanismo de reuse separado: os clientes HLS atualizam a media playlist pelo session URL e não criam uma sessão nova a cada atualização.

3.3. Reutilização de segmentos entre sessões

O caminho /h<sess>/<keyHex>.ts não depende de <sess> na resolução de <keyHex> para o conteúdo: <keyHex> identifica de forma globalmente inequívoca o segmento TS dentro do fluxo. O Nginx com uma cache key normalizada (que remove o prefixo /h<sess>/) atende todas as requisições do mesmo <keyHex> a partir de uma única entrada de cache, independentemente de quais clientes as emitiram.

A deduplicação é aplicável somente aos nomes content-addressed — segmentos com identificador hexadecimal de 16 caracteres (.ts, .m4s com <keyHex>, .vtt). Os segmentos numerados do live-DASH (<número>.m4s), o init.mp4 e os manifestos são únicos apenas dentro da própria sessão — a sua cache key deve preservar o prefixo /h<sess>/, caso contrário o cache entregará o conteúdo de um fluxo aos espectadores de outro. Para o DASH, a deduplicação dos manifestos entre clientes do mesmo login é assegurada pelo session reuse (ver 3.2).

4. Parâmetros da requisição

Parâmetro

Valor padrão

Efeito

a

0

1 — URLs absolutos nos manifestos; 0 — relativos

s

40

timeShiftBufferDepth em segundos

m

40

Comprimento mínimo da janela para a emissão do manifesto

v

6 para os modos OTT, 3 para Peering / HLS

#EXT-X-VERSION no HLS (ignorado pelo DASH); um valor explícito no URL substitui o valor padrão

h3

ausente (off)

opt-in para HTTP/3 (QUIC): faz o servidor emitir Alt-Svc na resposta; sticky no session URL. Ver HTTP/3 (QUIC)

A alteração de um parâmetro pela query string atualiza os valores armazenados na sessão na sua próxima reabertura. Os parâmetros de reprodução do arquivo t, d e epg são descritos em Reprodução do arquivo (VOD).

5. Características de carga

A carga sobre o origin escala com a quantidade de fluxos distintos assistidos simultaneamente. O aumento do número de clientes que assistem ao mesmo fluxo não aumenta a quantidade de requisições ao origin quando existe um cache de reverse proxy e uma cache key normalizada.

Cenário

Frequência de requisições ao origin (ref.)

1 cliente no fluxo X

MPD: 0.4 req/s, segment: 0.2 req/s

N clientes em um único fluxo X (cache ativado)

MPD: 1 req/s, segment: 0.2 req/s

N clientes DASH em modo de repetição em um único fluxo

MPD: 1 req/s (com proxy_cache_lock)

N clientes em N fluxos distintos

MPD: 0.4·N req/s, segment: 0.2·N req/s

Os segmentos são deduplicados globalmente pelos nomes content-addressed; a deduplicação dos manifestos entre clientes é assegurada pelo session reuse (DASH) e pelo cache dentro da sessão.

6. Nginx como reverse proxy de cache

6.1. Configuração básica

proxy_cache_path /var/cache/nginx/pss_segments
    levels=1:2 keys_zone=pss_segments:100m
    max_size=20g inactive=30m use_temp_path=off;

proxy_cache_path /var/cache/nginx/pss_manifests
    levels=1:2 keys_zone=pss_manifests:10m
    max_size=256m inactive=5m use_temp_path=off;

upstream pss_backend {
    server 127.0.0.1:43972;
    keepalive 64;
}

map $uri $pss_cache_key {
    "~^/h[0-9a-f]{16}(?<tail>(/[0-9]+)?/[0-9a-f]{16}\.(ts|m4s)|/sub/[0-9]+/[0-9a-f]{16}\.vtt)$"  "stream:$tail";
    default  $uri;
}

server {
    listen 80;
    server_name stream.example.com;

    location ~* "^/h[0-9a-f]{16}(/[0-9]+|/sub/[0-9]+)?/([0-9a-f]+\.(ts|m4s|vtt)|init\.mp4)$" {
        proxy_cache               pss_segments;
        proxy_cache_key           $pss_cache_key;
        proxy_cache_valid         200 60s;
        proxy_cache_valid         404 403 0s;
        proxy_cache_lock          on;
        proxy_cache_use_stale     updating error timeout;
        proxy_cache_revalidate    on;
        proxy_ignore_headers      Vary;
        add_header                X-Cache-Status $upstream_cache_status;

        proxy_pass                http://pss_backend;
        proxy_http_version        1.1;
        proxy_set_header          Connection "";
        proxy_buffering           on;
    }

    location ~* "(^/h[0-9a-f]{16}(/[0-9]+|/sub/[0-9]+)?/index\.(m3u8|mpd)$|^/(hls|dash|llhls)/.*\.(m3u8|mpd)$)" {
        proxy_cache               pss_manifests;
        proxy_cache_key           $pss_cache_key;
        proxy_cache_valid         200 1s;
        proxy_cache_valid         404 403 0s;
        proxy_cache_lock          on;
        proxy_cache_lock_timeout  2s;
        proxy_cache_use_stale     updating;
        add_header                X-Cache-Status $upstream_cache_status;

        proxy_pass                http://pss_backend;
        proxy_http_version        1.1;
        proxy_set_header          Connection "";
    }

    location / {
        proxy_pass                http://pss_backend;
        proxy_http_version        1.1;
        proxy_set_header          Connection "";
        proxy_set_header          X-Forwarded-Proto $scheme;
        proxy_set_header          X-Forwarded-Host  $host;
        proxy_buffering           off;
        proxy_read_timeout        3600s;
    }
}

A porta do origin no exemplo é a porta padrão do servidor HTTP de streaming (43972; HTTPS — 43982). São normalizados apenas os nomes content-addressed dos segmentos (ver 3.3); os manifestos, o init.mp4 e os segmentos numerados são armazenados em cache pelo URI completo da sua sessão. A diretiva proxy_ignore_headers Vary no location dos segmentos é justificada: o servidor acompanha as respostas OTT com o cabeçalho Vary: Origin e, sem ela, o cache seria dividido em variantes conforme o valor de Origin do cliente (ver 7).

6.2. Finalidade das diretivas

Diretiva

Finalidade

proxy_cache_lock on

Serializa a execução das requisições upstream em cache miss simultâneos pela mesma chave

proxy_cache_use_stale updating

Retorna a cópia desatualizada às requisições paralelas durante o período de atualização do cache

proxy_cache_revalidate on

Utiliza If-Modified-Since em cache miss quando há uma cópia armazenada

proxy_cache_valid 404 403 0s

Proíbe o cache dos erros de autorização e dos 404

keepalive 64 no upstream

Mantém um pool de conexões persistentes com o origin

proxy_buffering on

Para os segmentos; ativa a bufferização da resposta no nginx

proxy_buffering off

Para a seção /; desativa a bufferização (raw streaming)

6.3. Cálculo do max_size do cache de segmentos

Valor aproximado: bitrate × timeShiftBufferDepth × distinct_streams × 2

Exemplo: 10 fluxos × 8 Mbps × 40 s × 2 ≈ 800 MB. Recomenda-se prever uma margem de 10x para levar em conta a variabilidade do bitrate.

6.4. Terminação TLS

O servidor Perfect Streamer aceita conexões nas portas HTTP e HTTPS. Com a terminação TLS no nginx, o upstream utiliza a porta HTTP. O encaminhamento dos cabeçalhos X-Forwarded-Proto e X-Forwarded-Host é obrigatório para a formação correta dos URLs absolutos com absPath=1.

server {
    listen 443 ssl http2;
    server_name stream.example.com;

    ssl_certificate           /etc/letsencrypt/live/stream.example.com/fullchain.pem;
    ssl_certificate_key       /etc/letsencrypt/live/stream.example.com/privkey.pem;
    ssl_protocols             TLSv1.2 TLSv1.3;
    ssl_session_cache         shared:SSL:10m;
    ssl_session_timeout       1d;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    location ... {
        proxy_pass                http://pss_backend;
        proxy_set_header          X-Forwarded-Proto https;
        proxy_set_header          X-Forwarded-Host  $host;
        proxy_set_header          Host              $host;
        # + caching directives from 6.1
    }
}

server {
    listen 80;
    server_name stream.example.com;
    return 301 https://$host$request_uri;
}

Com HTTPS entre o nginx e o origin aplicam-se as diretivas proxy_ssl_verify e proxy_ssl_trusted_certificate. Para conexões de loopback a criptografia é redundante.

6.5. Vários hosts

Ao atender vários server_name a partir de um único processo nginx, $host é adicionado à cache key para isolar o conteúdo:

map $uri $pss_cache_key {
    "~^/h[0-9a-f]{16}(?<tail>(/[0-9]+)?/[0-9a-f]{16}\.(ts|m4s)|/sub/[0-9]+/[0-9a-f]{16}\.vtt)$"  "$host:stream:$tail";
    default  "$host:$uri";
}

O tamanho de keys_zone é calculado como 8000 chaves/MB. Para instalações multi-host com milhares de fluxos recomenda-se keys_zone=...:300m ou superior.

7. Cache no lado do cliente

Cache-Control: immutable é processado pelos navegadores modernos. O cache do cliente retorna o segmento sem requisição condicional em um acesso repetido (inclusive em um seek para trás dentro do buffer do player).

Os Service Workers podem aplicar a estratégia cache-first com base no conteúdo de Cache-Control. Os players DASH utilizam MSE através de SourceBuffer; um segmento colocado no buffer permanece disponível sem uma nova requisição HTTP até sair do limite de deslizamento.

Para requisições entre domínios o servidor entrega Access-Control-Allow-Origin: * junto com o cabeçalho Vary: Origin, Access-Control-Request-Headers. Um proxy de cache que respeita Vary divide as entradas em variantes conforme o valor de Origin do cliente (os players de navegador enviam Origin, os de console não), o que reduz a HIT rate. Como o ACAO é o universal «*», é seguro adicionar proxy_ignore_headers Vary no location dos segmentos (ver 6.1).

8. Distribuição através de CDN

O Perfect Streamer é compatível com CDN no modo pull-from-origin.

Origin shield. Recomenda-se a colocação de um ou vários nós shield entre o CDN edge e o origin para reduzir a frequência de requisições ao origin quando os clientes estão distribuídos globalmente.

Purge. Os segmentos content-addressed não requerem purge. Quando os metadados do fluxo mudam (codec, resolução), os manifestos são atualizados dentro de max-age=1 sem purge explícito.

Cache warming. Quando se espera um aumento de carga sobre um fluxo específico, é admissível o aquecimento da CDN a partir de vários pontos geográficos antes do início da transmissão.

Distribuição geográfica. Os segmentos (max-age=60) são bem adequados ao cache geograficamente distribuído. Os manifestos (max-age=1) admitem um atraso de entrega de até um segundo — aceitável para a transmissão live sem baixa latência.

9. Monitoramento

9.1. X-Cache-Status

Adição de add_header X-Cache-Status $upstream_cache_status; a cada location com cache. Valores:

Valor

Descrição

HIT

Resposta a partir do cache

MISS

Ausente no cache, obtido do origin e armazenado

EXPIRED

Expirado, atualizado

UPDATING

Cópia stale entregue a uma requisição paralela durante a atualização

STALE

use_stale retornou uma cópia expirada (origin indisponível)

REVALIDATED

O origin retornou 304 Not Modified

BYPASS

proxy_cache_bypass foi acionado

9.2. Formato do access log

log_format pss_cache '$remote_addr $status $request_method "$request" '
                     '$body_bytes_sent rt=$request_time ut=$upstream_response_time '
                     'cache=$upstream_cache_status key=$pss_cache_key';

server {
    access_log /var/log/nginx/pss.log pss_cache;
}

9.3. Métricas

O módulo nginx-vts exporta métricas per-zone no formato Prometheus:

GET /status/format/prometheus

Limiares recomendados para alertas:

Métrica

Limiar

Causa possível

Segment HIT rate

< 90% em 5 minutos

Normalização da cache key comprometida; max_size pequeno

Manifest MISS rate

> 50% em 1 minuto

proxy_cache_lock não serializa as requisições

Upstream response time p95

> 500 ms em 1 minuto

Sobrecarga do origin

Cache zone fill

> 90% em 10 minutos

Aproximação do max_size, LRU-eviction prevista

A qualidade da entrega no lado do nó é visível nas métricas de sessão na tela «Clientes» (Clientes).

10. Diagnóstico

Sintoma

Causa provável

Solução

Segment HIT rate baixo

Vary: Origin divide o cache em variantes; violação da normalização no map

Adicionar proxy_ignore_headers Vary ao location dos segmentos; verificar o regex na diretiva map

404 nos segmentos após a saída da janela

404 armazenado em cache para um segmento que saiu da sliding window

Adicionar proxy_cache_valid 404 0s ao location segments

Atraso de playback start de 2–5 s

proxy_cache_lock_timeout excede a target latency

Reduzir para 1–2 s; ativar proxy_cache_use_stale updating

Manifest não é atualizado

proxy_ignore_headers Cache-Control está definido e vigora um proxy_cache_valid com TTL elevado

Indicar explicitamente proxy_cache_valid 200 1s ou deixar de ignorar os cabeçalhos

Crescimento de TIME_WAIT no upstream

Ausência de keepalive no bloco upstream

Adicionar keepalive 64, proxy_http_version 1.1, proxy_set_header Connection ""

403 em /dash/.../<segment>.m4s a partir de clientes de console

O cliente resolve os URLs relativos a partir do URL anterior ao redirecionamento

O servidor emite <BaseURL> com caminho absoluto; compatível no build atual

Travamentos e rebuffering frequente em clientes remotos

Throughput TCP efetivo baixo devido a slow start e idle restart com RTT elevado (300 ms e acima)

Ajuste da pilha de rede do Linux no origin: ver 10.1

10.1. Ajuste TCP do origin para clientes de alto RTT

O problema manifesta-se em clientes com RTT elevado até o origin (por exemplo, 300 ms e acima) quando o bitrate do fluxo está próximo da capacidade do canal. Os sintomas no player são rebuffering frequente e interrupções; no servidor, o cliente aparenta estar normal e não há erros.

Causa:

  • TCP slow start. Cada nova conexão TCP começa com uma congestion window de cerca de 14 KB e aumenta-a ao longo de vários RTT. Com RTT de 300 ms, atingir a janela completa leva 2–3 segundos. Nesse tempo, um segmento HLS/DASH com duração de 5 s (4–6 MB) é baixado sensivelmente mais devagar do que em tempo real.

  • TCP idle restart. Entre as requisições de segmentos, o cliente no modelo pull do HLS faz uma pausa de 4–5 s. Por padrão, após tal pausa o kernel do Linux redefine a congestion window da conexão de volta ao initial cwnd (comportamento de net.ipv4.tcp_slow_start_after_idle=1). Como resultado, no GET seguinte a conexão keep-alive inicia a transmissão a partir do slow start novamente — mesmo em uma sessão já aquecida.

Adicionalmente, a situação é agravada pelo fato de que o congestion control CUBIC padrão lida mal com RTT longos e com perdas de pacotes em trechos intermediários da rede.

A solução consiste em dois parâmetros sysctl no origin:

# Keep congestion window across idle pauses inside keep-alive sessions.
sysctl -w net.ipv4.tcp_slow_start_after_idle=0

# Use BBR instead of CUBIC: better behaviour on long-RTT paths
# with mild packet loss; paces sending instead of bursting.
modprobe tcp_bbr
sysctl -w net.ipv4.tcp_congestion_control=bbr

Para aplicação permanente:

cat > /etc/sysctl.d/99-pss-net.conf <<EOF
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_congestion_control    = bbr
EOF
sysctl --system

O efeito principal vem do primeiro parâmetro (tcp_slow_start_after_idle=0) — ele elimina diretamente o slow start repetido entre as requisições de segmentos dentro de uma mesma conexão keep-alive. O segundo (BBR) confere robustez adicional e aplica-se a todas as novas conexões. O ajuste não requer a reinicialização do Perfect Streamer. Aos clientes HTTP/3 (QUIC) esses parâmetros não se aplicam: o QUIC funciona sobre UDP com o seu próprio controle de congestionamento.

11. Segurança

11.1. Session URL

Um URL do formato /h<sess>/... desempenha a função de token de sessão — não requer autenticação repetida. O tempo de vida é limitado por um timeout de inatividade de 60 segundos; na ausência de atividade a sessão é removida automaticamente.

Requisitos:

  • HTTPS para todos os caminhos OTT (/hls/, /dash/, /h<sess>/) em produção;

  • O Session ID no cabeçalho Location da resposta 302 não é armazenado em cache (no-cache, no-store).

11.2. Rate limiting

limit_req_zone $binary_remote_addr zone=dash_top:10m  rate=5r/s;
limit_req_zone $binary_remote_addr zone=hls_top:10m   rate=5r/s;
limit_req_zone $binary_remote_addr zone=llhls_top:10m rate=5r/s;

server {
    location /dash/ {
        limit_req zone=dash_top burst=20 nodelay;
        proxy_pass http://pss_backend;
    }
    location /hls/ {
        limit_req zone=hls_top burst=20 nodelay;
        proxy_pass http://pss_backend;
    }
    location /llhls/ {
        limit_req zone=llhls_top burst=20 nodelay;
        proxy_pass http://pss_backend;
    }
}

O Session URL (/h<sess>/) não requer rate limiting — o processamento é barato e as respostas são armazenadas em cache.

11.3. Cache das respostas com erro

proxy_cache_valid 200 60s;
proxy_cache_valid 301 302 0s;
proxy_cache_valid 404 403 0s;
proxy_cache_valid any 1s;

Proíbe o cache dos redirecionamentos (sess único em Location) e das respostas com erros de autorização ou de recurso inexistente.

11.4. Restrição do acesso de rede ao origin

A porta do servidor HTTP de streaming (43972 por padrão; 43982 para HTTPS) deve estar fechada ao tráfego externo. Configurações admissíveis:

  1. Bind do Perfect Streamer em 127.0.0.1 (com nginx local)

  2. Regra de firewall:

iptables -A INPUT -p tcp -m multiport --dports 43972,43982 ! -s 10.0.0.0/8 -j DROP

12. Integração com middleware

12.1. Modelo prefix-login

O Perfect Streamer suporta a delegação da identificação do usuário a um sistema de middleware através do mecanismo prefix-login — uma alternativa integrada à integração completa com o faturamento externo (as contas verificadas por um sistema externo são configuradas na tela «Usuários / Logins», aba «Remoto (faturação)», Usuários / Logins).

No login local é ativado o indicador de prefixo, após o que o servidor aceita URLs com um login da forma <prefix><id_do_assinante>:

/dash/test1/sub42/xxx/index.mpd
/hls/test1/sub43/xxx/index.m3u8

Aqui sub é o prefixo de login configurado e 42/43 são os identificadores dos assinantes do middleware; a senha é comum.

12.2. Estatísticas por assinante

Na lista de clientes, cada sessão carrega tanto o login de configuração quanto o login de URL real do assinante (match-login), pelo qual o middleware associa as sessões aos seus próprios assinantes. Os dados são visíveis na tela «Clientes» (Clientes).

12.3. Limitações do prefix-login

  • Senha comum. Todos os assinantes do pool de prefixo utilizam um único valor de senha. O comprometimento da senha concede acesso a qualquer <prefix><cadeia>.

  • Granularidade de acesso. A lista de fluxos permitidos aplica-se a todo o pool de prefixo. O acesso ao nível de um assinante individual é assegurado pela integração com o faturamento externo.

  • Rotação da senha. A alteração da senha desconecta todos os assinantes ativos. Para uma substituição gradual é necessário o uso temporário de dois prefix-logins.