跨平台迁移踩坑记:从路径大小写到国产操作系统的那些事
去年做一个项目,要把一套系统从Windows Server迁移到国产的麒麟系统上。数据库用的是金仓,数据量不大,本以为一两天就能搞定。结果光是把表空间挪过去就折腾了整整一个下午。
问题出在路径上。Windows上用反斜杠写的路径,到了Linux上不认。还有个更隐蔽的问题------老系统里有个表空间路径用了大小写混写,在Windows上跑得好好的,到了麒麟系统上报"目录找不到"。当时我就想,同一个数据库,换个操作系统怎么就这么别扭?
后来查文档才发现,金仓有个自动创建表空间目录的功能,而且专门测试过大小写混写的路径。顺着这个往下挖,发现这里面涉及的东西还挺多。
一个参数解决的老大难问题
先说说这个自动创建表空间目录的功能。
以前在建表空间的时候,必须先把目录建好,属主改对,才能执行CREATE TABLESPACE。少一步都不行。
sql
-- 老方式:先手动建目录
-- 操作系统执行:mkdir -p /data/kingbase/tablespace/order
-- 操作系统执行:chown kingbase:kingbase /data/kingbase/tablespace/order
-- 然后才能建表空间
CREATE TABLESPACE order_data LOCATION '/data/kingbase/tablespace/order';
现在有了auto_createtblspcdir参数(默认开启),可以直接执行CREATE TABLESPACE,目录不存在的会自动建。
sql
-- 新方式:数据库自动建目录
CREATE TABLESPACE order_data LOCATION '/data/kingbase/tablespace/order';
这个功能本身不复杂,但它解决的问题却很有代表性------不同操作系统对路径的处理方式不一样,数据库帮用户屏蔽了这些差异。
官方文档里有个细节挺有意思:测试用例里专门用了大小写混写的路径名TEst3。这说明开发人员意识到,路径大小写在不同操作系统上的表现是个容易踩坑的地方。
路径分隔符:一个反斜杠引发的血案
Windows和Linux在路径表示上一个明显的区别就是分隔符。Windows用反斜杠\,Linux和Unix用正斜杠/。两者不通用。
比如Windows上这样的表空间定义:
sql
-- Windows上的写法
CREATE TABLESPACE app_data LOCATION 'D:\kingbase\data\tablespace\app';
如果直接把这个SQL拿到Linux上执行,会报错,因为\k、\t这些会被解析成转义字符。需要手动改成:
sql
-- Linux上的写法
CREATE TABLESPACE app_data LOCATION '/opt/kingbase/data/tablespace/app';
这个问题迁移的时候特别容易忽略。脚本里有几十个表空间定义,手动改一遍很容易漏。
一个实用的建议:在SQL里统一用正斜杠,即使在Windows上也这么写。金仓能正确解析。
sql
-- 跨平台兼容的写法
CREATE TABLESPACE app_data LOCATION 'D:/kingbase/data/tablespace/app';
这样写,Windows和Linux都能认,迁移的时候不需要改。
大小写敏感:另一个容易被忽视的问题
官方文档里专门测试了TEst3这个路径名,说明开发团队意识到了大小写敏感度在不同操作系统上的差异。
问题的本质是:Windows上的文件名不区分大小写,Linux上严格区分。TABLE、Table、table在Windows眼里是同一个东西,在Linux上是三个不同的。
如果一个表空间在Windows上创建时路径写了/data/MyData,实际目录是/data/mydata,Windows上照样能访问。把这个表空间定义迁移到Linux上,数据库去找/data/MyData,发现不存在,就报错了。
规避风险的建议:
sql
-- 推荐:全部用小写
CREATE TABLESPACE order_data LOCATION '/data/kingbase/tablespace/order_data';
-- 不推荐:大小写混写
CREATE TABLESPACE order_data LOCATION '/data/Kingbase/Tablespace/Order_Data';
全部用小写是最稳妥的做法。如果历史遗留系统里已经有大小写混写的路径,迁移之前先检查一下:
sql
-- 查看现有表空间的路径
SELECT spcname, pg_tablespace_location(oid) FROM pg_tablespace;
确认路径名的大小写和实际目录完全一致,再执行迁移。
国产操作系统的特殊要求
现在很多项目要求跑在统信UOS、麒麟这类国产操作系统上。这些系统底层还是Linux,路径分隔符和大小写规则和标准Linux一样。但问题不在系统本身,而在配套的加密文件系统。
有些国产操作系统支持文件级加密,比如麒麟的"麒麟加密"、统信的"统信安全文件系统"。开启加密后,对目录属主和权限的要求更严格。
加密文件系统对数据库的影响:
- 目录属主必须是数据库运行用户,加密系统也认这个
- 加密目录的权限更严格,分组权限可能受限
- 自动创建目录时,创建出来的目录可能需要同时满足加密策略的要求
金仓的自动创建目录功能在创建目录时会设置正确的属主(运行数据库的操作系统用户)。在加密文件系统上,应该也能正常工作,因为底层创建目录的系统调用是一样的。
但有一个潜在问题:如果父目录是加密的,自动创建的子目录会继承加密属性吗?这取决于加密文件系统的具体实现。目前已知大部分国产加密文件系统会继承父目录的加密属性,子目录自动被加密,不需要额外配置。
在加密环境下的操作建议:
- 先把父目录建好并完成加密配置
- 确认数据库运行用户有访问权限
- 然后执行CREATE TABLESPACE,让数据库自动创建子目录
sql
-- 父目录已加密且属主正确
CREATE TABLESPACE secure_data LOCATION '/encrypted/kingbase/tablespace/secure_data';
自动创建的secure_data目录会继承父目录的加密属性。
几个测试命令
在实际部署之前,可以用这些命令确认环境是否符合要求。
测试目录属主:
sql
-- 在数据库外测试
ls -ld /path/to/tablespace
-- 确认属主是kingbase
测试大小写:
sql
-- 建一个测试表空间
CREATE TABLESPACE test_location LOCATION '/tmp/TestPath';
-- 如果成功,检查实际创建的目录名大小写
\! ls -ld /tmp/*Path
测试自动创建:
sql
-- 确认参数开启
SHOW auto_createtblspcdir;
-- 应该返回 on
-- 建一个路径不存在的表空间
CREATE TABLESPACE auto_test LOCATION '/tmp/auto_create_test/testspace';
-- 检查目录是否自动创建
\! ls -ld /tmp/auto_create_test
总结一下
表空间路径这件事,看似是个小问题,但跨平台迁移的时候经常会卡住。金仓的自动创建表空间目录功能,加上对大小写混写路径的测试覆盖,说明开发团队确实在跨平台兼容性上花了功夫。
回顾几个关键点:
- 路径分隔符 :统一用正斜杠
/,跨平台最省心 - 大小写:全小写最安全,不要依赖Windows的大小写不敏感特性
- 国产操作系统:加密文件系统上,先建父目录配好加密,再让数据库自动建子目录
- 跨平台迁移:迁移前检查路径名和实际目录的大小写是否一致
这些细节单个看不致命,但凑在一起就可能把一次简单的迁移拖成持久战。提前了解这些差异,做好规划,能让工作顺利不少。