ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

SVN备份迁移实战:从dump到load的完整攻略及常见坑位

SVN备份迁移实战:从dump到load的完整攻略及常见坑位 SVN备份迁移实战一套完整的仓库搬迁方案含常见坑位清单干了快十年运维和研发管理经手过的版本控制服务器少说也有十几台。每次接到“SVN备份迁移”这种活儿我知道八成又有人要踩坑了要么是项目组要换机房要么是原来的服务器磁盘快满了要么是领导觉得版本库放在某个人电脑上太不靠谱需要统一迁到公司服务器。SVN这东西虽然老但很多传统团队的存量代码和历史记录都在里面动它之前不想清楚轻则历史提交记录错乱重则整个仓库打不开那真是一晚上都睡不安稳。这篇博文我不会给你讲什么高深理论就结合我实操过的迁移经历从备份方案选型、核心参数解读、完整迁移步骤到常见故障排查把SVN备份迁移这件事掰开了讲清楚。适合刚接手SVN服务器的运维、团队里的版本管理员以及准备把散落的仓库统一收拢的研发负责人。文章里的命令和步骤你直接拿去用踩过的坑我也给你标出来。1. 迁移前的项目调研与备份方案选型1.1 先摸清家底仓库结构、版本规模、二进制文件占比很多人一上来就敲svnadmin命令我建议你先花半天时间做调研。问自己三个问题这台服务器上一共多少个仓库最大的仓库有多少个版本仓库里有没有大量二进制文件比如设计稿、编译产物、安装包调研方法很简单登录服务器执行# 查看SVN根目录下所有仓库 ls -la /data/svn/repos/ # 查看每个仓库的版本号范围需要逐一执行 svnlook youngest /data/svn/repos/project-a svnlook youngest /data/svn/repos/project-b # 统计仓库实际占用空间 du -sh /data/svn/repos/*/这一步千万不要省。我有一次接手一个号称“只有几十个版本”的仓库结果svnlook youngest出来修订号已经到八千多而且里面塞了几百张产品原图整个仓库占了20多个G。如果你用默认方式直接打dump文件备份时间、传输时间和目标服务器磁盘空间都要乘上好几倍。另外要摸清客户端的访问方式团队是直接用svn://协议访问还是走http://Apache有没有配置用户权限文件有没有写钩子脚本这些虽然不属于“备份”本身但迁移时漏掉任何一个都会导致新环境跑不起来。1.2 三种主流备份方案对比SVN仓库备份我常用三种方式这里直接给你一个对比表格方便你结合实际情况选型。备份方式核心命令优点缺点适用场景svnadmin dump/loadsvnadmin dump/svnadmin load版本历史完整保留可跨SVN大版本、跨平台迁移文件可压缩可增量全量备份时速度偏慢大仓库dump文件很大跨服务器迁移、更换SVN主版本、整理仓库历史svnadmin hotcopysvnadmin hotcopy速度快直接复制仓库目录结构热备不影响在线访问高度依赖相同SVN版本无法跨平台/跨版本同机备份、备机容灾、快速恢复文件系统直接拷贝cp/rsync最简单、最直接无需额外操作需要完全停服容易拷贝到不一致状态不推荐小仓库、临时备份、死马当活马医从迁移这个角度说我百分之九十五的情况下会用dump/load。原因后面细讲你先记住这个方向没错。1.3 为什么迁移首选 dump/load 而不是 hotcopy很多人问hotcopy不是更快吗为什么迁移不用它关键在于“迁移”和“备份”的目标不一样。备份是怕数据丢了怎么快怎么稳怎么来迁移则要考虑目标环境可能和源环境不一样。比如你原来服务器是CentOS 6上装SVN 1.6新服务器是Ubuntu 22.04装SVN 1.14这两者的版本库内部格式FSFS的布局和索引方式是有差异的。用hotcopy直接拷贝过去的仓库新版本SVN虽然大致能读但偶尔会有警告高版本往低版本迁更是直接不认。svnadmin dump导出的是纯文本格式的“修订版本数据流”它把这些差异全部抹平了。你在1.6上dump出来的文件拿到1.14版本上load完全没问题反过来从1.14导出到1.6也能load前提是你没用太新的特性。这就好比你把整个房子的图纸、材料和装修记录打包成标准格式的纸箱到新地址重新组装而不是把整栋房子连地基一起平移。提示如果你确认新旧服务器SVN版本完全一致比如都是1.11.x那hotcopy迁移确实更省事。但即便如此我也建议你同时用dump方式导一份完整备份存着双保险。2. 核心细节读懂 dump 与 load 的关键参数2.1 svnadmin dump 的常用参数与作用svnadmin dump的基本用法是svnadmin dump /data/svn/repos/project-a /backup/project-a.dump对一个几百M的仓库这条命令可能要跑十几分钟甚至更久。实际生产环境中我很少直接裸用一般会加参数svnadmin dump -r 0:LATEST --incremental --deltas /data/svn/repos/project-a | gzip -9 /backup/project-a.dump.gz拆开说一下这几个参数-r 0:LATEST指定导出的修订版本范围。0是起始版本LATEST是当前最新版本。如果你只要最近100个版本可以写成-r N:LATESTN是你要的起始版本号。--incremental增量导出。如果不加这个参数dump出来的数据会包含一个“从无到有”的完整基础版本加上之后所有版本的变化量适合用来做镜像。加了它导出的数据等于“基于前面某个版本的增量变化”在合并多个dump文件时很有用。--deltas这个参数让dump文件记录每个版本与上一版本之间的差异而不是每个版本都存一份完整文件快照。好处是dump文件体积明显变小坏处是load的时候需要连续算历史差异会稍微慢一点。对远程传输来说减小体积是实打实的收益。还有一个我常用的组合svnadmin dump /data/svn/repos/project-a | gzip -9 /backup/project-a-$(date %Y%m%d).dump.gz先dump再管道给gzip压缩。别小看这一步文本型的dump文件压缩率可以达到10:1。一个10G的仓库dump出来可能也有8Ggzip之后往往不到1G。2.2 svnadmin load 与版本号重写备份相对简单难点在恢复。svnadmin load的基本用法# 在目标服务器上创建空仓库 svnadmin create /data/svn/repos/project-a-new # 把dump文件灌进去 gunzip -c /backup/project-a.dump.gz | svnadmin load /data/svn/repos/project-a-newload的时候它可能会提示“revision 1 loaded”之类的信息不用紧张这是正常的。有一个细节很多人没注意目标仓库如果之前已有版本号load进去的数据版本号会接着已有版本号递增。所以目标仓库最好是一个“全新创建的空仓库”。还有一个容易踩的坑如果你导出的dump文件带了UUIDload的时候目标仓库会保留这个UUID如果是用svnadmin create新建的仓库它自带一个新的UUIDload完成后会被dump里的UUID覆盖。这本身没问题但对客户端来说仓库UUID变了原来所有工作副本的URL定位就会失效。后面我会单独讲svn relocate的操作。2.3 增量备份与完整备份的组合策略上面讲的是全量dump。服务器上跑了多个仓库或者单个仓库特别大的情况下每次迁移/备份都全量dump显然不现实。更合理的做法是全量增量组合。假设你有一个仓库周一凌晨做了全量备份full.dump含r0到r100之后每天做增量# 周二增量备份r101到r110 svnadmin dump -r 101:110 --incremental /data/svn/repos/project-a inc-101-110.dump # 周三增量备份r111到r120 svnadmin dump -r 111:120 --incremental /data/svn/repos/project-a inc-111-120.dump恢复当天你要按顺序loadgunzip -c full.dump.gz | svnadmin load /data/svn/repos/project-a-new gunzip -c inc-101-110.dump.gz | svnadmin load /data/svn/repos/project-a-new gunzip -c inc-111-120.dump.gz | svnadmin load /data/svn/repos/project-a-new顺序不能乱也不能漏。我吃过一次亏增量包漏了中间一段load时报错说“期望修订版本110实际接收101”整个恢复过程只能推倒重来。注意做增量dump时命令里必须加--incremental。不加的话dump文件开头会带一个独立的基础版本这会导致后续load时版本号重复甚至直接报错。2.4 备份文件务必验证svnadmin verify 是你的救命稻草备份完不是就完事了一定要验证。svnadmin verify是检验仓库完整性的工具svnadmin verify /data/svn/repos/project-a它会逐版本检查仓库内部数据结构发现问题会明确报告。“verify通过”意味着仓库本身是健康的备份文件只要基于它dump出来理论上也健康。对dump文件本身的验证我一般这样处理load完成之后在新仓库上再执行一次svnadmin verify。如果新仓库verify通过同时svnlook youngest显示的版本号跟源仓库一致那这次迁移基本就稳了。这个双端验证的环节看起来多花几分钟实际上能帮你挡掉九成以上的“迁移后才发现数据不对”的灾难。3. 按部就班一个真实仓库的迁移过程实操3.1 从旧服务器导出完整备份假设我有一台老服务器仓库路径/home/svn/repos/oa-system需要迁到新服务器。完整操作流程如下。第一步在旧服务器上查看仓库状态svnlook youngest /home/svn/repos/oa-system # 假设输出2456第二步执行全量dump带压缩svnadmin dump --deltas -r 0:2456 /home/svn/repos/oa-system | gzip -9 /tmp/oa-system-$(date %Y%m%d).dump.gz执行过程中别急着干别的留意输出。如果中途出现* Dumped revision 0、* Dumped revision 1这样的进度说明在正常跑。如果一直卡着不动八成是仓库有问题或者IO瓶颈。第三步检查备份文件ls -lh /tmp/oa-system-*.dump.gz # 确认文件大小合理比如大于0第四步把备份包传到新服务器。我一般用rsync断点续传比scp靠谱rsync -avzP /tmp/oa-system-$(date %Y%m%d).dump.gz usernew-server:/tmp/3.2 在新服务器上创建并导入仓库来到新服务器先确认SVN版本svnadmin --version创建新仓库svnadmin create /data/svn/repos/oa-system这里有个小细节svnadmin create默认会创建一套完整的仓库结构包括hooks、conf、format等目录。如果你希望新仓库的目录布局和旧仓库完全一致可以加上--fs-type fsfsFSFS是默认但显式声明更好其他参数保持默认。然后执行导入gunzip -c /tmp/oa-system-*.dump.gz | svnadmin load /data/svn/repos/oa-system导入过程会有大量输出每加载一个版本会打印一行。看到------- Committed revision N 这样的字样说明在正常推进。全部结束后执行验证svnadmin verify /data/svn/repos/oa-system svnlook youngest /data/svn/repos/oa-system # 期望输出2456和源仓库一致到这里仓库数据本身已经迁过来了。3.3 权限文件、钩子脚本与配置文件的同步仓库数据迁完新服务器上的SVN服务要能正常对外提供服务还差权限体系和钩子脚本。SVN的原生权限体系依赖conf/svnserve.conf、conf/passwd和conf/authz这三个文件。其中svnserve.conf定义仓库访问方式、是否启用认证、匿名访问权限等。passwd存放用户名和密码纯文本格式。authz路径级别的权限控制比如哪些用户能读哪些目录、谁能写哪些分支。直接把这几个文件拷贝过去覆盖即可cp /home/svn/repos/oa-system/conf/svnserve.conf /data/svn/repos/oa-system/conf/ cp /home/svn/repos/oa-system/conf/passwd /data/svn/repos/oa-system/conf/ cp /home/svn/repos/oa-system/conf/authz /data/svn/repos/oa-system/conf/钩子脚本在hooks目录下常见的如post-commit提交后触发常用于触发构建或发送通知、pre-commit提交前校验常用于检查提交信息格式。这些脚本是Unix可执行文件拷贝后要记得赋予执行权限chmod x /data/svn/repos/oa-system/hooks/*注意很多人在这一步只迁数据不迁钩子导致新环境的“提交后自动部署”“邮件通知”等全部静默失效。建议迁移完把 hooks 目录逐个脚本核对一遍确认没有遗漏。还有一项容易被忽略如果SVN是通过Apache的http模式访问涉及dav_svn.conf的Location配置、SSL证书等这些不在svnadmin的管辖范围内需要单独在Apache配置里迁移或重配。3.4 客户端视角svn relocate 的正确姿势服务器端一切就绪后开发团队的客户端要改远程仓库地址。SVN客户端不支持像Git remote那样随意切换而不出问题但SVN官方提供了优雅的方案svn relocate。老版本SVN的命令是svn switch --relocate http://old-server/svn/oa-system http://new-server/svn/oa-systemSVN 1.7以后简化为svn relocate http://old-server/svn/oa-system http://new-server/svn/oa-systemTortoiseSVN用户更简单右键工作副本 - TortoiseSVN - Relocate填新地址即可。执行relocate后再执行svn update如果没有报错且能拉取到最新代码说明工作副本切换成功。这里有一个容易导致团队混乱的细节如果新旧服务器的仓库UUID不一致relocate会失败或导致工作副本与仓库不匹配。在svnadmin load时如果dump文件里带有原UUID新仓库就已经自动沿用了。你可以用下面的命令确认svnadmin dump /data/svn/repos/oa-system --revision 0 | grep UUID如果没有沿用需要手动设置svnadmin setuuid /data/svn/repos/oa-system 原仓库UUID3.5 迁移完成后的完整验证清单本次迁移结束前建议按清单逐项验证检查项检查方法预期结果仓库版本号svnlook youngest /data/svn/repos/oa-system与源仓库保持一致仓库完整性svnadmin verify /data/svn/repos/oa-system无错误输出权限控制用非管理员用户checkout、commit测试权限拦截生效钩子脚本执行一次提交观察钩子输出/日志钩子正常触发工作副本团队执行svn relocatesvn update无报错版本一致服务自启确认svnserve或httpd开机自启配置重启服务器后服务可用4. 常见问题与排查技巧实录4.1 svnadmin load 报错版本号连续性与重复导入load时报 “Revision 20 already exists” 是最典型的错误通常是因为目标仓库不是空的或者同一个dump文件被load了两次。解决办法只有一个新仓库必须用svnadmin create全新创建不要在已有历史的仓库上loadload之前用svnlook youngest确认目标仓库为空返回0。4.2 dump文件损坏load过程中如果报 “Malformed dumpfile header” 或 “Unexpected end of dump file”多半是dump文件在传输或压缩过程中损坏了。处理思路先检查源仓库本身健不健康如果不确定就执行svnadmin verify。重新dump这次建议不压缩或换用gzip -1这种低压缩比模式再重新传输。传输建议用rsync加-P参数确保文件完整传到目标机器后再解压。4.3 Windows端 TortoiseSVN 的一系列客户端问题热搜词里有一堆TortoiseSVN关键词我猜很多读者是Windows环境下的小乌龟用户。先说和迁移最相关的几个。rebase/update时出现 “Cannot relocate URL: previous location has different repository root” 这种报错说明新旧URL不在同一个仓库根下。你要用仓库根URL来relocate而不是用分支目录URL。SVN的relocate要求只是“仓库根路径”变了内部结构和相对路径不能变。还有另一个特别常见的是“clean up”卡死。提交或更新被中断后工作副本被锁住右键clean up也不动。我一般用两种方法一是关掉所有占用该目录的编辑器/IDE进程再clean up二是如果不行到wc.db文件所在目录用SQLite工具清掉work_queue表里的残留记录。再说一个Windows安装环境相关的经典报错安装TortoiseSVN时提示“安装程序错误2503/2502”。这个是因为Windows Installer缓存目录权限不对。处理办法用管理员身份运行cmd执行msiexec /package 小乌龟安装包.msi通常能绕过报错完成安装。4.4 迁移后权限丢失或变样如果新环境里所有人都能访问所有仓库或者某些用户权限突然失效优先排查authz文件里的路径组名。SVN的authz文件里有[groups]段定义用户组后面路径里用组名引用。迁移过程中如果仓库根路径如[oa-system:/]的变化导致组名对应不上就会出问题。一个常见坑旧服务器里仓库名是oa-system新服务器里svnserve.conf配置的仓库根是/data/svn/repos/客户端访问的URL变成了svn://new-server/oa-system看起来名没变。但如果你把仓库改名为oa_systemauthz里的路径段全部要跟着改很多人漏了这步导致权限静默失效。4.5 大仓库dump导出核Big文件支持热搜词里有“svn 支持大的二进制文件存放吗”这里给你一个明确结论SVN支持存放任意大小的文件理论上文件系统支持多大就存多大但大二进制文件会显著拖慢仓库性能和dump/load速度。因为SVN是基于差异存储的二进制文件每次变更都可能存一个完整副本仓库体积会迅速膨胀。迁移中如果遇到超大单文件比如超过1G我的建议是先确认这个文件是否真的需要入库如果只是编译产出物或临时安装包建议挪出版本控制改用统一存储或制品库。必须入库的话dump时加上--deltas参数至少能把每次变更的体积压一压。load到新仓库后定期用svnadmin pack对FSFS仓库做一次整理压缩历史数据。4.6 relocate之后提交冲突团队成员执行relocate后如果本地工作副本还停留在旧地址提交时会报 “Repository UUID mismatches” 或 “Working copy path ... is out of date”。这种情况我在迁移后见过不少次多半是有人忘了执行relocate硬用旧URL提交。解决方案很直接命令重新relocate一遍然后svn update校准到最新版本。如果本地有未提交的改动先svn status看清楚状态再操作别莽撞地clean up。5. 迁移后的长期维护与自动化备份建议仓库迁到了新环境以后不能再裸奔了。我建议你趁热打铁把自动备份机制也搭起来。最简单稳妥的策略是每天凌晨用svnadmin hotcopy做一份全量镜像备份到另一块磁盘每周做一次svnadmin dump完整归档加压缩。热点仓库每天提交量大的可以另外加增量dump。Linux服务器上的定时计划用cron# 每天凌晨2点热拷贝 0 2 * * * /usr/local/bin/svn-backup-hotcopy.sh # 每周日凌晨3点全量dump并压缩 0 3 * * 0 /usr/local/bin/svn-backup-dump.shWindows环境用任务计划程序定时执行bat脚本即可。脚本逻辑很简单先创建带日期的备份目录执行hotcopy/dump命令最后把超过N天的旧备份删除。搭完定时备份之后建议做一次演练。演练目标不是“能备份”而是“能从备份恢复”。很多团队备份脚本写了一堆真出故障时才发现备份文件是坏的或者恢复流程没人会。按月或按季度做一次“恢复演练”把备份load到临时目录确认能checkout出代码这件事才算闭环。聊到最后一个实际体会SVN的备份迁移本质上不是技术难题而是“细心活”。所有坑都出在细节上——仓库结构没摸清、权限文件漏了带、钩子脚本没同步、客户端relocate没指导到位。你只要把每个环节都当成检查点来过一遍按本文的清单执行这个活儿基本不会翻车。最后再分享一个小技巧在旧服务器正式下线之前建议保留至少一周的只读窗口期。直接把svnserve服务停掉但别删除仓库目录万一新环境出了什么幺蛾子你还能重新回到旧环境救场。这一周“和平共存期”是我踩过几次坑之后养成的习惯成本极低价值极高。
返回列表