路由器上那 54MB 内存,逼我用 Rust 重写了采集器

简介: 本文详解 v0.7.0 版网络采集器为何必须部署于路由器(因仅路由器可获取 DHCP/NAT/WiFi/DNS 四类关键内网信号),并对比 Go 与 Rust 实现:Rust 版内存占用从 54MB 降至 12MB,DB 从 45MB 缩至 2.6MB,扫描提速 1.7 倍,且无 GC 波动。附 OpenWrt/iStoreOS 安装指南及常见排坑。

上一篇写完当天,v0.7.0 的安装包就挂上去了,采集器的 .ipk/.apk 也在里面——那句「还没进 release」是我写稿时还没传,现在有了。这篇接着讲它:采集器为什么非得跑在路由器上,以及怎么装。

先说结论式的那句话:不是路由器方便,是内网里别的机器根本看不见那些信号。

别的机器看不见什么

路由器是网络的汇聚点(choke point)。它同时看着 DHCP 租约、NAT 连接、WiFi 关联和 DNS 查询——这四样,你在任何一台普通主机上都拿不到:

  • dhcp_leases:权威的 hostname ↔ MAC ↔ IP 映射(读 dnsmasq 的/tmp/dhcp.leases)
  • conntrack:「此刻谁在跟谁通信」(读/proc/net/nf_conntrack)
  • hostapd:WiFi 终端的关联信息,带信号强度和连接时长
  • dns_log:被动 DNS 指纹——把探测包全挡掉的设备,照样要做 DNS 解析

最后一条是我觉得最值钱的。一个设备可以拒绝你的 ICMP、关掉 SNMP、过滤 mDNS,只要它还想上网,就得问 DNS。这一条永远在泄漏它的存在。

这四个源在非路由器主机上会干净降级成 no-op(打条日志跳过,不报错),所以你只有两个选择:要么跑在路由器上,要么放弃这四路信号。

我的几个站点各自有路由器,采集器必须落在路由器上,数据回传到中心。问题也就跟着来了——路由器是整个网络里内存最紧张的地方。

54MB 是什么概念

我的采集器节点之一是 NanoPi NEO(ARMv7,512MB 内存)。先说清楚这是块什么板子:能跑 Linux,但可用内存非常有限,而它上面还要跑 dnsmasq、hostapd、防火墙这些。

Go 版采集器在这块板上的实测(2 天 96 轮观察器,2026-10-04 → 10-06,生产流量):

  • 常驻内存区间 38.5 – 62.8 MB,中位数 54.1 MB

  • 本地 agent.db 稳态 40 – 47 MB

  • /24 一轮主动扫描 142 – 165 秒

54MB 常驻在一台路由器上是不可接受的——很多路由器的可用内存就一百来兆,一个采集器吃掉一半。而且那 38.5–62.8MB 的区间是 GC 锯齿,意味着你没法做容量规划,只能靠猜。

闪存那边也不好看:40–47MB 的本地库在 NAND + overlayfs 上持续写,磨损是真实的。

换成 Rust 之后的实测

同一块板、同一网段、同样的生产流量,Rust 采集器(mibee-agent-rs/0.1.5,2026-10-09):

  • 二进制:19,988,640 B → 4,795,716 B(4.2 倍)

  • RSS 中位数:54.1 MB → 11.9 MB(4.5 倍);区间从 38.5–62.8 MB 收到 10.9–12.4 MB

  • 连续运行 2 天 8 小时实时采样:12.6 MiB RSS(systemd 报 11.8 MiB)

  • /24 扫描:142–165 秒 → 84.8–88.6 秒(约 1.7 倍)

  • 本地 agent.db:40–47 MB → 2.58 MB

比数字更重要的是那个区间——10.9 到 12.4 MB,平的。没有 GC 就没有锯齿,这才是小机型容量规划真正要的东西:你知道它占多少。

扫描快出来的那 1.7 倍,主要不是 Rust 本身快,是SNMP 门控:L2/MIB 那几个探针只对「第一段已经证明它讲 SNMP」的主机跑。Go 引擎对每台不支持 SNMP 的主机都要白白等几轮 walk 超时。加上五个 L2 探针之后 /24 仍是 85 秒(加之前 86 秒),这个数据说明门控是真的有效。

