Hotdry.
systems-engineering

设计 Uptime Kuma 分布式监控架构:多区域健康检查与故障转移

针对 Uptime Kuma 原生不支持分布式部署的限制,设计基于外部工具的多区域监控架构,实现高可用性健康检查与自动故障转移。

在当今分布式系统时代,监控工具本身的高可用性变得至关重要。Uptime Kuma 作为一款优秀的自托管监控工具,以其丰富的功能集和优雅的用户界面赢得了广泛认可。然而,当我们需要构建跨地域的高可用监控系统时,却发现 Uptime Kuma 原生并不支持分布式架构。本文将深入分析这一限制,并设计一套完整的分布式监控架构方案。

Uptime Kuma 的现状与分布式需求

Uptime Kuma 是一个功能全面的自托管监控工具,支持 HTTP (s)、TCP、Ping、DNS 记录、Websocket 等十多种监控类型,并提供 90+ 通知服务集成。其默认配置使用 SQLite 数据库,以 20 秒间隔执行健康检查,这些特性使其成为中小型项目的理想选择。

然而,当我们面临以下场景时,单点部署的局限性就显现出来:

  1. 跨地域监控需求:需要在不同地理区域部署监控节点,避免因区域网络问题导致的误报
  2. 高可用性要求:监控系统本身不能成为单点故障
  3. 负载均衡:大量监控目标需要分布式处理
  4. 数据冗余:监控历史数据需要多地备份

根据 GitHub issue #1259 的记录,Uptime Kuma 的分布式模式功能请求已被标记为 "not planned"(不计划实现)。这意味着我们需要通过外部工具和架构设计来解决这一问题。

原生架构的限制分析

数据库层面的挑战

Uptime Kuma 默认使用 SQLite 作为数据存储,这是一个轻量级的文件数据库,虽然性能优秀,但在分布式场景下面临以下挑战:

  1. 并发写入限制:SQLite 在写入时需要文件锁,多实例同时写入会导致冲突
  2. 数据同步困难:文件数据库难以实现实时数据同步
  3. 一致性保证:分布式环境下难以保证数据强一致性

监控逻辑的分布式协调

即使解决了数据存储问题,监控逻辑的分布式协调仍然复杂:

  1. 任务分配:如何将监控任务合理分配到不同节点
  2. 结果聚合:如何汇总各节点的监控结果
  3. 状态同步:如何保持各节点状态一致
  4. 故障检测:如何检测监控节点自身的故障

分布式架构设计方案

基于以上分析,我们设计了一套基于外部工具的分布式架构方案。该方案的核心思想是:保持 Uptime Kuma 实例的独立性,通过外部系统实现数据同步和负载均衡

架构概览

┌─────────────────────────────────────────────────────────────┐
│                   负载均衡层 (Nginx/Traefik)                  │
│                   或 DNS 轮询/故障转移                        │
└─────────────────┬───────────────────┬───────────────────────┘
                  │                   │
    ┌─────────────▼───────┐ ┌─────────▼─────────────┐
    │  区域 A: Uptime Kuma │ │  区域 B: Uptime Kuma  │
    │  实例 + SQLite       │ │  实例 + SQLite        │
    └─────────────┬───────┘ └─────────┬─────────────┘
                  │                   │
    ┌─────────────▼───────────────────▼─────────────┐
    │            数据同步层 (选择一种方案)            │
    │ 1. LiteStream (SQLite 复制)                   │
    │ 2. NATS KV 存储                               │
    │ 3. 定期备份/恢复                               │
    └───────────────────────────────────────────────┘

方案一:基于 LiteStream 的 SQLite 复制

LiteStream 是 Fly.io 提供的 SQLite 复制工具,可以实现多主复制。虽然 Uptime Kuma 官方不支持分布式模式,但我们可以通过容器化部署和 LiteStream 实现数据同步。

实现步骤:

  1. 容器化部署:将 Uptime Kuma 部署在支持 LiteStream 的平台上
  2. 配置复制:设置 LiteStream 复制策略,确保数据在多个实例间同步
  3. 读写分离:设计合理的读写策略,避免写入冲突

关键参数配置:

# Docker Compose 配置示例
version: '3.8'
services:
  uptime-kuma:
    image: louislam/uptime-kuma:2
    volumes:
      - ./data:/app/data
      - ./litestream.yml:/etc/litestream.yml
    ports:
      - "3001:3001"

