拆解飞牛fnOS 30天:我都做了什么
这篇是阶段性总结,记录一下这一个多月拆解飞牛fnOS的全过程,以及踩过的坑、发现的好东西。
写在前面
事情的起因是导师给了一台飞牛NAS,让我先把它的底层摸清楚,为后面的工作做准备。
一开始我以为就是个"开箱体验"级别的任务——装个系统、点点Web界面、看看有什么功能。结果SSH进去之后越挖越深,一搞就是一个多月,出了十几万字的文档。
今天就把这30天的工作做个总结,也算给自己一个交代。
第一阶段:摸底——从哪开始挖?
先搞清楚这是什么系统
刚SSH上去的时候,第一步当然是认系统:
cat /etc/os-release
uname -a结果发现是Debian 12改的,内核版本6.18,还带了个 .c1032-trim 的后缀——一看就是飞牛自己编译的内核。
这就有意思了:它不是拿个现成的Linux发行版改个皮肤,是连内核都自己重新编译过的。
定个计划,不然容易乱
系统是Debian、内核是自研的,那能挖的东西就多了。我列了个4天的学习计划:
- 第一天:系统基础+启动流程+存储架构
- 第二天:文件服务+用户权限
- 第三天:Web后端+应用生态
- 第四天:整体梳理
事实证明这个计划定早了——光存储架构这一块,就挖了整整两天。
第二阶段:存储层——最大的发现来了
意外发现 /fs
第一天挖到存储的时候,我在根目录下看到一个不认识的挂载点:/fs。
df -h /fs
Filesystem Size Used Avail Use% Mounted on
trimafs 1.9T 40G 1.8T 3% /fstrimafs?这是什么文件系统?不是ext4,不是ZFS,不是Btrfs,我从来没听过。
继续挖:
lsmod | grep trim
trimafs2 77824 1一个叫 trimafs2 的内核模块,77KB。再看 /proc/filesystems 里的注册信息,标了 nodev——说明它不是直接管磁盘的,是个联合文件系统。
它到底联合了什么?
往下看底层:
mount | grep vol
trim_6c71e3b3-... on /vol2 type zfs (rw,noatime,xattr,trimacl,casesensitive)
/dev/mapper/trim_d1c5b5d5-... on /vol3 type ext4 (rw,relatime)结果让我有点惊讶:
/vol2是 ZFS/vol3是 ext4
两个完全不同的文件系统,被 trimafs2 在内核层拼成了一个统一的 /fs。
为什么要这么做?
我后来想了很久这个问题。传统NAS的存储池是物理绑定的——你建一个RAID5,就是一个独立的池,想加盘就得往这个池里加,想合并两个池?不行,得拷数据。
但真实用户的情况是:硬盘是陆续买的。第一年一块盘,第二年加两块,第三年又加一块。不同时期的盘,文件系统可能不一样,RAID可能不一样,接口可能也不一样。
飞牛这个方案的思路就是:底层各自独立,上层统一视图。ZFS还是ZFS,ext4还是ext4,各自的快照、校验、容错都在。但用户看到的就是一个大目录,存文件不用关心落在哪块盘上。
加新盘?直接挂进来就行,不用数据迁移。
和开源方案比怎么样?
现在开源圈做联合文件系统,最常用的是 mergerfs。但 mergerfs 是用户态FUSE实现的——每次文件操作都要在用户态和内核态之间来回拷贝,性能开销不小。
飞牛这个是内核态自研的,直接在VFS层处理,没有额外的上下文切换,性能好很多。但代价是开发难度大——内核模块有bug,直接系统panic,数据都可能丢。
77KB的代码量,看起来不多,但内核级代码的复杂度,懂的都懂。
还有个配套的:trimacl
ZFS的挂载参数里还有个 trimacl——原生ZFS没这个参数,是飞牛打了补丁的。
这个补丁的作用是:统一不同文件系统的权限模型。ZFS和ext4的ACL本来就不一样,打了这个补丁之后,不管你底层是什么文件系统,权限行为都是统一的。
联合文件系统 + 统一权限补丁,这两个加起来,才构成了飞牛存储层的完整自研技术栈。
第三阶段:后端架构——30个微服务全走Unix Socket
挖完存储,开始看Web后端。
我先看Nginx配置,结果发现一个很特别的地方:所有后端服务都是Unix Socket,没有一个用TCP端口的。
upstream trim_cgi {
server unix:/run/trim_cgi.socket;
}
upstream accountsrv {
server unix:/var/run/trim.accountsrv.sock:;
}
# ... 一共30多个账户服务、文件服务、快照服务、docker管理……每个都是独立的进程,独立的systemd服务,全部通过本地socket和Nginx通信。
为什么要这么设计?
我觉得好处很明显:
- 安全:所有服务都不暴露端口,外面只能访问Nginx那几个端口,攻击面小
- 解耦:每个服务独立重启,不影响其他服务
- 性能:本地socket比TCP快,没有网络栈开销
- 开发友好:每个服务可以用不同语言写,只要跑个HTTP server监听socket就行
另外还有个全局的安全访问码机制——用Nginx的 auth_request 做的,所有请求先过一次校验,再转发到后端。相当于全系统的二次验证。
第四阶段:文件服务——SMB里的四个自研VFS模块
再往下看文件服务,SMB的配置里也有惊喜:
vfs objects = trim_perms full_audit shadow_copy2 trim四个自研的VFS模块:
trim_perms:权限控制full_audit:操作审计shadow_copy2:快照恢复trim:飞牛自己的一套逻辑
相当于SMB这一层也不是原生Samba,是深度定制过的。FTP、WebDAV同理,都是改了的版本。
第五阶段:输出——从碎片到系统文档
挖了这么多东西,如果不整理,过两天就忘了。所以我边挖边写,最后出了一套系列文章:
- 系统基础与启动流程
- 存储架构深挖
- 系统目录结构与技术栈
- 文件服务与用户权限体系
- Web后端架构深度解析
- 系统识别方法论与二次开发指南
另外还单独写了一份给老师看的正式报告,把最核心的技术发现都整理进去了。
这一个多月的感受
1. 飞牛的技术实力比我想的强
一开始我以为就是个"Debian改了改"的NAS,结果挖下来发现,从内核模块到VFS补丁,从微服务架构到SMB定制,自研的东西比我想象的多得多。
官方宣传里几乎不提这些——你去看飞牛官网,全是AI相册、智能影视这些应用层功能。真正硬的东西,全藏在底下。
2. 拆解的方法比结果重要
这一个多月最大的收获,不是发现了几个技术点,而是学会了一套"怎么拆解一个陌生系统"的方法:
- 先认系统,再摸架构
- 从
/proc、lsmod这种零成本的地方入手 - 看到不认识的东西,顺藤摸瓜往下挖
- 边挖边记,不然第二天就忘了
这套方法,后面拆奥瑞克的机器也能用。
3. 写博客是最好的学习方式
挖完只是第一步,能把它写成文章讲清楚,才是真的懂了。
写的过程中会发现很多"我以为我懂了,其实没懂"的地方——比如联合文件系统的设计动机,一开始我只觉得"挺酷",写文章的时候逼自己想"为什么要这么做",才想明白它解决的是渐进式扩容的痛点。
接下来做什么
- 继续写系列文章,目前第一篇(联合文件系统)已经写完了,后面还有trimacl、微服务架构这几篇
- 开始拆奥瑞克的机器,做对比分析
- 把拆解的内容整理成正式的技术文档,供项目使用
慢慢来,不着急。
本文记录了拆解飞牛fnOS的全过程,基于fnOS 1.2.0505版本实际分析,仅供技术学习交流。
已有 2 条评论
看完了,感谢分享。
我顺便把文章塞给 ai 了(FnOS 里面的 opencode),让他后续做维护的时候更了解该怎么做
另外飞牛的 AI skill 也蛮有意思的,针对安全部分也做了不少工作。
yegefulpguokwgfswdpdmixnpsenxu