代价:三倍代码

这部分我不想省。

  • Go 采集器:5,152 行(借力 gosnmp、yaml.v3、Go crypto)

  • Rust 采集器:15,937 行(自研 BER 编码、SNMPv3 USM + 密钥本地化、AES-256-GCM vault、cron 解析器)

三倍代码是刻意付的代价,换的是两件事:运行期内存没有意外,以及线上格式不再依赖一个分配行为不受我们控制的库。Go 版把线上格式交给库,Rust 版自己拥有它们——也拥有它们的差分测试。

这个差分测试上线当天就回本了。它揪出我们自己 SNMPv3 编码器里的一个潜伏 bug:msgMaxSize 65535 被编成了 FF FF,按 BER 规则那是有符号的 −1。真实 agent 会静默丢弃我们发过的每一个 v3 报文,而自测用的宽容版 echo server 永远不会发现——只有拿真实 net-snmp 对拍才看得见。已修复并加了回归测试。

这就是为什么那次重写的验收门槛设成了「分类器逐字节一致」而不是「功能差不多」。全语料(约 2600 条规则)双种子对拍,加上对真实 net-snmp 的差分(v2c walk 5/5、RFC 4293 回退 5/5、v3 authPriv 5/5,全部逐字节一致)。

装起来

v0.7.0 的采集器有三种形态:tar 包、.ipk、.apk。先确认你的固件用哪个包管理器——OpenWrt 从 24.10 起把 opkg 换成了 apk,iStoreOS 新旧版本两种底子都有:

ssh root@<路由器IP> 'command -v opkg apk; grep DISTRIB_RELEASE /etc/openwrt_release'

然后二选一:

​​​​​​​

# opkg(OpenWrt 22.03/23.05 底,多数 iStoreOS 现行版)
opkg install /tmp/mibee-agent_0.7.0_arm64.ipk

# apk(OpenWrt 24.10+ 底)
apk add --allow-untrusted /tmp/mibee-agent_0.7.0_arm64.apk

包里的 pre 脚本会做架构闸门(uname 不匹配直接拒绝安装)+ -version 冒烟执行,post 脚本生成 /etc/mibee/agent.yaml(LAN 网段从 uci 推导),但center 的 url 和 token 是留空占位、服务不启动——这是有意的,你得先注册好再让它跑。

注册采集器的令牌在中心上创建(POST /api/v1/agents/tokens,需要管理员令牌),然后把这几个键填进 /etc/mibee/agent.yaml:

  • center.url:中心的地址
  • center.auth_token:上一步创建的令牌
  • network.name/network.cidr:这台路由器自己的 LAN(比如lan-62/192.168.2.0/24)
  • scanner.discovery.*:那四个路由器专属源,按需开

填完启动:/etc/init.d/mibee-agent enable && /etc/init.d/mibee-agent start,然后 logread -e mibee-agent 看一眼,应该能看到版本串和启动行。

跑起来之后,中心的采集器页长这样:

图片

每个采集器的版本、在线状态、归属网络、最近上报时间都在这里。其中时钟偏移这一列超过 ±60 秒会高亮——对分布式采集来说这个数比看起来重要:时钟漂了,上报时间戳就不可信,心跳判断跟着失真。

踩过的坑

这几个是文档里写着的、也是我真碰上的,按遇到概率排:

  • ICMP 探测全是 permission denied:OpenWrt 默认 net.ipv4.ping_group_range = 1 0,等于把非特权 ping socket 整体禁掉了。一次性修复是写一条 sysctl 配置(0 2147483647),mibee-steward doctor 会检查这一项。这个坑的概率接近 100%,装完先查它。

  • bind: address already in use:LuCI 占着 80/443,采集器/中心换到 8080 之类。

  • scp报 /usr/libexec/sftp-server: not found:厂商固件(含 GL.iNet)不带 sftp-server,新版 scp 回退 SFTP 就失败。加-O 强制旧协议。
  • GL.iNet MT2500 上新建的 IPv4 监听握不了手:厂商内核 bug,SYN-ACK 以未填充的 0.0.0.0 发出去被对端 RST,v6 正常。该固件上的解法是绑 v6(server.host: "::"),或者干脆让路由器只跑采集器、中心放别处。这台机器我最后就是这么用的。

  • database is locked (SQLITE_BUSY):WAL 模式下高并发探测的写冲突。连接池上限是编译期固定值,实际可调的是降低scanner.max_concurrent_hosts

  • MIPS 路由器直接劝退:modernc.org/libc(纯 Go SQLite 后端的传递依赖)没有可用的 mips 移植,老款 ath79/ramips(Archer C7、R7000 那批)不在支持之列。ARM/ARM64 才行。