litestream.yml 配置:

dbs:
  - path: /app/data/kuma.db
    replicas:
      - url: s3://your-bucket/kuma.db
        retention: 24h

方案二:基于 NATS KV 存储的同步

NATS 是一个高性能的消息系统,其 KV(键值)存储功能可以用于状态同步。我们可以通过以下方式实现:

  1. 状态发布:每个 Uptime Kuma 实例将监控结果发布到 NATS KV
  2. 状态订阅:所有实例订阅 KV 更新,保持状态同步
  3. 冲突解决:设计时间戳或版本号机制解决状态冲突

实现架构:

// 伪代码示例:使用 NATS KV 同步监控状态
func syncMonitorStatus(region string, status MonitorStatus) {
    kv, _ := js.KeyValue("uptime-kuma-status")
    key := fmt.Sprintf("status:%s:%s", region, status.Target)
    kv.Put(key, serialize(status))
}

func watchStatusChanges() {
    kv, _ := js.KeyValue("uptime-kuma-status")
    watcher, _ := kv.Watch("status:*")
    for update := range watcher.Updates() {
        if update != nil {
            status := deserialize(update.Value())
            updateLocalStatus(status)
        }
    }
}

方案三:定期备份与恢复

对于要求不高的场景,可以采用定期备份和恢复的方式:

  1. 定时备份:主实例定期导出备份
  2. 同步传输:将备份文件同步到备用实例
  3. 定时恢复:备用实例定期导入备份

自动化脚本示例:

#!/bin/bash
# 备份脚本
BACKUP_FILE="/tmp/kuma-backup-$(date +%Y%m%d-%H%M%S).tar.gz"
curl -s "http://primary-kuma:3001/api/backup" -o $BACKUP_FILE

# 同步到备用实例
scp $BACKUP_FILE backup-kuma:/tmp/

# 在备用实例上恢复
ssh backup-kuma "curl -X POST -F 'file=@/tmp/$(basename $BACKUP_FILE)' http://localhost:3001/api/restore"

多区域健康检查实现

区域分配策略

为了实现真正的多区域监控,我们需要设计合理的区域分配策略:

  1. 地理就近原则:根据监控目标的地理位置分配监控节点
  2. 负载均衡原则:根据节点负载情况动态分配任务
  3. 故障转移原则:当某个区域节点故障时,自动将任务转移到其他区域

健康检查配置清单

以下是一份多区域健康检查的配置清单:

regions:
  - name: us-east-1
    endpoints:
      - http://us-east-1-kuma:3001
    monitored_targets:
      - https://api-us.example.com
      - https://cdn-us.example.com
    check_interval: 30s
    timeout: 10s
    
  - name: eu-west-1
    endpoints:
      - http://eu-west-1-kuma:3001
    monitored_targets:
      - https://api-eu.example.com
      - https://cdn-eu.example.com
    check_interval: 30s
    timeout: 10s
    
  - name: ap-southeast-1
    endpoints:
      - http://ap-southeast-1-kuma:3001
    monitored_targets:
      - https://api-ap.example.com
      - https://cdn-ap.example.com
    check_interval: 30s
    timeout: 10s

结果聚合与告警

多区域监控的关键在于结果聚合。我们需要设计聚合策略:

  1. 多数表决:当多数区域报告正常时,认为服务正常
  2. 最差情况:任何一个区域报告异常即触发告警
  3. 加权平均:根据不同区域的可靠性赋予不同权重

聚合算法示例:

def aggregate_results(region_results):
    """
    聚合多个区域的监控结果
    """
    status_counts = {
        'up': 0,
        'down': 0,
        'unknown': 0
    }
    
    for region, result in region_results.items():
        status_counts[result.status] += region.weight
    
    # 决策逻辑:如果超过50%的区域报告异常,则触发告警
    total_weight = sum(region.weight for region in region_results.keys())
    if status_counts['down'] / total_weight > 0.5:
        return 'critical'
    elif status_counts['down'] > 0:
        return 'warning'
    else:
        return 'healthy'

故障转移与高可用性

监控节点自监控

监控系统自身的高可用性至关重要。我们需要实现监控节点的自监控:

  1. 心跳检测:各节点定期发送心跳信号
  2. 健康检查:外部服务检查监控节点的可用性
  3. 自动恢复:检测到节点故障时自动重启或转移

