Federação Geográfica
← Voltar ao Índice da Documentação | Referência de Configuração | Guia de Operações
Visão Geral
OmniMessage usa federação baseada em HTTP com um modelo de pull para implantações multi-controlador em centros de dados ou regiões. Cada controlador opera de forma independente — gerenciando sua própria fila de mensagens, tabela de roteamento e conjunto de frontends conectados. Os controladores se descobrem através de registros DNS SRV (ou configuração estática), trocando informações de saúde e registro de frontends via HTTPS.
Quando o roteamento determina que uma mensagem pertence a um site remoto, a mensagem permanece na Mnesia do controlador de origem. Uma notificação leve é enviada ao controlador de destino, o que aciona uma consulta imediata. O FederationPoller do controlador de destino consulta periodicamente (e mediante notificação) os pares de origem em busca de mensagens destinadas aos seus frontends locais, as armazena em cache e as torna disponíveis para os frontends locais. Após a entrega, o controlador de destino reporta o status de entrega de volta ao origem.
Características Principais
| Aspecto | Detalhe |
|---|---|
| Rede | Funciona sobre qualquer WAN, incluindo links não confiáveis |
| Estado compartilhado | Nenhum — cada controlador é independente |
| Propriedade da mensagem | Mensagens permanecem no controlador de origem até serem entregues |
| Segurança | HTTPS com TLS |
| Portas | Uma única porta HTTPS (8443) |
| Meta de escala | 5-20 controladores |
| Tratamento de partições | Retentativas do Poller — sem split-brain |
Arquitetura
Decisões de Design Principais
- Fluxo de mensagens (modelo de pull): Mensagens permanecem no controlador de origem. O controlador de destino as puxa via polling periódico e notificação sob demanda. Frontends apenas se comunicam com seu controlador de origem.
- Tratamento de partições: Retentativas do Poller automaticamente. Mensagens permanecem seguras no controlador de origem até serem entregues com sucesso.
- Sincronização de configuração: Nenhuma. Cada controlador gerencia sua própria tabela de roteamento de forma independente.
- Malha de pares: Malha completa. Todos os controladores trocam informações de saúde e registros de frontends com todos os outros controladores.
- Descoberta: Registros DNS SRV (recomendado) ou lista de pares estática (para ambientes sem DNS dinâmico).
Fluxo de Mensagens (Modelo de Pull)
Quando uma mensagem chega a um controlador e o roteamento determina que o frontend de destino está em um controlador remoto:
- A mensagem permanece na Mnesia do controlador de origem como
:pending - Uma notificação leve é enviada ao controlador de destino (fire-and-forget)
- O FederationPoller do controlador de destino busca a mensagem via GET /api/federation_messages
- A mensagem é armazenada em cache localmente e disponibilizada para os frontends locais
- Após a entrega, o destino reporta o status de volta ao origem
Par Inacessível — Falha na Notificação
Se o controlador de destino estiver fora do ar quando a notificação for enviada, a notificação falha silenciosamente. A mensagem permanece :pending no origem. Quando o controlador de destino se recupera, seu FederationPoller retoma o polling periódico e descobre a mensagem durante o próximo ciclo (padrão: a cada 5 segundos). Nenhuma mensagem é perdida.
Recuperação de Partição — Múltiplas Mensagens em Fila
Durante uma partição prolongada, mensagens se acumulam no controlador de origem. Quando o link se recupera, o FederationPoller se atualiza automaticamente — todas as mensagens pendentes são retornadas em uma única consulta.
Fluxo de Mensagens em Três Sites
Em uma malha multi-site, cada controlador apenas consulta mensagens destinadas aos seus próprios frontends.
Saúde do Par e Sincronização de Registro
Os controladores de federação mantêm a consciência uns dos outros através de dois ciclos periódicos:
Ciclo de Verificação de Saúde
A cada 10 segundos (configurável), cada controlador chama POST /api/federation/health em cada par conhecido. A chamada é bidirecional — o chamador envia seu próprio status e recebe o status do par na resposta. Um par é marcado como não saudável após 3 falhas consecutivas.
Ciclo de Sincronização de Registro
A cada 15 segundos (configurável), cada controlador chama POST /api/federation/registry em cada par saudável. A chamada troca listas de frontends — o chamador envia seus frontends ativos e recebe os frontends ativos do par. É assim que os controladores aprendem qual par possui qual frontend.
Status dos pares e seu efeito no polling de federação:
| Status | Verificações de Saúde | FederationPoller | Sincronização de Registro |
|---|---|---|---|
| Desconhecido | Em progresso | Não consultado | Não tentado |
| Saudável | Aprovado | Polling ativo | Ativo |
| Degradado | 1-2 falhas | Não consultado | Não tentado |
| Não saudável | 3+ falhas | Não consultado | Não tentado |
Configuração
A federação é configurada em config/runtime.exs sob a chave :federation. Está desativada por padrão e deve ser explicitamente ativada.
Configuração Mínima (Descoberta DNS SRV)
# config/runtime.exs
config :sms_c, :federation,
enabled: true,
dns_srv_domain: "_smsc._tcp.smsc.example.com"
Referência Completa de Configuração
# config/runtime.exs
config :sms_c, :federation,
# Interruptor mestre — a federação está completamente inativa quando falso
enabled: true,
# Domínio DNS SRV para descoberta de pares (deixe vazio para usar static_peers em vez disso)
dns_srv_domain: "_smsc._tcp.smsc.example.com",
# Com que frequência re-resolver registros DNS SRV (milissegundos)
dns_poll_interval_ms: 30_000,
# Com que frequência trocar status de saúde com todos os pares conhecidos (milissegundos)
health_check_interval_ms: 10_000,
# Com que frequência trocar registros de frontends com pares saudáveis (milissegundos)
registry_sync_interval_ms: 15_000,
# Com que frequência o FederationPoller consulta pares saudáveis por mensagens (milissegundos)
poll_interval_ms: 5_000,
# Timeout HTTP para todas as chamadas de API peer-to-peer (milissegundos)
http_timeout_ms: 5_000,
# Porta da API usada ao construir URLs de pares a partir de registros DNS SRV
api_port: 8443,
# Lista de pares estáticos — usada quando dns_srv_domain está vazio
static_peers: []
Parâmetros de Federação
| Parâmetro | Tipo | Requerido | Padrão | Descrição |
|---|---|---|---|---|
enabled | Booleano | Sim | false | Interruptor mestre. Quando false, serviços de federação iniciam, mas não descobrem ou contatam pares. |
dns_srv_domain | String | Não | "" | Domínio DNS SRV para descoberta automática de pares. Quando vazio, static_peers é usado em vez disso. |
dns_poll_interval_ms | Inteiro | Não | 30000 | Intervalo entre tentativas de re-resolução de DNS SRV. Valores mais baixos detectam novos pares mais rapidamente, mas aumentam a carga do DNS. |
health_check_interval_ms | Inteiro | Não | 10000 | Intervalo entre rodadas de verificação de saúde. Cada rodada contata cada par conhecido. |
registry_sync_interval_ms | Inteiro | Não | 15000 | Intervalo entre rodadas de sincronização de registro de frontends. Cada rodada contata cada par saudável. |
poll_interval_ms | Inteiro | Não | 5000 | Com que frequência o FederationPoller consulta pares saudáveis por mensagens. Notificações acionam polls imediatos. |
http_timeout_ms | Inteiro | Não | 5000 | Timeout para cada chamada HTTPS individual a um par. Aplica-se a verificações de saúde, sincronização de registro e busca de mensagens. |
api_port | Inteiro | Não | 8443 | Porta da API usada ao construir URLs de pares a partir de registros DNS SRV. Deve corresponder à porta da API configurada em config :api_ex. |
static_peers | Lista | Não | [] | Lista de configurações de pares para ambientes sem DNS SRV. Cada entrada é um mapa com chaves host e port. |
Configuração de Par Estático
Para ambientes onde DNS SRV não está disponível, configure pares explicitamente:
config :sms_c, :federation,
enabled: true,
dns_srv_domain: "",
static_peers: [
%{host: "10.0.1.2", port: 8443},
%{host: "10.0.2.2", port: 8443},
%{host: "10.0.3.2", port: 8443}
]
| Parâmetro | Tipo | Requerido | Padrão | Descrição |
|---|---|---|---|---|
host | String | Sim | - | Endereço IP ou nome do host do controlador remoto. |
port | Inteiro | Não | 8443 | Porta da API HTTPS do controlador remoto. |
Configuração de Registro DNS SRV
Registros DNS SRV permitem que controladores se descubram automaticamente. Cada controlador resolve o domínio configurado e usa os pares de host/porta resultantes como pares.
Configuração da Zona DNS:
; Prioridade Peso Porta Destino
_smsc._tcp.smsc.example.com. 86400 IN SRV 10 100 8443 smsc-alice.smsc.example.com.
_smsc._tcp.smsc.example.com. 86400 IN SRV 10 100 8443 smsc-bob.smsc.example.com.
_smsc._tcp.smsc.example.com. 86400 IN SRV 10 100 8443 smsc-carol.smsc.example.com.
; Registros A para os destinos
smsc-alice.smsc.example.com. 86400 IN A 10.0.1.2
smsc-bob.smsc.example.com. 86400 IN A 10.0.2.2
smsc-carol.smsc.example.com. 86400 IN A 10.0.3.2
Adicionando um novo site: Adicione um novo registro SRV ao DNS. Todos os controladores existentes descobrirão o novo par dentro de um ciclo de dns_poll_interval_ms (padrão 30 segundos).
Removendo um site: Remova o registro SRV do DNS. Controladores existentes removerão o par que partiu dentro de um ciclo de polling.
Requisitos de Rede
A federação requer apenas uma única porta HTTPS entre os sites.
| Porta | Protocolo | Direção | Propósito |
|---|---|---|---|
| 8443 | TCP/TLS | Bidirecional | Todo o tráfego de federação (saúde, registro, notificação, mensagens, status de entrega) |
| 53 | UDP/TCP | Saída | Resolução DNS SRV (se usando descoberta DNS) |
Regras de firewall (por site):
# Permitir tráfego de federação de IPs de controladores pares
iptables -A INPUT -p tcp -s 10.0.1.0/24 --dport 8443 -j ACCEPT
iptables -A INPUT -p tcp -s 10.0.2.0/24 --dport 8443 -j ACCEPT
iptables -A INPUT -p tcp -s 10.0.3.0/24 --dport 8443 -j ACCEPT
Endpoints da API de Federação
Todos os endpoints de federação são servidos na porta padrão da API (8443) sob /api/federation/. Esses endpoints são chamados por controladores pares, não por clientes externos ou frontends.
| Endpoint | Método | Propósito |
|---|---|---|
/api/federation/identity | GET | Retorna o nome do nó deste controlador e a versão do protocolo |
/api/federation/health | POST | Troca de saúde bidirecional — chamador envia status, chamado responde com o seu próprio |
/api/federation/registry | POST | Troca de registro de frontend bidirecional |
/api/federation/notify | POST | Receber notificação leve de que uma mensagem está disponível para um frontend local |
/api/federation/delivery_status | POST | Receber confirmação de entrega do controlador de destino |
/api/federation_messages | GET | Retornar mensagens pendentes para frontends especificados (usado pelo FederationPoller) |
Todas as requisições e respostas usam JSON. A identificação do par é transportada no cabeçalho X-Federation-Node.
Exemplos de Implantação
Exemplo 1: Implantação em Três Sites com DNS SRV
Três centros de dados, cada um com frontends locais para sua base de assinantes. DNS SRV fornece descoberta.
# Site A — DC Alice (config/runtime.exs)
config :sms_c,
smsc_node_name: "alice-dc01-smsc01"
config :sms_c, :federation,
enabled: true,
dns_srv_domain: "_smsc._tcp.smsc.example.com"
# Site B — DC Bob (config/runtime.exs)
config :sms_c,
smsc_node_name: "bob-dc01-smsc01"
config :sms_c, :federation,
enabled: true,
dns_srv_domain: "_smsc._tcp.smsc.example.com"
# Site C — DC Carol (config/runtime.exs)
config :sms_c,
smsc_node_name: "carol-dc01-smsc01"
config :sms_c, :federation,
enabled: true,
dns_srv_domain: "_smsc._tcp.smsc.example.com"
Como funciona: Todos os três controladores resolvem o mesmo domínio SRV e se descobrem automaticamente. Cada controlador registra seus frontends locais. Quando uma mensagem chega ao DC Alice destinada a um assinante atendido pelo DC Bob, a tabela de roteamento seleciona bob-dc01-smsc01 como destino. A camada de federação detecta que este frontend pertence ao Controlador B e envia uma notificação. O FederationPoller do Controlador B consulta o Controlador A e armazena a mensagem em cache para entrega local.
Exemplo 2: Duas Sites Ativo-Ativo com Pares Estáticos
Dois centros de dados conectados por um link dedicado. Sem DNS SRV disponível.
# DC Primário (config/runtime.exs)
config :sms_c,
smsc_node_name: "primary-smsc01"
config :sms_c, :federation,
enabled: true,
dns_srv_domain: "",
static_peers: [
%{host: "10.200.1.5", port: 8443}
]
# DC Secundário (config/runtime.exs)
config :sms_c,
smsc_node_name: "secondary-smsc01"
config :sms_c, :federation,
enabled: true,
dns_srv_domain: "",
static_peers: [
%{host: "10.100.1.5", port: 8443}
]
Como funciona: Cada controlador é configurado com o endereço IP do outro. As verificações de saúde e sincronizações de registro ocorrem através do link dedicado. As mensagens permanecem no controlador que as recebeu. O FederationPoller de cada controlador consulta o par por mensagens destinadas aos frontends locais.
Exemplo 3: Polling Agressivo para Links de Baixa Latência
Para sites conectados por links confiáveis e de baixa latência onde uma federação rápida é importante:
config :sms_c, :federation,
enabled: true,
dns_srv_domain: "_smsc._tcp.cluster.internal",
health_check_interval_ms: 5_000,
registry_sync_interval_ms: 5_000,
poll_interval_ms: 1_000,
http_timeout_ms: 2_000
Caso de uso: Implantações em campus ou áreas metropolitanas onde os sites estão conectados por links de < 10 ms RTT e uma rápida recuperação é mais importante do que minimizar o tráfego de controle.
Métricas
A federação expõe os seguintes eventos de telemetria que podem ser observados via Prometheus na porta 9568.
Métrica: sms_c_federation_message_received_count
Tipo: Contador
Descrição: Número de notificações de federação recebidas de pares
Rótulos:
origin_node- Par que enviou a notificação
Métrica: sms_c_federation_health_check_count
Tipo: Contador
Descrição: Resultados de verificação de saúde por par
Rótulos:
peer- Identificador do parresult-okoufailed
Consultas de exemplo:
# Taxa de notificações por minuto
rate(sms_c_federation_message_received_count[5m]) * 60
# Falhas de verificação de saúde por par
sum by (peer) (rate(sms_c_federation_health_check_count{result="failed"}[5m]))
Indicadores Chave para Monitorar
| O que Observar | Onde | Limite de Alerta |
|---|---|---|
| Mensagens federadas em cache | GET /api/federation/status ou UI Web | Contagem crescente (par não entregando) |
| Status de saúde do par | GET /api/federation/identity em cada par | Qualquer par não saudável > 5 minutos |
| Latência de verificação de saúde | Logs da aplicação | > 2 segundos (degradação do link) |
Resolução de Problemas
Par Não Descoberto
Sintomas: Logs do controlador mostram que nenhum par foi descoberto; cluster_status retorna vazio.
Possíveis causas:
- Domínio DNS SRV está incorreto ou não resolvível
- Servidor DNS está inacessível a partir do host do controlador
- Registros SRV ainda não se propagaram
- Federação não está ativada (
enabled: false)
Resolução:
- Verifique a resolução DNS SRV a partir do host do controlador:
dig SRV _smsc._tcp.smsc.example.com - Verifique se
enabled: trueestá definido na configuração de federação - Verifique logs da aplicação para mensagens de "Descoberta DNS de Federação" na inicialização
- Se estiver usando pares estáticos, verifique se a lista
static_peerscontém entradas corretas de host/porta
Par Marcado como Não Saudável
Sintomas: Mensagens para um site específico não estão sendo consultadas. Logs mostram mensagens "Verificação de saúde falhou".
Possíveis causas:
- Controlador remoto está fora do ar
- Firewall bloqueando a porta 8443 entre os sites
- Problemas com certificados TLS
- Partição de rede entre os sites
Resolução:
- Verifique se o controlador remoto está em execução:
curl -k https://<peer-host>:8443/api/federation/identity - Verifique se as regras de firewall permitem tráfego na porta 8443 do IP do controlador local
- Revise logs da aplicação em ambos os lados para erros de TLS ou conexão
- Verifique a conectividade de rede entre os sites
Mensagens Não Estão Sendo Entregues ao Site Remoto
Sintomas: Mensagens permanecem :pending no controlador de origem. Contagem de mensagens federadas em cache é 0 no destino.
Possíveis causas:
- Controlador de destino está não saudável (FederationPoller apenas consulta pares saudáveis)
- FederationPoller não está em execução
- Registro de frontends não sincronizado (destino não sabe quais frontends são locais)
Resolução:
- Verifique o status do par no controlador de destino
- Verifique se o FederationPoller está na árvore de supervisão (verifique logs da aplicação para "Federation poller started")
- Verifique se os registros de frontends estão sincronizados (
GET /api/federation/status— verifique listas de frontends) - Teste manualmente o endpoint federation_messages:
curl -k 'https://<origin>:8443/api/federation_messages?frontends=<frontend_name>&include_unrouted=false'