顺带一个好消息:v0.7.0 第一次提供了armv7 的采集器二进制(mibee-agent-linux-armv7)。我那块 NanoPi NEO 就是 armv7,以前得自己交叉编译,现在直接下载就行。

现在还做不到什么

  • MIPS 架构不支持,是 modernc/libc 的结构性限制。要支持得把 SQLite 后端换成 bbolt 或 goleveldb,那是真正的重构,我推迟到真有 MIPS 需求时再说。

  • .ipk/.apk是手工组装的二进制包,不是 OpenWrt buildroot 官方产物。包内标Architecture: all,真正的架构闸门在 pre 脚本的 uname 检查 + 冒烟执行;精确的逐目标架构命名、签名和软件源(feed)订阅还没做。能用,但别指望opkg update装到它。

  • 采集器的本地 DB 路径没有独立配置项,固定是配置文件同目录下的 agent.db。想挪到 tmpfs 得把整个配置目录搬过去,重启后配置要重建——所以我的建议是留在闪存,它写量很小(只暂存扫描结果),断连期间还有内存队列(100 批)顶着。

  • hostapd 的 WiFi 终端源还没做活体验证。测试里解析的是真实的 hostapd_cli/iw 抓包,但我手上还没有带 AP 的实测环境,这条只能算「代码写完了、没在活机上验过」。

  • 行覆盖率 74.3%(2026-10-09,cargo llvm-cov),Rust 侧的覆盖率棘轮还没做成 CI 门禁。这个数字其实低估了验证强度——分类器和 SNMP 层是全语料字节对拍把门,行覆盖率看不见它们。

  • 它是单人项目。GitHub 上 485 次提交全部出自我一个人,响应速度取决于我的时间和状态。有问题可以提 issue,不保证当天回。

实测记录

两个节点的切换时间是 2026-10-06:NanoPi NEO(armv7,systemd)和 FastRhino R68S(arm64,走 iStoreOS 的网页包通道)。从那之后的 0.1.0 → 0.1.5 五次生产升级:零失败升级、零服务重启(整个窗口 NRestarts=0)、零扫描节奏缺失。

随机 MAC 守卫、多宿主稳定性修复、TLS-CN 主机名通道这几个改动都是在这个窗口里发出来并实测过的——也就是说,上一篇里写的那些修复,是先在路由器上跑过才进的版本。

项目地址

仓库(AGPL-3.0):https://github.com/Mi-Bee-Studio/MiBeeSteward

Releases(v0.7.0,采集器有 amd64 / arm64 / armv7 三个二进制和路由器包):https://github.com/Mi-Bee-Studio/MiBeeSteward/releases

Rust 采集器完整对比报告(这篇里每个数字的出处):https://github.com/Mi-Bee-Studio/MiBeeSteward/blob/main/docs/zh/agent-rs.md

OpenWrt 部署文档(安装、排障表、资源占用):https://github.com/Mi-Bee-Studio/MiBeeSteward/blob/main/docs/zh/openwrt.md

如果你手上也有一台吃灰的 ARM 路由器,它是能当网络探针用的——4.8MB 的二进制,12MB 常驻内存。跑起来之后告诉我哪些设备没被认出来,这类反馈对指纹库的贡献最直接,我这边也能收到 star。


我在「蓝宝石的傻话」写一个人维护几张异地局域网的实战:自托管、网络、开源项目的开发和踩坑。这个系列上一篇是《86 台设备,我手写的清单里至少 6 条是错的》,讲这套东西解决什么问题;再往下想写的是指纹规则怎么写——你自己认设备那条路也能走通。

