# Retro: EMR Serverless em IPv6-only e a subnet que ficou sem DNS64

O EMR Serverless passou a aceitar subnets dual-stack e IPv6-only em 16/10/2026, sem custo adicional e em todas as release versions. O recurso resolve a falta de IPv4 em subnets compartilhadas, mas transfere para você a prontidão da rede: DNS64, rota NAT64, egress-only gateway e endpoints. Escrevi o retro do incidente que eu esperaria na primeira noite de batch, para que ele não precise acontecer.

- URL: https://fernando.moretes.com/blog/retro-emr-serverless-em-ipv6-only-e-a-subnet-que-ficou-sem-dns64

- Markdown: https://fernando.moretes.com/blog/retro-emr-serverless-em-ipv6-only-e-a-subnet-que-ficou-sem-dns64/article.md?lang=pt

- Published: 2026-10-20T10:14:19.550Z

- Category: AWS & Cloud

- Tags: emr-serverless, ipv6, vpc, nat64, spark, finops, resiliencia

- Reading time: 7 min

- Source: [Amazon EMR Serverless now supports IPv6 and dual-stack connectivity](https://aws.amazon.com/about-aws/whats-new/2026/10/amazon-emr-serverless/)

---

A pergunta perigosa sobre o IPv6 no EMR Serverless não é "meus jobs rodam em IPv6?", é "o que cada subnet da aplicação sabe fazer quando um job pede um endereço que só existe em IPv4?". O anúncio de 16/10/2026 é curto: Spark e Hive passam a rodar em subnets dual-stack ou IPv6-only, sem custo adicional, em todas as regiões e release versions do serviço. A documentação é mais honesta que o anúncio: o modo de endereçamento é derivado das subnets, e a responsabilidade de fazer o tráfego IPv6 chegar aos seus dados é sua. Este texto é um retro antecipado, um incidente que não aconteceu, montado a partir da documentação e dos modos de falha que ela mesma lista. Prefiro escrever o postmortem antes do que depois.

## O cenário: subnets /22 que não cabem mais três aplicações

O ponto de partida é o que a própria AWS usa como exemplo de planejamento. Cada worker do EMR Serverless consome um endereço IP na subnet em que sobe, por meio de uma ENI. Uma aplicação com workers de 4 vCPU e teto de 4.000 vCPU chega a 1.000 workers, ou seja, 1.000 ENIs. Uma subnet /22 tem 1.024 endereços e 1.019 utilizáveis, porque a AWS reserva cinco. Com três aplicações dividindo as mesmas subnets e uma cota de 12.000 vCPU na conta, a recomendação da documentação vira 3.000 endereços livres por subnet, em pelo menos duas zonas de disponibilidade.

Em plataforma de dados de banco, isso costuma bater num muro: o bloco IPv4 da VPC foi negociado com o time de rede corporativa anos atrás, não sobrepõe com o on-premises e não cresce sem uma rodada de aprovação. É exatamente o caso que o IPv6 resolve. Uma subnet IPv6 da VPC é um /64, e a conversa sobre endereço acaba.

No cenário, o time decide ir direto para IPv6-only em três subnets, uma por AZ, criadas por um módulo de IaC. Duas foram montadas à mão no piloto e receberam DNS64. A terceira veio do módulo, que não sabia que DNS64 existia. Nenhum teste de integração pegou isso, porque o job de teste rodou duas vezes e caiu nas duas subnets boas.

## Os números que movem a decisão

- **1.000**: ENIs por aplicação. Workers de 4 vCPU com teto de 4.000 vCPU: um IP por worker
- **1.019**: IPs utilizáveis num /22. Mal cabe uma aplicação; três exigem 3.000 por subnet
- **US$ 0,045/GB**: Processamento no NAT gateway. Exemplo da página de preços (US East Ohio): todo byte via NAT64 paga

## Linha do tempo do incidente simulado

1. **D-7: troca de subnets**: O time para a aplicação, roda `update-application` com as três subnets IPv6-only no `--network-configuration` e inicia de novo. O modo é avaliado a cada start, então a mudança só vale depois do restart. Dois jobs de teste passam.

2. **02:00: o batch noturno começa**: Cerca de um terço dos jobs falha com `UnknownHostException` ao chamar endpoints que só publicam registro A. Cada job roda em uma única subnet escolhida do conjunto, e os que caíram na subnet sem DNS64 não resolvem nada que não seja IPv6.

3. **02:40: o retry esconde o padrão**: A política de retry do orquestrador reenvia os jobs. Parte passa porque cai em outra subnet. A falha parece intermitente, e intermitente vira "rede instável" na primeira hipótese do plantão.

4. **04:10: correlação por subnet**: Alguém abre o detalhe de cada job run, que mostra a subnet usada, e cruza com sucesso e falha. 100% das falhas estão na mesma subnet. `modify-subnet-attribute --enable-dns64` resolve a resolução de nomes.

5. **05:00: a segunda falha**: Um job de ingestão com driver JDBC antigo falha com `UnresolvedAddressException`. Havia `-Djava.net.preferIPv4Stack=true` em `spark.driver.extraJavaOptions`, um contorno de anos atrás. A documentação proíbe forçar a pilha IPv4 em qualquer modo.

6. **D+5: a conta chega**: O Cost Explorer mostra salto em processamento de dados do NAT gateway. As leituras do S3, que antes saíam pelo gateway endpoint, agora resolvem via DNS64 para `64:ff9b::/96` e atravessam o NAT64.

> **Causa raiz:** O EMR Serverless deriva o modo de endereçamento das subnets e não valida se a rede está pronta para ele. A prontidão de cada subnet (CIDR IPv6, auto-assign, DNS64, rota `64:ff9b::/96` para o NAT gateway, rota `::/0` para o egress-only gateway) não estava codificada no módulo de IaC, e a seleção de uma subnet por job transformou um defeito determinístico em falha aparentemente aleatória.

## Por que a falha parecia aleatória: as regras do modo de endereçamento

Vale entender as regras antes de culpar a rede. Subnet só IPv4 roda como sempre rodou. Subnet dual-stack roda IPv4 até você ligar `spark.emr-serverless.networking.ipv6.enabled=true` no `spark-defaults` da aplicação (para Hive, `hive.emr-serverless.networking.ipv6.enabled` no `hive-site`). Subnet IPv6-only roda IPv6 sem propriedade nenhuma.

Quando o conjunto mistura tipos, a aplicação inteira roda no único modo que todas suportam. IPv4-only com IPv6-only é rejeitado na validação. IPv6-only com dual-stack roda tudo em IPv6-only, inclusive as subnets dual-stack, que então precisam cumprir os mesmos pré-requisitos. IPv4-only com dual-stack roda tudo em IPv4.

Três detalhes produzem incidente:

- **O modo vale no start:** uma aplicação em execução mantém o modo com que subiu. Você corrige a subnet e nada muda até o próximo `stop`/`start`.
- **Um job, uma subnet:** o job roda em uma única subnet escolhida da lista. Uma subnet defeituosa entre três falha um terço das vezes, e retry mascara.
- **Dual-stack não prefere IPv6 por padrão:** mesmo com o opt-in ligado, o engine usa IPv4 até você setar `spark.emr-serverless.driverEnv.SPARK_PREFER_IPV6` e `spark.executorEnv.SPARK_PREFER_IPV6`. Setar isso numa subnet só IPv4 derruba o job.

A lição: o modo de endereçamento é estado derivado, não configurado. A API não deixa você declarar o modo; ela deixa você declarar subnets e deduz o resto. Estado derivado precisa de teste que prove a derivação em cada subnet, não na média.

## Por onde sai cada byte de um job em subnet IPv6-only

O caminho depende do registro DNS do destino: AAAA sai direto, A vira `64:ff9b::/96` e paga NAT64.

### 🟧 AWS: subnet IPv6-only (uma por AZ)

- Spark driver SPARK_PREFER_IPV6 automático (compute)
- Executors 1 ENI IPv6 por worker (compute)

### 📡 VPC: resolução e rotas

- Route 53 Resolver DNS64 na subnet (network)
- NAT gateway rota 64:ff9b::/96 (NAT64) (network)
- Egress-only IGW rota ::/0 (network)
- Interface endpoints Glue, STS, KMS, Logs (security)

### 🌐 Destinos

- S3 dual-stack s3.dualstack.<region> (storage)
- Endpoint só IPv4 JDBC legado, API pública (external)
- Endpoint IPv6 AAAA publicado (external)

### Fluxos

- drv -> r53: consulta DNS
- exe -> r53: consulta DNS
- r53 -> nat: só registro A: sintetiza 64:ff9b::
- nat -> v4: traduz para IPv4, cobra por GB
- exe -> eigw: destino com AAAA
- eigw -> s3ds: leitura e escrita de dados
- eigw -> v6: saída sem entrada
- drv -> vpce: catálogo, credenciais, chaves

## Remediação de rede: transformar pré-requisito em invariante

A correção do DNS64 levou um comando. A remediação que impede a reincidência levou mais trabalho, e é ela que importa.

**Módulo de subnet com contrato:** o módulo de IaC passa a exigir, para toda subnet marcada como destino de EMR Serverless, `assign_ipv6_address_on_creation = true`, `enable_dns64 = true`, rota `64:ff9b::/96` para o NAT gateway e rota `::/0` para o egress-only internet gateway. O auto-assign só vale para recursos criados depois da mudança, então ligar tarde não conserta ENI que já existe.

**Validação antes do apply:** uma checagem no pipeline (policy as code ou um teste que lê `describe-subnets` e `describe-route-tables`) falha o deploy se qualquer subnet do conjunto não cumprir o contrato. Validação que roda depois do incidente é postmortem, não controle.

**Canário por subnet:** como o job escolhe a subnet e você não, crio uma aplicação canário com uma subnet só, uma para cada AZ. Um job Spark mínimo resolve e conecta nos endpoints de que o batch depende (catálogo, STS, KMS, o bucket de dados, o banco de origem) e falha alto. Roda antes da janela do batch e depois de qualquer mudança de rede.

**JVM limpa:** varredura em todas as `sparkSubmitParameters` e `runtimeConfiguration` atrás de `preferIPv4Stack`. Um contorno de 2019 não pode decidir a pilha de rede de 2026.

Nada disso é sofisticado. O custo dele não é escrever, é manter o contrato quando alguém criar a quarta subnet daqui a dezoito meses sem ler este documento.

## O custo que o anúncio não menciona: NAT64 e o S3

"Sem custo adicional" é verdade para o recurso. Não é verdade para o caminho que o tráfego passa a percorrer.

Em subnet IPv6-only, todo destino que só publica registro A recebe um endereço sintetizado em `64:ff9b::/96`, e essa rota aponta para o NAT gateway. O NAT gateway cobra por hora e por GB processado; a página de preços da VPC usa US$ 0,045 por GB como exemplo em US East (Ohio). Uma plataforma que lê 8 TB por noite do S3 e manda isso pelo NAT64 paga cerca de US$ 360 por noite só de processamento, algo como US$ 10.800 em 30 noites. O gateway endpoint do S3 na subnet do workload não pega esse tráfego, porque o destino deixou de ser um prefixo IPv4.

O S3 só atende IPv6 pelos endpoints dual-stack (`s3.dualstack.<region>.amazonaws.com`), e o cliente precisa pedir isso explicitamente. Antes de medir, não confie: compare `BytesOutToDestination` do NAT gateway antes e depois da troca.

Outros serviços exigem o mesmo cuidado. Na tabela de suporte a IPv6 da AWS, o Glue tem dual-stack e endpoint privado com IPv6, mas o endpoint público não; o Lake Formation também só tem IPv6 pelo endpoint privado. Em IPv6-only, isso quer dizer interface endpoint para catálogo e permissões, ou NAT64 pago em cada chamada.

E a segurança: a documentação do S3 avisa que políticas com `aws:SourceIp` só em IPv4 fazem clientes perderem ou ganharem acesso indevidamente quando passam a usar IPv6. Revise toda bucket policy antes da troca, não depois.

## Os três modos lado a lado
| Critério | IPv4-only | Dual-stack com opt-in | IPv6-only |
| --- | --- | --- | --- |
| Consumo de IPv4 | 1 por worker | 1 por worker, continua consumindo | Zero |
| Ativação | - | `ipv6.enabled` na aplicação + `SPARK_PREFER_IPV6` no job | Automática pelas subnets |
| Destinos só IPv4 | Direto | Direto por IPv4 | Só com DNS64 + NAT64, pago por GB |
| Risco de incidente | Esgotar a subnet no pico | Baixo: falha volta para IPv4 | Alto se qualquer subnet ou dependência não estiver pronta |
| Quando usar | Folga de endereço e sem mandato de IPv6 | Transição e validação de dependências | Mandato de compliance ou esgotamento real, com dependências mapeadas |

## Leitura pelo Well-Architected

- **security**: Endereço IPv6 é globalmente único: saída só por egress-only gateway, nunca rota `::/0` para o internet gateway nas subnets de workers. O EMR Serverless já recusa security group com porta aberta para `0.0.0.0/0` ou `::/0`. Revise `aws:SourceIp` em bucket policies e prefira `aws:SourceVpce`.
- **reliability**: Espalhe subnets por pelo menos duas AZs, como a documentação recomenda, mas trate cada uma como unidade de falha própria: canário por subnet e alarme por subnet. Retry automático sem correlação por subnet converte defeito determinístico em ruído.

## Anti-padrões que este retro tenta evitar

- **Validar com dois jobs:** com três subnets e uma escolhida por job, dois jobs verdes não provam nada sobre a terceira.
- **Ir direto para IPv6-only sem inventário de dependências:** cada driver, SDK e endpoint que o job toca precisa suportar IPv6 ou passar por NAT64; o EMR Serverless não altera o código nem o endpoint de terceiros.
- **Ligar `SPARK_PREFER_IPV6` como padrão global:** em subnet só IPv4 a preferência derruba o job.
- **Corrigir a subnet e não reiniciar a aplicação:** o modo foi fixado no start, e o plantão conclui que a correção não funcionou.

> **O que eu faria:** Eu começaria por dual-stack com opt-in, numa aplicação nova, e deixaria a preferência por IPv6 ligada só nos jobs cujas dependências eu já medi. IPv6-only fica para quando houver mandato ou esgotamento real, e só depois de duas semanas de canário por subnet verde e de um gráfico de bytes no NAT gateway que eu consiga explicar linha a linha. A lição que tirei de outras migrações de rede é que o defeito quase nunca está no serviço novo, está na subnet que alguém criou com o módulo velho. Por isso o contrato mora no IaC, não na wiki.

## Lições e recomendação

Adote o IPv6 no EMR Serverless quando o espaço IPv4 das subnets compartilhadas já limita o teto de vCPU ou quando houver exigência formal de IPv6. Use dual-stack com opt-in enquanto houver dependência só IPv4 relevante em volume; use IPv6-only quando todas as dependências publicarem AAAA ou estiverem atrás de interface endpoint, e o NAT64 ficar restrito a chamadas de controle. Em qualquer caso, codifique DNS64, rotas e auto-assign no módulo de subnet, rode canário por subnet e meça o NAT gateway antes de declarar a migração concluída. O recurso é gratuito; a rede mal preparada cobra por GB.

**Rating:** Adote com dual-stack primeiro / Adopt wi

## Referências

- [Amazon EMR Serverless now supports IPv6 and dual-stack connectivity (AWS What's New, 16/10/2026)](https://aws.amazon.com/about-aws/whats-new/2026/10/amazon-emr-serverless/)
- [Configure IPv6 subnets for EMR Serverless applications](https://docs.aws.amazon.com/emr/latest/EMR-Serverless-UserGuide/ipv6-subnets.html)
- [Configuring VPC access for EMR Serverless applications (subnet planning)](https://docs.aws.amazon.com/emr/latest/EMR-Serverless-UserGuide/vpc-access.html)
- [DNS64 and NAT64 (Amazon VPC User Guide)](https://docs.aws.amazon.com/vpc/latest/userguide/nat-gateway-nat64-dns64.html)
- [Egress-only internet gateway (Amazon VPC User Guide)](https://docs.aws.amazon.com/vpc/latest/userguide/egress-only-internet-gateway.html)
- [AWS services that support IPv6](https://docs.aws.amazon.com/vpc/latest/userguide/aws-ipv6-support.html)
- [Making requests to Amazon S3 over IPv6](https://docs.aws.amazon.com/AmazonS3/latest/developerguide/ipv6-access.html)
- [Amazon VPC pricing (NAT gateway)](https://aws.amazon.com/vpc/pricing/)