故障转移策略

设计合理的故障转移策略需要考虑以下因素:

  1. 故障检测时间:多快能检测到节点故障
  2. 转移延迟:故障转移需要多长时间
  3. 数据一致性:转移过程中如何保证数据不丢失

推荐参数:

  • 故障检测超时:30 秒
  • 转移延迟:< 60 秒
  • 数据同步间隔:5 分钟(对于备份方案)

DNS 故障转移配置

对于面向公网的监控面板,可以使用 DNS 故障转移:

; 主 DNS 记录
uptime.example.com. 300 IN A 192.0.2.1
uptime.example.com. 300 IN A 192.0.2.2

; 健康检查配置
healthcheck:
  protocol: http
  path: /api/health
  port: 3001
  interval: 30s
  timeout: 5s
  failure_threshold: 2

实施建议与最佳实践

分阶段实施策略

建议采用分阶段的方式实施分布式监控架构:

阶段一:基础部署

  • 在两个不同区域部署独立的 Uptime Kuma 实例
  • 配置相同的监控目标
  • 手动同步配置(使用备份 / 恢复功能)

阶段二:自动化同步

  • 实现配置的自动化同步
  • 设置定时备份和恢复任务
  • 添加基本的健康检查

阶段三:完全分布式

  • 实现实时数据同步
  • 部署负载均衡器
  • 配置完整的故障转移机制

监控与告警配置

分布式监控系统需要完善的自我监控:

  1. 节点健康监控:监控每个 Uptime Kuma 实例的健康状态
  2. 同步状态监控:监控数据同步的延迟和成功率
  3. 性能指标监控:监控各节点的资源使用情况

推荐告警阈值:

  • 节点不可用时间:> 2 分钟
  • 数据同步延迟:> 5 分钟
  • CPU 使用率:> 80% 持续 5 分钟
  • 内存使用率:> 90% 持续 5 分钟

安全考虑

分布式部署增加了攻击面,需要特别注意安全:

  1. 网络隔离:各节点间使用 VPN 或私有网络通信
  2. 认证授权:实现节点间的相互认证
  3. 数据加密:传输中的数据需要加密
  4. 访问控制:严格限制管理接口的访问

性能优化建议

数据库优化

虽然 SQLite 性能良好,但在高负载下仍需优化:

  1. WAL 模式:启用 Write-Ahead Logging 提高并发性能
  2. 适当索引:为常用查询字段添加索引
  3. 定期清理:清理历史数据,保持数据库大小合理

网络优化

跨区域部署需要注意网络优化:

  1. 压缩传输:对同步数据进行压缩
  2. 增量同步:只同步变化的数据
  3. 连接复用:保持长连接减少握手开销

总结与展望

Uptime Kuma 虽然原生不支持分布式架构,但通过合理的外部工具和架构设计,我们仍然可以构建高可用的多区域监控系统。本文提出的三种方案各有优劣:

  1. LiteStream 方案:适合已经使用 Fly.io 的场景,提供较好的数据一致性
  2. NATS KV 方案:适合需要实时同步的场景,灵活性高
  3. 备份 / 恢复方案:适合要求不高的场景,实现简单

选择哪种方案取决于具体的业务需求、技术栈和运维能力。无论选择哪种方案,都需要注意监控系统自身的高可用性,避免监控系统成为单点故障。

随着边缘计算和全球化部署的普及,分布式监控的需求会越来越强烈。希望 Uptime Kuma 社区未来能够考虑原生支持分布式架构,或者有更多的第三方工具出现,简化分布式监控的部署和维护。

参考资料

  1. GitHub issue #1259: "Distributed mode" - 官方明确表示不计划支持分布式模式
  2. DEV.to 文章: "DIY multi-regional uptime monitoring with Fly.io and Uptime Kuma" - 社区实现的多区域部署方案
  3. GitHub issue #2955: "Monitoring Agent for multi location status" - 多位置监控代理功能请求
  4. LiteStream 文档 - Fly.io 的 SQLite 复制工具
  5. NATS 文档 - 高性能消息系统,支持 KV 存储

通过本文的设计方案,您可以在现有技术条件下构建一个可靠的多区域监控系统,为您的业务提供全面的可用性保障。

查看归档