在 VisualSVN Server 里新建仓库时,向导里有一项 Repository Filesystem,只有两个选项:FSFS 和 VDFS。很多人直接下一步就过了,但这一项决定的东西不少——仓库能不能跨站点复制、能不能用 LZ4 压缩、备份该怎么做,都由它定。
顺便纠正一个流传很广的说法:FSFS 不是「数据库存储方式」。它是彻头彻尾的文件系统存储,一个版本对应一个普通文件。Subversion 历史上真正的数据库后端叫 Berkeley DB(BDB),2004 年就被 FSFS 取代了,VisualSVN Server 从来只有 FSFS / VDFS 两个选项,没有 BDB。之所以容易记错,大概是因为 FSFS 仓库的 db/ 目录里确实躺着一个 SQLite 数据库文件(rep-cache.db),但那只是去重索引,不是仓库本体。
一、FSFS:默认的文件系统存储
FSFS 是 Subversion 的标准仓库后端,VisualSVN Server 新建仓库时的默认选项。它的核心设计是每个新版本写成一个不可变的独立文件,这个选择在当年是压倒性的:
| 维度 | FSFS | Berkeley DB(已淘汰) |
|---|---|---|
| 提交的追加成本 | O(N),追加即可 | O(N²),越提交越慢 |
| 崩溃恢复 | 丢一次未完成的事务,已提交的版本永远完好 | 需要跑日志恢复,恢复不了就得重建 |
| 备份 | 拷文件即可,可以只拷增量 | 必须热备工具,不能简单拷 |
| 跨平台 | 纯文件,没有字节序和锁库依赖 | 依赖 BDB 库和环境 |
仓库目录结构
一个 FSFS 仓库就是个普通文件夹,默认都放在 C:\Repositories 下:
MyRepo/
├── conf/ # 仓库配置:svnserve.conf、passwd、authz
├── hooks/ # 钩子脚本:pre-commit、post-commit 等
├── locks/ # 目录级写锁
├── format # 仓库布局版本(3 = 1.5 以后的布局)
├── README.txt
└── db/ # 版本数据的真正存放处
├── current # 当前最新版本号,一个纯文本数字
├── fs-type # 内容固定是 fsfs
├── fsfs.conf # FSFS 后端参数(是否启用去重等)
├── format # FSFS 格式版本,比如 8
├── revs/ # 版本内容,分片存放
├── revprops/ # 版本属性(提交人、时间、日志)
├── transactions/ # 正在进行中的事务,提交完即清空
├── min-unpacked-rev # 打包起点
└── rep-cache.db # SQLite,代表共享(去重)的索引
几个容易看懵的点:
db/format不是format。外层format描述仓库目录布局,db/format才是 FSFS 格式版本,升级格式改的是这个文件。revs/不是平铺的。现代仓库默认分片(sharding),每 1000 个版本文件装进一个子目录,所以版本 1 的路径是db/revs/0/1,版本 1234 是db/revs/1/1234。这是为了避免单目录塞几十万文件拖慢文件系统。分片大小可以调,默认 1000。db/transactions/里出现残留目录通常不用慌,那是没提交成功的客户端事务,不影响仓库一致性,但可以当作异常提交的线索。rep-cache.db是 SQLite,用来记录内容相同文件的复用关系(representation sharing,也就是去重)。它损坏或丢失不会让仓库报废,Subversion 会重建或退化为不去重,不要手工去编辑它。
FSFS 格式版本对照
格式版本决定这个仓库能用哪些特性。VisualSVN Server 官方给了完整对照表:
| FSFS 格式 | 对应 Subversion | 对应 VisualSVN Server | 带来的能力 |
|---|---|---|---|
| 1 | 1.1+ | 1.0+ | 初版 FSFS 后端 |
| 2 | 1.4+ | 1.0+ | 存储数据压缩 |
| 3 | 1.5+ | 1.5+ | 合并跟踪、仓库分片布局 |
| 4 | 1.6+ | 1.7+ | 仓库打包、代表共享(去重) |
| 6 | 1.8+ | 2.6+ | 打包扩展到版本属性(revprops) |
| 7 | 1.9+ | 3.4+ | 逻辑版本内容寻址、可选性能参数 |
| 8 | 1.10+ | 3.9+ | LZ4 压缩 |
旧格式向前兼容(新客户端能读老仓库),所以不升级也不会坏,只是用不到后面的特性。格式 8 的重点是 LZ4:老仓库一直在用 zlib(zlib-0 到 zlib-9 十档,默认 zlib-5),格式 8 的仓库默认改用 LZ4,对大二进制文件的读写速度改善明显。注意是「升级格式之后才生效」,光装新版服务端不会让老仓库自动变成 LZ4。
打包(Packing)
打包是把若干个已经写满的分片拼成单个 pack 文件,减少文件数量和元数据开销。在 VisualSVN Server 里这是管理员手动触发的操作,而且在仓库属性里能看到进度(例如 Shards packed: 7/34)。
要不要打包得看场景:它省的是存储开销和目录项,代价是某些访问路径会略慢。仓库文件数已经到百万级、备份和扫描都被拖累时收益明显;平时小仓库打包没多大意义,还可能换来一点点性能退化。
逻辑寻址(Logical Addressing)
格式 7 引入的可选项,在版本内容和物理存储之间加了一层转换。开启后能减少某些操作的重复存储,但多一次间接寻址。新仓库默认是物理寻址(Physical),官方口径是「久经验证、更稳」,所以除非有明确的体积问题,保持默认即可。
二、VDFS:分布式文件系统存储
VDFS 全称 VisualSVN Distributed File System。理解它的关键一句话是:VDFS 不是 FSFS 的替代品,而是把 FSFS 包了一层,在文件系统之上实现服务器之间的透明数据复制,让分布在不同地点的多个节点各存一份完整仓库。
所以 VDFS 仓库的格式号是个三位数,第一位是 VDFS 格式版本,后两位是它内部封装的那套 FSFS 格式:
VDFS 格式 107 = VDFS 格式 1 + 内部封装 FSFS 格式 7
VDFS 格式 108 = VDFS 格式 1 + 内部封装 FSFS 格式 8
VDFS 格式 1 是目前唯一的 VDFS 文件系统格式。各格式对应的服务端版本:
| VDFS 格式 | 要求 VisualSVN Server | 内部 FSFS 格式 |
|---|---|---|
| 101 / 102 / 103 / 104 / 106 | 3.0+ | 1 / 2 / 3 / 4 / 6 |
| 107 | 3.4+ | 7 |
| 108 | 3.9+ | 8 |
主从架构与「全都可写」
VDFS 用的是经典主/从复制架构:主办公区放主服务器,各分支放从服务器;也可以云上做主、每个办公室做从。典型部署是单域、跨域都支持,也支持非域环境。
和 svnsync 镜像最大的区别在这里:
| 对比项 | VDFS 分布式仓库 | svnsync 镜像 |
|---|---|---|
| 从节点是否可写 | 可写,主从都没有功能限制 | 只读,写入会被服务端拒绝 |
| 复制触发 | 自动、对客户端透明 | 需要定时任务跑 svnsync sync |
| 复制内容 | 整个文件系统层,包括版本属性 | 逐版本同步,钩子和部分属性要另做 |
| 异地读性能 | 本地局域网速度,官方称读操作可提速约 1000% | 仍取决于到上游的链路 |
| 成本 | 企业版授权 | 免费 |
提交的传播规则值得单独记一下:
- 提交到主库:主库写入,之后自动复制到所有从库。主库即使有从库不可达也照样可读可写。
- 提交到从库:事务会同时提交到主库和本节点,再扩散到其他从库。
- 读操作不依赖主库,从库本地就能读全量数据,这正是它加速异地访问的原理。
- 主库不可达时,从库会自动变成只读——这是保护措施,避免两个节点各自写出一套分叉的历史。
创建与复制关系
在 VisualSVN Server Manager 里右键 Repositories → New → Repository,在 Repository Filesystem 里选 Distributed VDFS repository,然后指定角色:
- Master repository:可以新建空库,也可以从现有仓库导入数据。已有的普通 FSFS 仓库想变成 VDFS,做法是停止 VisualSVN 服务后在仓库上右键 → All Tasks → Convert to VDFS Format。
- Slave repository:要填主服务器和主仓库名,认证方式选基于证书(
schannel),灾备场景建议勾上 Enable mutual authentication(双向认证)。
复制关系(角色、主服务器、主仓库路径、认证方式)记录在仓库内的 vdfs.conf 里,包含 role、master-hostname、master-path 以及 [authentication] 段。主库一侧还需要在 Repository Replication Permissions 里把从服务器加为授权复制伙伴(Add server authenticated by Replication Certificate)。
复制是自动的,一般不需要手工触发。想确认从库是否已经追上主库,可以在从库上跑:
# 输出为空 = 已与主库一致
Sync-SvnRepository MyRepo
故障转移要手工做
这一点必须说清楚:VDFS 不是高可用集群,它不提供自动故障转移。主库挂了,从库只是只读,得由管理员显式把某个从库提升为主库:
# 前提:防火墙放行、复制证书在目标机器受信任、该机器在授权复制伙伴列表里
Suspend-SvnRepository MyRepo
Switch-SvnRepository -Name MyRepo -Role Master
Set-SvnRepository MyRepo -ReplicationEnabled $true
Resume-SvnRepository MyRepo
等原主库恢复后,通常的做法是把恢复回来的那台先作为从库接上临时主库(Switch-SvnRepository MyRepo -Role Slave -MasterServer <主机名>),数据追平后再切回主库角色。绝对要避免的局面是旧主库和新主库同时在线且都对外写——那会直接产生两条分叉的历史,这个损失没法用工具自动合并回来。
如果真正需要的是「机器挂了业务不停」,该上的是 Windows 故障转移群集这类方案,VDFS 解决的是多站点访问速度和异地灾备,不是同一件事。
许可证
VDFS 只随 Enterprise 版提供,Standard 版没有这个功能。两种企业授权方式:
| 授权类型 | 覆盖范围 | 注意 |
|---|---|---|
| 标准 Enterprise | 单个 VisualSVN Server 实例 | 集群里每个节点都要各买一份;用户数按每台服务器分别计算 |
| Enterprise Multinode | 同一个 VDFS 复制集群内的所有节点,节点数不限 | VDFS 仓库数量始终无限;授权规模按集群中单个节点的最大用户数买 |
许可证是永久授权 + 12 个月免费升级,规模固定,要加用户只能付费升级到更大规模。仅用于测试软件更新和配置变更的非生产实例可以共用同一份企业授权。试用期 45 天,无需注册。
三、怎么选
| 你的情况 | 选择 | 理由 |
|---|---|---|
| 单机房、单台服务器 | FSFS | 默认、免费、备份简单,用不上复制的任何能力 |
| 一套代码要跨地域给多个办公区用,且希望各地都能提交 | VDFS | 本地局域网速度读写,比 svnsync 只读镜像实用得多 |
| 需要异地灾备副本 | VDFS | 复制是全文件系统层的,比 svnsync 少很多维护工作 |
| 要求主库故障自动接管、业务不中断 | 都不是 | VDFS 需要人工提升角色,这一层要靠故障转移群集 |
| 预算只有 Standard 版 | FSFS | VDFS 在 Standard 版里根本不可用 |
一句话:FSFS 是默认且免维护的选择,只有「多站点 + 各地可写」这个明确需求出现时才值得上 VDFS,因为它的代价不只是钱,还有一套要维护的证书、复制伙伴和人工切换流程。
四、查看和变更已有仓库的存储格式
不用去翻文件,选中仓库看右侧 Details 标签,这些属性直接告诉你仓库的存储形态:
| 属性 | 可能的值 | 含义 |
|---|---|---|
| Filesystem type | FSFS / VDFS | 存储后端类型 |
| Filesystem format | 1、2、3、4、6、7、8 或 101~108 | 三位数即 VDFS |
| Compression | lz4 / zlib-5 等 | 看是否吃到了格式 8 的 LZ4 |
| Sharded / Shard size | yes / 1000 | 是否分片及每片版本数 |
| Shards packed | 7/34 | 已打包的分片数 |
| Logical Addressing | yes / no | 物理还是逻辑寻址 |
变更格式的两条路径:
- FSFS → VDFS:图上操作,停服务后在仓库上右键 → All Tasks → Convert to VDFS Format。注意这是单向的,转过去就没有图形界面的回头路。
- 升级 FSFS 格式版本(比如 4 升到 8 以启用 LZ4):VisualSVN Server Manager 不提供这个入口,要用命令行工具。做法是停止 VisualSVN 服务,用随服务端安装的
svnadmin upgrade升级,或者用svnadmin dump+svnadmin load重建一个最新格式的仓库。两种做法之前都必须先有一份可用的备份,升级失败无法靠改回format文件回退。
五、运维上容易踩的坑
- 别把 FSFS 仓库放在网络共享上。 用 SMB/NFS 共享让多台服务器同时读写同一份仓库文件是坏主意,锁语义不可靠,损坏后很难救。要让多地共享仓库,那是 VDFS 该干的事。
- 杀毒软件要排除仓库目录。 实时扫描会打开并短暂锁住
db/下的文件,正是提交最忌讳的干扰,还可能把正在写的事务文件判成可疑对象。把Repositories目录(以及服务端程序目录)加进排除列表。 - 备份用
svnadmin hotcopy或停服务整目录拷贝。 处在提交过程中的仓库直接拷会得到不一致的快照。不要只拷db/revs,仓库的format、conf/、hooks/缺一个都可能恢复不起来。 - 别手工编辑或删除
rep-cache.db、db/transactions/里的内容。rep-cache.db坏了 Subversion 会自行处理,手工删除反而可能连带影响去重关系。 - 老仓库的压缩不会自动升级。 装了 3.9+ 也还是
zlib-5,非要 LZ4 就得先升格式。 - VDFS 切主不能凭感觉来。 提升从库为主库前,必须确认旧主库已经物理下线或至少不再接收写入,否则会产生两个主库并行写入的分叉。
- VDFS 的复制证书和防火墙要提前准备。 从库加入失败,十有八九是证书没被信任、防火墙没放行,或者从服务器没被加进主库的复制伙伴列表——这三个地方按顺序查。
小结
| FSFS | VDFS | |
|---|---|---|
| 本质 | Subversion 标准文件系统存储 | 封装 FSFS,加一层跨服务器透明复制 |
| 存储单位 | 一个版本一个文件,可分片、可打包 | 同 FSFS,格式号是三位数(如 107) |
| 节点角色 | 无 | 主 / 从,从节点也可写 |
| 故障转移 | 不涉及 | 需人工 Switch-SvnRepository 提升 |
| 授权 | Standard 即可 | 仅 Enterprise |
| 适用 | 绝大多数单站点场景 | 多站点、异地可写、异地灾备 |
最实用的一条判断标准:如果你不打算在第二个地点放第二台 SVN 服务器,就老老实实留在默认的 FSFS,把它放在本地磁盘、排除杀毒扫描、用 hotcopy 做备份,这套组合已经能扛住这个规模下的绝大多数问题。
评论区