Pular para o conteúdo principal

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

AspectoDetalhe
RedeFunciona sobre qualquer WAN, incluindo links não confiáveis
Estado compartilhadoNenhum — cada controlador é independente
Propriedade da mensagemMensagens permanecem no controlador de origem até serem entregues
SegurançaHTTPS com TLS
PortasUma única porta HTTPS (8443)
Meta de escala5-20 controladores
Tratamento de partiçõesRetentativas 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:

  1. A mensagem permanece na Mnesia do controlador de origem como :pending
  2. Uma notificação leve é enviada ao controlador de destino (fire-and-forget)
  3. O FederationPoller do controlador de destino busca a mensagem via GET /api/federation_messages
  4. A mensagem é armazenada em cache localmente e disponibilizada para os frontends locais
  5. 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:

StatusVerificações de SaúdeFederationPollerSincronização de Registro
DesconhecidoEm progressoNão consultadoNão tentado
SaudávelAprovadoPolling ativoAtivo
Degradado1-2 falhasNão consultadoNão tentado
Não saudável3+ falhasNão consultadoNã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âmetroTipoRequeridoPadrãoDescrição
enabledBooleanoSimfalseInterruptor mestre. Quando false, serviços de federação iniciam, mas não descobrem ou contatam pares.
dns_srv_domainStringNão""Domínio DNS SRV para descoberta automática de pares. Quando vazio, static_peers é usado em vez disso.
dns_poll_interval_msInteiroNão30000Intervalo 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_msInteiroNão10000Intervalo entre rodadas de verificação de saúde. Cada rodada contata cada par conhecido.
registry_sync_interval_msInteiroNão15000Intervalo entre rodadas de sincronização de registro de frontends. Cada rodada contata cada par saudável.
poll_interval_msInteiroNão5000Com que frequência o FederationPoller consulta pares saudáveis por mensagens. Notificações acionam polls imediatos.
http_timeout_msInteiroNão5000Timeout 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_portInteiroNão8443Porta 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_peersListaNã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âmetroTipoRequeridoPadrãoDescrição
hostStringSim-Endereço IP ou nome do host do controlador remoto.
portInteiroNão8443Porta 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.

PortaProtocoloDireçãoPropósito
8443TCP/TLSBidirecionalTodo o tráfego de federação (saúde, registro, notificação, mensagens, status de entrega)
53UDP/TCPSaídaResoluçã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.

EndpointMétodoPropósito
/api/federation/identityGETRetorna o nome do nó deste controlador e a versão do protocolo
/api/federation/healthPOSTTroca de saúde bidirecional — chamador envia status, chamado responde com o seu próprio
/api/federation/registryPOSTTroca de registro de frontend bidirecional
/api/federation/notifyPOSTReceber notificação leve de que uma mensagem está disponível para um frontend local
/api/federation/delivery_statusPOSTReceber confirmação de entrega do controlador de destino
/api/federation_messagesGETRetornar 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.

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 par
  • result - ok ou failed

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 ObservarOndeLimite de Alerta
Mensagens federadas em cacheGET /api/federation/status ou UI WebContagem crescente (par não entregando)
Status de saúde do parGET /api/federation/identity em cada parQualquer par não saudável > 5 minutos
Latência de verificação de saúdeLogs 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:

  1. Verifique a resolução DNS SRV a partir do host do controlador: dig SRV _smsc._tcp.smsc.example.com
  2. Verifique se enabled: true está definido na configuração de federação
  3. Verifique logs da aplicação para mensagens de "Descoberta DNS de Federação" na inicialização
  4. Se estiver usando pares estáticos, verifique se a lista static_peers conté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:

  1. Verifique se o controlador remoto está em execução: curl -k https://<peer-host>:8443/api/federation/identity
  2. Verifique se as regras de firewall permitem tráfego na porta 8443 do IP do controlador local
  3. Revise logs da aplicação em ambos os lados para erros de TLS ou conexão
  4. 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:

  1. Verifique o status do par no controlador de destino
  2. Verifique se o FederationPoller está na árvore de supervisão (verifique logs da aplicação para "Federation poller started")
  3. Verifique se os registros de frontends estão sincronizados (GET /api/federation/status — verifique listas de frontends)
  4. Teste manualmente o endpoint federation_messages: curl -k 'https://<origin>:8443/api/federation_messages?frontends=<frontend_name>&include_unrouted=false'