跳到主要内容

地理联邦

← 返回文档索引 | 配置参考 | 操作指南

概述

OmniMessage 使用 基于 HTTP 的联邦 来支持跨数据中心或区域的多控制器部署。每个控制器独立运行——管理自己的消息队列、路由表和连接的前端。控制器通过 DNS SRV 记录(或静态配置)发现彼此,通过 HTTPS 交换健康和前端注册信息,并在路由确定消息属于远程站点时,将消息转发到其前端服务目标的控制器。

当站点间链接中断时,消息会在本地排队,并在链接恢复时自动转发到远程控制器。没有消息丢失,并且在分区期间不会重新路由到本地前端。

关键特性

方面细节
网络在任何 WAN 上工作,包括不可靠的链接
共享状态无 — 每个控制器都是独立的
安全性使用 TLS 的 HTTPS
端口单一 HTTPS 端口(8443)
规模目标5-20 个控制器
分区处理排队等待(无��裂脑)

架构

关键设计决策

  • 消息流:源控制器通过 HTTPS 将消息推送到目标控制器。前端仅与其主控制器通信。
  • 分区处理:排队等待。当远���控制器不可达时,不会重新路由到本地前端。
  • 配置同步:无。每个控制器独立管理自己的路由表。
  • 对等网:全网格。所有控制器与所有其他控制器交换健康和前端注册信息。
  • 发现:DNS SRV 记录(推荐)或静态对等列表(用于没有动态 DNS 的环境)。

消息转发流程

当消息到达控制器并且路由确定目标前端位于远程控制器上时,消息通过 HTTPS 转发到远程控制器以进行本地交付。

对等健康和注册同步

联邦控制器通过两个周期性循环保持对彼此的意识:

健康检查周期

每 10 秒(可配置),每个控制器在每个已知对等体上调用 POST /api/federation/health。该调用是双向的——调用者发送自己的状态并在响应中接收对等体的状态。对等体在连续 3 次失败后被标记为 不健康

注册同步周期

每 15 秒(可配置),每个控制器在每个健康的对等体上调用 POST /api/federation/registry。该调用交换前端列表——调用者发送其活动前端并接收对等体的活动前端。这是控制器了解哪个对等体拥有哪个前端的方式。

对等体状态及其对消息转发的影响:

状态健康检查消息转发注册同步
未知进行中排队未尝试
健康通过立即转发活跃
降级1-2 次失败排队未尝试
不健康3 次以上失败排队未尝试

消息状态

联邦引入了三种额外的消息状态,这些状态在消息队列中可见:

状态意义
:forwarded消息已成功发送到目标控制器
:forward_queued消息在转发队列中等待,因为目标控制器不可达
:forward_failed消息超过最大重试次数,将不再重试

这些状态与标准状态(:pending:delivered:failed:retry)一起出现在消息队列 Web UI 和 API 响应中。

配置

联邦在 config/runtime.exs 中的 :federation 键下进行配置。默认情况下是 禁用 的,必须显式启用。

最小配置(DNS SRV 发现)

# config/runtime.exs
config :sms_c, :federation,
enabled: true,
dns_srv_domain: "_smsc._tcp.smsc.example.com"

完整配置参考

# config/runtime.exs
config :sms_c, :federation,
# 主开关 — 当为 false 时,联邦完全不活动
enabled: true,

# 用于对等发现的 DNS SRV 域(留空以使用 static_peers)
dns_srv_domain: "_smsc._tcp.smsc.example.com",

# 重新解析 DNS SRV 记录的频率(毫秒)
dns_poll_interval_ms: 30_000,

# 与所有已知对等体交换健康状态的频率(毫秒)
health_check_interval_ms: 10_000,

# 与健康对等体交换前端注册的频率(毫秒)
registry_sync_interval_ms: 15_000,

# 转发工作者重试排队消息的频率(毫秒)
forward_retry_interval_ms: 5_000,

# 在将排队消息标记为 :forward_failed 之前的最大重试次数
forward_max_retries: 50,

# 所有对等 API 调用的 HTTP 超时(毫秒)
http_timeout_ms: 5_000,

# 从 DNS SRV 记录构建对等 URL 时使用的 API 端口
api_port: 8443,

# 静态对等列表 — 当 dns_srv_domain 为空时使用
static_peers: []

联邦参数

