TTL (Time To Live) é um parâmetro que determina o tempo máximo durante o qual os dados são considerados válidos. Após a expiração do TTL, o registro é marcado como obsoleto (stale) e deve ser excluído ou atualizado. De acordo com Mozilla Developer Network (2026), o mecanismo TTL é a base do cache HTTP através do cabeçalho Cache-Control: max-age e é usado em todos os navegadores modernos e aplicativos móveis para otimizar requisições de rede.
Pontos Principais
TTL (Time To Live) é um timestamp ou intervalo após o qual os dados são considerados inválidos. No contexto do cache, o TTL determina por quanto tempo um registro pode ser armazenado no cache antes de precisar ser reobtido da fonte. Em protocolos de rede, o TTL limita o tempo de vida de um pacote, evitando roteamento infinito.
O valor TTL é sempre expresso em unidades de tempo: milissegundos, segundos, minutos ou horas. Após o término do tempo definido, o registro é excluído do cache ou marcado como obsoleto. Na próxima requisição a um registro obsoleto, o sistema pode retornar os dados obsoletos com uma atualização subsequente (stale-while-revalidate) ou bloquear a requisição até obter dados frescos.
Escolher o TTL é sempre um compromisso entre a atualidade dos dados e o desempenho. Um TTL muito curto (1–5 segundos) força o aplicativo a fazer requisições de rede frequentes, anulando o benefício do cache. Um TTL muito longo (horas/dias) aumenta o risco de mostrar informações desatualizadas ao usuário. O valor ótimo depende do tipo de dados: taxas de câmbio — segundos, clima — minutos, versão de API — horas.
TTL é invalidação passiva: os dados são removidos automaticamente após um período de tempo. A alternativa é a invalidação ativa, onde a fonte de dados notifica o cache sobre as mudanças (por exemplo, através de mensagens WebSocket ou notificações push). A invalidação passiva via TTL é mais simples de implementar, mas não garante atualidade instantânea. A invalidação ativa é mais complexa, mas permite manter os dados atualizados sem os atrasos inerentes ao TTL.
O mecanismo TTL pode ser implementado de duas maneiras: expiração absoluta (absolute expiration) e expiração relativa (relative expiration). Com a expiração absoluta, o registro armazena o momento específico em que se tornará inválido. Com a expiração relativa, o momento de criação do registro e o TTL como intervalo são registrados, e a verificação é feita calculando creationTime + TTL > currentTime.
Em cada requisição ao cache, o sistema verifica o TTL de cada registro. Se o TTL expirou, os dados são excluídos ou marcados como obsoletos, e a requisição é encaminhada à fonte. Para otimizar a verificação do TTL, pode-se usar limpeza programada (eliminação periódica de todos os registros expirados) ou limpeza preguiçosa (eliminação apenas quando o registro é acessado). A limpeza preguiçosa é mais eficiente em memória, pois não requer uma thread em segundo plano para escanear todo o cache.
Em sistemas distribuídos, o TTL também é usado para resolução automática de conflitos. Por exemplo, se dois servidores escreverem valores diferentes para a mesma chave simultaneamente, o registro com TTL posterior pode ser considerado prioritário. O Amazon DynamoDB usa TTL para exclusão automática de registros obsoletos em tabelas — este é um recurso incorporado que não requer gerenciamento manual.
Para melhorar o desempenho quando o TTL expira, são usadas estratégias de leitura obsoleta. Stale-while-revalidate — retornar imediatamente os dados obsoletos ao cliente e simultaneamente iniciar uma atualização em segundo plano. Stale-if-error — retornar dados obsoletos se a fonte estiver temporariamente indisponível. Cache-Aside (Lazy Loading) — em caso de falta no cache, carregar os dados da fonte, salvar no cache com novo TTL e só então retornar ao cliente. Cada estratégia é escolhida com base nos requisitos de consistência dos dados.
Em aplicativos móveis, o TTL é um mecanismo chave para gerenciamento de cache. Vamos ver os principais cenários onde o TTL determina o comportamento do aplicativo e a experiência do usuário.
O protocolo HTTP fornece um mecanismo TTL incorporado através dos cabeçalhos Cache-Control. A diretiva max-age define o TTL em segundos: Cache-Control: public, max-age=3600 significa que a resposta pode ser armazenada em cache por 1 hora. Diretivas adicionais s-maxage (para caches compartilhados, ex.: CDN) e stale-while-revalidate fornecem controle mais preciso. Quando o TTL coincide com o cabeçalho expires, o max-age tem prioridade como o padrão HTTP/1.1 mais moderno.
| Tipo de dados | TTL recomendado | Justificativa |
|---|---|---|
| Clima | 10–30 minutos | Previsões não são atualizadas frequentemente |
| Taxas de câmbio | 15–60 segundos | Alta volatilidade |
| Feed de notícias | 2–5 minutos | Equilíbrio entre atualidade e desempenho |
| Perfil do usuário | 5–30 minutos | Raramente muda durante uma sessão |
| Lista de produtos | 10–60 minutos | Preços não mudam a cada segundo |
| Recursos estáticos | 1–24 horas | Versionados via URL ou ETag |
Para imagens, o TTL pode atingir vários dias, já que o conteúdo raramente muda. No entanto, aplicativos móveis geralmente usam uma abordagem híbrida: TTL curto para pré-visualizações (30 minutos — atualidade dos quadros) e TTL longo para imagens em tamanho real (7 dias). Imagens com o cabeçalho HTTP Cache-Control: immutable não devem ser re-requisitadas até a expiração do TTL — esta é uma otimização para recursos estáticos proposta na RFC 8246. Essas imagens são armazenadas em cache no nível do SO (URLCache, OkHttp Cache) sem envolvimento do aplicativo.
Em redes, o TTL não é usado para cache, mas para limitar o tempo de vida dos pacotes. Cada pacote IP contém um campo TTL (8 bits), que é diminuído em 1 por cada roteador. Quando o TTL chega a 0, o pacote é descartado e o remetente recebe uma mensagem ICMP Time Exceeded. Isso evita o roteamento infinito durante loops de rede.
Os registros DNS têm um TTL que determina por quanto tempo um resolvedor (por exemplo, cache DNS do ISP) pode armazenar o registro sem consultar o servidor autoritativo. Valores típicos: 300 segundos (5 minutos) para registros com alterações frequentes, 86400 segundos (24 horas) para domínios estáveis. Serviços CDN geralmente definem TTL baixo (60–300 segundos) para redirecionamento rápido de tráfego durante falhas, enquanto domínios estáticos podem ter TTL de até 7 dias. Ao migrar um servidor, recomenda-se primeiro reduzir o TTL para 60 segundos (48 horas antes da migração) para que as mudanças se propaguem rapidamente.
Em aplicativos móveis, o TTL é usado para gerenciar sessões e tokens de acesso. Tokens JWT (JSON Web Tokens) contêm um campo exp (tempo de expiração), que é o tempo Unix absoluto de expiração. Após a expiração, um token de atualização é usado para obter um novo token de acesso sem reautenticação. O TTL do token de acesso geralmente é de 1–24 horas, o TTL do token de atualização é de 7–30 dias. Este é um equilíbrio entre segurança (TTL curto reduz o risco de vazamento) e UX (TTL longo reduz a frequência de novos logins).
Escolher o TTL é uma decisão de engenharia que depende do tipo de dados, SLA de atualidade e custo de uma nova requisição. Vamos considerar as principais estratégias.
A abordagem mais simples — todos os registros têm o mesmo TTL. Por exemplo, armazenar em cache todas as respostas de API por 5 minutos. Vantagem: simplicidade de implementação e comportamento previsível. Desvantagem: não leva em conta as diferentes frequências de mudança dos diferentes tipos de dados. O TTL fixo é justificado para dados homogêneos onde todos os registros têm a mesma “Atualidade” — por exemplo, taxas de criptomoedas em uma mesma bolsa.
O TTL muda dinamicamente com base no comportamento dos dados. Por exemplo, se um registro raramente é atualizado no servidor, o TTL aumenta; se é atualizado com frequência, diminui. A implementação pode usar cabeçalhos de resposta HTTP: o cabeçalho Age (quantos segundos a resposta já está no cache) e o cabeçalho Date permitem calcular o tempo de vida restante. O TTL adaptativo proporciona uma melhor taxa de acerto, mas requer lógica adicional no cliente.
Probabilistic Early Expiration (PEE) — uma técnica onde o TTL é escolhido aleatoriamente dentro de um intervalo determinado. Isso evita o efeito “manada atropeladora” (thundering herd), onde muitas requisições expiram simultaneamente e todos os clientes acessam a fonte ao mesmo tempo. PEE é especialmente útil para CDNs e caches de alta carga: em vez de um único TTL de 300 segundos, usa-se um valor aleatório de 240 a 360 segundos, distribuindo a carga na fonte uniformemente.
Vamos ver uma implementação de cache com TTL em Kotlin usando expiração absoluta. Cada registro armazena seu momento de criação e, ao ler, verifica-se se o TTL expirou.
class TtlCache<K, V>(
private val defaultTtlMs: Long = 300000L
) {
private data class Entry<V>(
val value: V,
val createdAt: Long = System.currentTimeMillis()
)
private val map = ConcurrentHashMap<K, Entry<V>>()
fun get(key: K): V? {
val entry = map[key] ?: return null
if (isExpired(entry)) {
map.remove(key)
return null
}
return entry.value
}
fun put(key: K, value: V, ttlMs: Long = defaultTtlMs) {
map[key] = Entry(value, createdAt = System.currentTimeMillis() + ttlMs)
}
private fun isExpired(entry: Entry<*>): Boolean {
return System.currentTimeMillis() > entry.createdAt
}
fun cleanup() {
map.entries.removeIf { isExpired(it.value) }
}
}
A classe Entry armazena o valor e o momento de criação + TTL (expiração absoluta). O método get verifica a expiração em cada acesso (limpeza preguiçosa) — registros expirados são excluídos apenas quando se tenta acessá-los. O método cleanup pode ser chamado periodicamente de uma thread em segundo plano para excluir em lote todos os registros obsoletos. ConcurrentHashMap fornece segurança de threads sem bloquear todo o cache.
No iOS, é conveniente usar URLCache com as configurações memoryCapacity e diskCapacity para cache com TTL. No entanto, o URLCache não suporta TTL individual para diferentes requisições. Vamos considerar um wrapper personalizado do NSCache com suporte a TTL.
final class ApiResponseCache {
private var cache = NSCache<NSString, CacheEntry>()
func getResponse(for url: URL) -> Data? {
guard let entry = cache.object(forKey: url.absoluteString as NSString)
else { return nil }
guard entry.expirationDate > Date() else {
cache.removeObject(forKey: url.absoluteString as NSString)
return nil
}
return entry.data
}
func storeResponse(data: Data, for url: URL, ttl: TimeInterval) {
let entry = CacheEntry(data: data, expirationDate: Date().addingTimeInterval(ttl))
cache.setObject(entry, forKey: url.absoluteString as NSString)
}
}
final class CacheEntry: NSObject {
let data: Data
let expirationDate: Date
}
Nesta implementação, o NSCache é usado como armazenamento thread-safe. CacheEntry contém Data e expirationDate. Quando get é chamado, verifica-se se o tempo expirou; se sim, o registro é excluído e nil é retornado. O TTL é definido em segundos via TimeInterval e pode ser diferente para cada URL: valores típicos para respostas de API são 120 segundos para conteúdo dinâmico e 3600 para dados estáticos.
Perguntas Frequentes
Tecnicamente, TTL e data de expiração são a mesma coisa: um intervalo de tempo após o qual os dados são considerados inválidos. A diferença está no contexto: o termo TTL é usado em TI (cache, redes, DNS), enquanto “data de expiração” é mais aplicado na lógica de negócios (códigos promocionais, assinaturas). Na implementação, ambos os mecanismos são idênticos — comparação do tempo atual com o tempo de expiração.
O TTL ideal é escolhido empiricamente. Metodologia: comece com um valor conservador (30–60 segundos), aumente gradualmente até surgirem reclamações sobre dados desatualizados. Monitore a taxa de acerto do cache: se for inferior a 70%, o TTL é muito curto. Considere o SLA: para dados financeiros, o TTL pode ser de 1 segundo; para notícias — 5 minutos; para perfis — 30 minutos.
Após a expiração do max-age, o navegador ou aplicativo móvel considera a resposta obsoleta. Na próxima requisição à mesma URL, o cliente envia uma requisição com o cabeçalho If-None-Match (ETag) ou If-Modified-Since. Se os dados não mudaram, o servidor retorna 304 Not Modified sem corpo de resposta e o TTL é atualizado. Se mudaram, o servidor retorna 200 com novos dados e novo Cache-Control.
Tecnicamente, o TTL pode ser muito grande (max-age=31536000 — 1 ano), mas isso raramente é justificado. Até recursos estáticos podem mudar, e o cliente não saberá até a expiração do TTL. Recomenda-se usar URLs versionadas (style.css?v=2) com TTL longo: quando o arquivo muda, a URL muda e o cache antigo se torna obsoleto automaticamente.
TTL e estratégias de despejo (LRU, FIFO) resolvem problemas diferentes. TTL determina quando os dados se tornam irrelevantes — este é um critério temporal. LRU e FIFO determinam quais dados remover quando o cache está cheio — este é um critério espacial. Eles podem ser combinados: um registro é excluído se o TTL expirou OU o cache está cheio (por LRU/FIFO). Em sistemas de produção, ambos os mecanismos trabalham juntos.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também