相关文章
|
1月前
|
存储 Linux 网络安全
免备案跨境主机实战、阿里云香港轻量应用服务器全解:配置价格、性能实测与建站选购避坑指南
面向海外访问的站点、跨境开发测试项目,很多开发者会优先选择免备案的香港节点云主机。阿里云香港轻量应用服务器作为开箱即用的跨境计算产品,将CPU、内存、ESSD系统盘、峰值带宽、月度上行流量打包为一体化套餐,搭配独立公网IPv4,不需要备案即可解析域名上线业务,受到个人站长、开发者以及小微企业的青睐。
471 2
|
1月前
|
人工智能 机器人 数据挖掘
WhatsApp API最新收费调整:Meta Business Agent按Token收费,Service消息10月起按条计费
2026年8月起,Meta Business Agent按Token收费;10月起,24小时窗口内的Service消息和Utility模板正式按条计费。WhatsApp客服回复、AI应答和订单通知不再免费。本文详解规则变化、成本影响及企业降本策略。
277 3
|
2月前
|
存储 安全 网络安全
【网络安全】认证与授权:OAuth2.0、JWT、SSO、RBAC/ABAC 权限模型(附《思维导图》+《认证授权:时序图 + 微服务网关鉴权落地架构》)
本文系统梳理认证(AuthN)与授权(AuthZ)知识体系,涵盖SSO、OAuth2.0、JWT、OIDC、RBAC/ABAC等核心协议与模型,从原理、架构、安全实践到微服务网关落地,提供结构化、可落地的技术选型与避坑指南。
|
2月前
|
人工智能 Kubernetes 负载均衡
|
2月前
|
弹性计算 安全
阿里云服务器ECS按流量计费的话,1GB流量多少钱?流量超出会怎样?
阿里云ECS按流量计费仅对出网流量收费,各地域单价不同:北京/上海/杭州等为0.8元/GB,青岛0.72元/GB,海外低至0.5元/GB。超量不限速,但欠费将暂停公网访问。详情见官网定价页。阿里云服务器ECS官网:https://t.aliyun.com/U/AZBUsA
|
2月前
|
人工智能 缓存 安全
模型这么多,请求该交给谁?阿里云 AI 网关智能路由,正式上线!
模型越来越多,每次请求该交给谁?AI 网关智能路由已上线:能力够是前提,更省、更快还是更适合由你选,Agent 干活中途不换脑。
|
2月前
|
消息中间件 存储 安全
RocketMQ 高可用创新论文入选 ACM FSE:无需复制业务数据,实现有状态服务秒级接管
面向云上有状态服务高可用,提出无需额外业务数据复制的秒级故障接管机制,在不牺牲成本和稳态性能的前提下,实现云上有状态消息服务的快速恢复。
253 15
|
3月前
|
人工智能 监控 测试技术
银行业AI架构:从裸调API到六层技能体系
# 银行AI智能体架构实战:从单体到Skill协同的技术演进 ## 痛点:银行IT架构的三重困境 走在任何一家银行的科技部走廊里,你都能听到同样的叹息:系统又慢了、需求又排不上、监管又来查了。这不是某一家银行的困境,而是整个银行业IT架构的共性问题。我们把它拆解为三重困境。 **困境一:单体系
|
3月前
|
存储 人工智能 关系型数据库
【新版】阿里云 云数据库RDS 功能介绍及配置价格表(MySQL/PostgreSQL/SQL Server)
阿里云云数据库RDS(Relational Database Service)是稳定可靠、可弹性伸缩的托管式关系型数据库服务,基于飞天分布式架构与高性能存储,全面支持MySQL、PostgreSQL、SQL Server、MariaDB四大主流引擎。新版RDS在AI能力、高可用架构、性能优化、安全管控、弹性计费等维度实现全面升级,推出基础版、高可用版、集群版三大系列,覆盖个人开发、企业应用、数据分析、AI训练等全场景。新版RDS以“智能、稳定、安全、弹性”为核心,提供包年包月、按量付费、Serverless、节省计划、资源包等多种计费模式,满足不同用户的多样化需求。本文将系统梳理新版RDS的核
643 2