参数类型必需默认描述
enabled布尔false主开关。当为 false 时,联邦服务启动但不发现或联系对等体。
dns_srv_domain字符串""用于自动对等发现的 DNS SRV 域。当为空时,使用 static_peers
dns_poll_interval_ms整数30000DNS SRV 重新解析尝试之间的间隔。较低的值可以更快地检测到新对等体,但会增加 DNS 负载。
health_check_interval_ms整数10000健康检查轮次之间的间隔。每轮联系每个已知对等体。
registry_sync_interval_ms整数15000前端注册同步轮次之间的间隔。每轮联系每个健康对等体。
forward_retry_interval_ms整数5000转发工作者检查健康对等体并重试排队消息的频率。
forward_max_retries整数50每条消息的最大转发尝试次数,超过此次数将标记为 :forward_failed。在默认重试间隔下,50 次重试 = ~4 分钟的排队。
http_timeout_ms整数5000对每个对等体的单独 HTTPS 调用的超时。适用于健康检查、注册同步和消息转发。
api_port整数8443从 DNS SRV 记录构建对等 URL 时使用的 API 端口。必须与 config :api_ex 中配置的 API 端口匹配。
static_peers列表[]用于没有 DNS SRV 的环境的对等体配置列表。每个条目是一个包含 hostport 键的映射。

静态对等配置

对于没有 DNS SRV 的环境,显式配置对等体:

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}
]
参数类型必需默认描述
host字符串-远程控制器的 IP 地址或主机名。
port整数8443远程控制器的 HTTPS API 端口。

DNS SRV 记录设置

DNS SRV 记录允许控制器自动发现彼此。每个控制器解析配置的域,并使用结果的主机/端口对作为对等体。

DNS 区域配置:

; 优先级 权重 端口 目标
_smsc._tcp.smsc.example.com. 86400 IN SRV 10 100 8443 smsc-alpha.smsc.example.com.
_smsc._tcp.smsc.example.com. 86400 IN SRV 10 100 8443 smsc-bravo.smsc.example.com.
_smsc._tcp.smsc.example.com. 86400 IN SRV 10 100 8443 smsc-charlie.smsc.example.com.

; 目标的 A 记录
smsc-alpha.smsc.example.com. 86400 IN A 10.0.1.2
smsc-bravo.smsc.example.com. 86400 IN A 10.0.2.2
smsc-charlie.smsc.example.com. 86400 IN A 10.0.3.2

添加新站点:向 DNS 添加新的 SRV 记录。所有现有控制器将在一个 dns_poll_interval_ms 周期内发现新的对等体(默认 30 秒)。

移除站点:从 DNS 中移除 SRV 记录。现有控制器将在一个轮询周期内移除已离开的对等体。任何排队给已移除对等体的消息将继续重试,直到达到 forward_max_retries,然后标记为 :forward_failed

网络要求

联邦只需要在站点之间的单一 HTTPS 端口。

端口协议方向目的
8443TCP/TLS双向所有联邦流量(健康、注册、转发、交付状态)
53UDP/TCP出站DNS SRV 解析(如果使用 DNS 发现)

防火墙规则(每个站点):

# 允许来自对等控制器 IP 的联邦流量
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

联邦 API 端点

所有联邦端点都在标准 API 端口(8443)下的 /api/federation/ 提供。这些端点由对等控制器调用,而不是由外部客户端或前端调用。

端点方法目的
/api/federation/identityGET返回此控制器的节点名称和协议版本
/api/federation/healthPOST双向健康交换 — 调用者发送状态,被���用者响应自己的状态
/api/federation/registryPOST双向前端注册交换
/api/federation/forwardPOST接收转发的消息以进行本地交付
/api/federation/delivery_statusPOST接收来自目标控制器的交付确认

所有请求和响应均使用 JSON。对等体标识通过 X-Federation-Node 头部传递。

部署示例

示例 1:使用 DNS SRV 的三站点部署

三个数据中心,每个数据中心都有本地前端以服务其订阅者基础。DNS SRV 提供发现。

# 站点 A — 数据中心 Alpha (config/runtime.exs)
config :sms_c,
smsc_node_name: "alpha-dc01-smsc01"

config :sms_c, :federation,
enabled: true,
dns_srv_domain: "_smsc._tcp.smsc.example.com"
# 站点 B — 数据中心 Bravo (config/runtime.exs)
config :sms_c,
smsc_node_name: "bravo-dc01-smsc01"

config :sms_c, :federation,
enabled: true,
dns_srv_domain: "_smsc._tcp.smsc.example.com"
# 站点 C — 数据中心 Charlie (config/runtime.exs)
config :sms_c,
smsc_node_name: "charlie-dc01-smsc01"

config :sms_c, :federation,
enabled: true,
dns_srv_domain: "_smsc._tcp.smsc.example.com"

工作原理:所有三个控制器解析相同的 SRV 域并自动发现彼此。每个控制器注��其本地前端。当到达数据中心 Alpha 的消息目标是由数据中心 Bravo 服务的订阅者时,路由表选择 bravo-dc01-smsc01 作为目标。联邦层检测到该前端属于控制器 B,并通过 HTTPS 转发消息。

