目录与心跳任务的 Map 节流

11 阅读1分钟

目录与心跳任务的 Map 节流

试用安装包下载 | SMS | 在线演示

项目地址:github.com/openskeye/g…

背景

国标设备上线后需要 周期性 Catalog,同时要对 注册/心跳超时 做检测。若「每个设备单独起 time.Ticker」,上万路设备会产生 数万 goroutine + 数万定时器,调度与内存开销不可接受。本仓库用 共享 Map + 全局1 秒刻度 统一驱动。

项目中的做法

1. Catalog:SipCatalogLoop + SipCatalogLoopMap

-设备状态变更时向 SipCatalogLoop channel 投递 SipCatalogLoopReq(上线 Online=true 写入 Map,下线移除)。

  • CatalogLoopLogic.proc 中 每秒遍历 SipCatalogLoopMap.Values()。
  • 通过 item.Now % val.Unix() != Config.Sip.CatalogInterval 过滤,只在 与配置间隔对齐的秒 向 SipSendCatalog 投递真正发送任务。

效果:一个定时器服务所有设备,Catalog 发送节奏由配置 CatalogInterval 与当前 Unix 秒对齐控制。

flowchart TB
  Reg["REGISTER/状态变更"]
  Ch["SipCatalogLoop"]
  Map["SipCatalogLoopMap\nkey =设备/请求 ID"]
  Tick["Ticker 1s"]
  Send["SipSendCatalog"]
  Reg --> Ch --> Map
  Tick --> Scan["遍历 Map"]
  Map --> Scan
  Scan -->|"满足 CatalogInterval 对齐"| Send

2. 心跳:SipHeartbeatLoop + SipHeartbeatLoopMap

  • 注册/心跳报文侧把任务写入 SipHeartbeatLoopMap。
  • HeartbeatOfflineLogic.proc 每秒扫描条目:若 注册过期超过 10s 或 距上次心跳超过 HeartbeatTimeout,从 Map 删除并投递 SetDeviceOnline 下线。
stateDiagram-v2
  [*] --> InMap: 注册/心跳更新
  InMap --> InMap: 每秒检查
  InMap --> Offline: 超时  Offline --> [*] SetDeviceOnline false

要点

  1. 时间对齐:Catalog 使用取模对齐,设备多时会在同一秒「齐发」一批 Catalog,可能对 SIP 栈与设备侧造成尖峰;若现场出现设备侧处理不过来,可在 Map 扫描内加 随机抖动 或 分批 sleep(需改代码)。
  2. Map 与 channel 分工:channel 只做 增删事件,周期逻辑只在 单协程 里读 Map,避免多写者竞态(xmap 并发安全)。
  3. 可观测性:SSE sev_state 会输出 SipCatalogLoopMap.Len()、SipHeartbeatLoopMap.Len(),用于判断泄漏或规模。

相关代码路径

  • core/app/sev/vss/internal/logic/gbs_proc/catalog_loop.go
  • core/app/sev/vss/internal/logic/gbs_proc/heartbeat_offline_loop.go
  • core/app/sev/vss/internal/types/types.go