示例 2:使用静态对等体的双站点主动-主动

两个通过专用链接连接的数据中心。没有 DNS SRV 可用。

# 主数据中心 (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}
]
# 次要数据中心 (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}
]

工作原理:每个控制器都配置了对方的 IP 地址。健康检查和注册同步通过专用链接进行。如果链接失败,消息会在本地排队,并在恢复时排出。

示例 3:低延迟链接的激进重试

对于通过可靠、低延迟链接连接的站点,其中快速转发恢复很重要:

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,
forward_retry_interval_ms: 1_000,
http_timeout_ms: 2_000

用例:校园或城市区域部署,其中站点通过 < 10 毫秒 RTT 链接连接,快速故障转移比最小化控制流量更重要。

指标

联邦公开了以下可以通过 Prometheus 在 9568 端口观察的遥测事件。

指标: sms_c_federation_forward_completed_count 类型: 计数器 描述: 成功转发到远程控制器的消息数量(包括来自转发队列的重试) 标签:

  • dest_controller - 目标控制器标识符(主机:端口)

示例查询

# 每分钟转发速率
rate(sms_c_federation_forward_completed_count[5m]) * 60

# 按目标控制器的转发数量
sum by (dest_controller) (rate(sms_c_federation_forward_completed_count[5m]))

此外,标准消息指标(:forwarded:forward_queued:forward_failed 状态)出现在现有队列统计端点和 Web UI 中。

关键指标监控

监控内容位置警报阈值
转发队列深度GET /api/status 或 Web UI> 100 待处理(调查链接)
对等健康状态在每个对等体上 GET /api/federation/identity任何对等体不健康 > 5 分钟
转发失败率Prometheus :forward_failed 状态计数任何非零(消息被丢弃)
健康检查延迟应用日志> 2 秒(链接降级)

故障排除

对等体未发现

症状:控制器日志显示没有发现对等体;cluster_status 返回为空。

可能原因

  • DNS SRV 域不正确或无法解析
  • 控制器主机无法访问 DNS 服务器
  • SRV 记录尚未传播
  • 联邦未启用(enabled: false

解决方案

  1. 验证控制器主机的 DNS SRV 解析:dig SRV _smsc._tcp.smsc.example.com
  2. 检查联邦配置中是否设置了 enabled: true
  3. 检查应用日志中是否有“联邦 DNS 发现”消息
  4. 如果使用静态对等体,验证 static_peers 列表是否包含正确的主机/端口条目

对等体标记为不健康

症状:发送到特定站点的消息被排队而不是转发。日志显示“健康检查失败”消息。

可能原因

  • 远程控制器已关闭
  • 防火墙阻止站点之间的 8443 端口
  • TLS 证书问题
  • 站点之间的网络分区

解决方案

  1. 验证远程控制器是否正在运行:curl -k https://<peer-host>:8443/api/federation/identity
  2. 检查防火墙规则是否允许来自本地控制器 IP 的 8443 端口流量
  3. 检查双方的应用日志以获取 TLS 或连接错误
  4. 检查站点��间的网络连接

消息卡在转发队列中

症状forward_queued 消息计数在增加;消息未能送达远程站点。

可能原因

  • 目标控制器不健康(转发工作者仅重试健康对等体)
  • 转发工作者未运行
  • 目标控制器的 API 在 /api/federation/forward 上返回错误

解决方案

  1. 检查对等体状态——转发工作者仅重试健康对等体
  2. 验证转发工作者是否在监督树中(检查应用日志中的“ForwardWorker”)
  3. 手动测试转发端点:curl -k -X POST https://<peer>:8443/api/federation/forward -H 'Content-Type: application/json' -d '{"source_msisdn":"test","destination_msisdn":"test","message_body":"test","source_smsc":"test","dest_smsc":"test"}'
  4. 检查 forward_max_retries——超过此计数的消息将标记为 :forward_failed,并且不会重试

消息标记为 forward_failed

症状:队列中有状态为 :forward_failed 的消息。

可能原因

  • 目标控制器在 forward_max_retries * forward_retry_interval_ms 期间不可达
  • 在默认设置下(50 次重试,5 秒间隔),这意味着对等体在大约 4 分钟内不可达

解决方案

  1. 调查为什么对等体在重试窗口内不可达
  2. 如果对等体已恢复,这些消息必须���动重新提交——它们不会自动重试
  3. 考虑增加 forward_max_retries,以适应预期的较长停机窗口
  4. 对于非常不可靠的链接,考虑使用 forward_max_retries: 1000(在 5 秒间隔下大约 83 分钟的排队)