从一个大小写混合的目录名说起——KES表空间在异构环境下的路径兼容与加密存储踩坑实录

23 阅读15分钟

@[toc]


兼容 是对前人努力的尊重 是确保业务平稳过渡的基石 然而 这仅仅是故事的起点

说实话我本来没打算写这个,但前两天群里又有人在问KES表空间路径的问题,我就想起去年那个折腾了我一整天的坑,越想越觉得得记下来,免得以后再踩。

去年我们做信创项目,数据库用的KES,当时要在一个测试环境上验证表空间的自动创建功能。文档里有个测试场景写的是大小写混合路径,路径长这样:/home/zhangjing/dailybuild0904/bin/test/test1/test2/TEst3。我当时看到这个TEst3就觉得有点意思,为啥要专门搞个大写T和E的混合?后来才明白,这玩意儿是真的有必要测。

先贴一下当时的SQL:

-- 大小写混合路径,注意那个TEst3
CREATE TABLESPACE mysp1 LOCATION '/home/zhangjing/dailybuild0904/bin/test/test1/test2/TEst3';
CREATE TABLE cc(id int, name varchar(50)) TABLESPACE mysp1;
INSERT INTO cc VALUES (1,'xiaozhang'),(2,'xiaozhao'),(3,'xiaohong');
SELECT * FROM cc;

看起来挺简单的对吧?嗯,在Linux上确实简单,跑起来没啥毛病。但是你要是换个环境试试...我后面再说这个。

auto_createtblspcdir这个参数值得单独聊聊

KES有个参数叫auto_createtblspcdir,默认是on。这玩意儿干啥的呢?就是你在CREATE TABLESPACE的时候,如果指定的目录不存在,它会帮你自动创建。说实话这个功能挺实用的,之前没有这个参数的时候,你得手动mkdir一堆目录,少创建一层就报错,烦得要命。

但这不是重点,重点是这个参数背后有五条约束,你得心里有数:

  • 路径必须是绝对路径,不能搞相对的
  • 不能在data目录下面建,这个好理解
  • 路径得唯一,不能跟已有的表空间路径重复
  • 得是超级用户才能操作
  • 目录属主必须跟数据库服务进程的属主一致

这五条看着简单,但最后那条"属主一致",在跟国产加密文件系统结合的时候,真的能搞出一些意想不到的问题。我后面会专门说。

真正的麻烦在跨平台

好了,开始说重点。我记得特别清楚,那天下午客户打电话过来说,他们在Windows服务器上测试表空间创建失败了。我当时的第一反应是——你们为啥要在Windows上跑KES啊?但客户就是客户,你不能这么说话。

然后我就开始排查。Windows上KES的默认安装路径是C:\Program Files\Kingbase\ES\V8,注意这个反斜杠\。而Linux上是/opt/Kingbase/ES/V9,用的正斜杠/。这俩路径分隔符不一样,在脚本和SQL里混着写就容易出事。

更坑的是大小写的问题。你看那个测试场景里的TEst3,在Linux上,ext4文件系统是严格区分大小写的,TEst3和test3和Test3是三个完全不同的目录,没毛病。但是到了Windows上呢?NTFS默认不区分大小写!也就是说你在Windows上创建了一个叫TEst3的目录,然后用test3去访问,它能找到。这在Linux上是不可能的。

# Linux上,这三个是不同的目录
ls /data/test3    # 不存在
ls /data/TEst3    # 存在
ls /data/Test3    # 不存在

# Windows上,这三个指向同一个目录
dir C:\data\test3    # 能找到
dir C:\data\TEst3    # 也能找到
dir C:\data\Test3    # 还是能找到

我有个哥们儿,也是这问题,从Windows迁移到银河麒麟上,折腾了三天。原来他们在Windows上开发的系统,SQL脚本里表空间路径写得乱七八糟,有的用大写有的用小写,Windows上都能跑,到了麒麟上全部报路径不存在。真的是服了。

而且这还不是最要命的。最要命的是你在一个混合环境里——比如开发环境是Windows,生产环境是麒麟或者统信——你在Windows上测试通过了的脚本,到了Linux上全部炸掉。这个属主问题也是,Windows的权限模型跟Linux完全不一样,那个"属主一致"的约束在Windows上的表现跟Linux上也不同。

国产操作系统上的那些事儿

说到国产操作系统,KES支持的平台是真的多。我列一下我接触过的:

Intel/AMD那堆x86的不说了,基本上Linux能跑的它都能跑。关键是国产CPU那块——龙芯上跑统信和银河麒麟,飞腾和鲲鹏上跑统信、银河麒麟、中标麒麟、openEuler,申威上跑统信、银河麒麟、普华。凝思和麒麟信安这种安全增强型的也支持。

这些系统有个共同特点:它们都是基于Linux内核的,所以文件系统层面跟标准Linux行为一致——严格区分大小写,用正斜杠做路径分隔。但每个系统又有自己的"加料"。

比如银河麒麟,它有个磐石安全架构,在文件系统层面集成了SM4加密。你看/home目录下,麒麟OS强化了用户数据加密,符合等保要求。/var/log目录下的日志也做了加密处理。这听起来挺不错,但你要知道,当你的KES表空间目录落在这些有特殊安全策略的文件系统上的时候,问题就来了。

我记得有一次,在某省级单位的麒麟V10服务器上部署KES,创建表空间的时候死活创建不成功。日志里报的是权限不足,但chmod 777都给了还是不行。后来发现是SELinux策略在拦截——麒麟V10的SELinux策略比标准CentOS严格多了。然后还得跟安全策略配合调整,折腾了好久,头发都快揪秃了。

后来解决方案是这样的:

# 先看SELinux状态
getenforce

# 临时关闭(测试用,生产别这么干)
setenforce 0

# 正确做法是调整策略
semanage fcontext -a -t kingbase_db_t "/data/kingbase/tablespaces(/.*)?"
restorecon -Rv /data/kingbase/tablespaces/

说实话我到现在也没完全搞明白麒麟V10上SELinux的所有策略规则,太复杂了。反正就是记住一点:在国产操作系统上搞数据库,先搞清楚安全策略,别上来就装。

跨平台路径处理这个事儿值得好好说说

这个话题其实社区里讨论挺多的,但真正把问题说清楚的没几个。我试着从我自己的理解来聊聊。

早期大家关注的问题比较简单,就是路径分隔符。Windows用\,Linux用/,你写脚本的时候混了就出错。这个好解决,统一用/就行,KES在Windows上其实也能识别正斜杠。

后来问题就升级了。当信创项目大面积铺开之后,异构操作系统之间的迁移变成了常态。比如原来在Windows上跑的KES,现在要迁移到银河麒麟上。表空间路径从D:\Kingbase\data\ts1变成了/data/kingbase/ts1,这不仅仅是分隔符变了,整个路径结构都变了。你得做映射,还得考虑权限。

再后来又出了新问题。有些项目是跨多种国产CPU和操作系统的,比如同一个数据库集群里有x86节点也有鲲鹏节点,表空间路径得在所有节点上一致。KES V9在集群部署的时候支持自动创建表空间目录,这个确实解决了部分问题,但路径一致性还是得靠人工保证。

我觉得有个研究方向被忽视了——就是怎么在数据库层面做一个跨平台的路径抽象层。现在各家国产数据库都是直接用操作系统的原生路径,但你换一个操作系统路径就不一样了,这个在异构集群里是个大问题。目前好像没有谁特别系统地研究过这个。

关于"大小写敏感性"的界定也挺有意思的。严格来说,这不是数据库的问题,是文件系统的问题。但数据库在处理表空间路径的时候,是直接把路径字符串传给操作系统的,所以文件系统什么行为,数据库就跟着什么行为。有些人在讨论要不要在数据库层面做一个大小写归一化处理,但这个争议很大——你做了归一化,Linux用户可能觉得你改变了他的预期行为;你不做,Windows用户又会觉得你的产品在Windows上不好用。反正就是两头不讨好。

接下来说加密的事儿

这个话题我本来不想展开说的,因为加密存储这个领域水太深了。但既然是深度体验嘛,不说不行。

先说KES自己的TDE(透明数据加密)。这玩意儿是KES原生支持的,不是什么外挂插件。加密对象包括数据文件、日志文件、备份文件。加密时机是写入磁盘前自动加密,读取的时候自动解密,对上层应用完全透明。

支持的算法有SM4和AES,这个在信创场景下很重要,因为等保和密评都要求用国密算法。SM4-CBC模式是默认推荐。

创建加密表空间的SQL长这样:

-- 创建加密表空间,使用SM4-CBC算法
CREATE TABLESPACE encrypted_tbs 
LOCATION '/data/kingbase/encrypted' 
WITH (encryption = 'sm4-cbc');

-- 把敏感表挪到加密表空间
ALTER TABLE customer_info SET TABLESPACE encrypted_tbs;

密钥管理这块KES用的是KEK保护DEK的方案。KEK是主密钥,DEK是数据加密密钥。支持HSM硬件安全模块和国密KMS。配置kingbase.conf的时候需要开启:

# kingbase.conf
tde.enabled = on
tde.key_manager = 'kms'

官方说TDE的性能损耗控制在5%以内。说实话这个数据我持保留态度,因为实际场景太复杂了。如果你的IO本身就是瓶颈,加了加密之后损耗肯定不止5%。但如果是CPU不是瓶颈的普通OLTP场景,5%的说法大致靠谱。

TDE还支持WAL日志加密和临时文件加密,这个挺细的,很多人没注意到。临时文件加密很重要,因为排序、哈希这些操作产生的临时文件可能包含敏感数据,如果不加密,直接从磁盘上就能捞到。

但加密跟表空间属主约束结合就出幺蛾子了

还记得前面说的那个"属主一致"的约束吧?KES要求表空间目录的属主必须跟数据库服务进程的属主一致。正常情况下这不是问题,但如果你的目录落在了加密文件系统上,情况就复杂了。

openEuler支持基于SM4的磁盘加密,用的是dm-crypt + cryptsetup,加密算法sm4-xts-plain64:

# openEuler上用国密SM4做磁盘加密
cryptsetup luksFormat /dev/sdd -c sm4-xts-plain64 --key-size 256 --hash sm3
cryptsetup luksOpen /dev/sdd crypt_tbs
mkfs.ext4 /dev/mapper/crypt_tbs
mount /dev/mapper/crypt_tbs /data/kingbase/encrypted

当你把KES的表空间目录放在这种加密设备上的时候,问题来了。首先,加密设备的挂载顺序得在KES启动之前,否则数据库找不到目录。其次,挂载后的目录属主可能不是kingbase用户,你得chown。第三,如果加密密钥的获取需要额外的认证步骤(比如KMS交互),启动流程就得改。

我之前遇到过一个场景,客户用的是麒麟V10 + TPM安全芯片 + KES TDE的三重组合。开机流程是这样的:先TPM验证身份,然后从KMS获取磁盘加密密钥,解密磁盘分区,挂载文件系统,再启动KES,KES自己又从KMS获取TDE密钥。整个链条太长了,有一次TPM固件升级导致认证方式变了,结果整条链全部不通,数据库起不来。那天我看了一眼表,凌晨两点半,服了。

更邪门的是,有时候操作系统层面的加密和数据库层面的TDE会产生冲突。比如你在麒麟V10上,它默认会对/home目录做SM4文件级加密。然后你的KES表空间恰好在/home/kingbase/下面——虽然一般不建议这么放——那数据库写数据的时候,就变成了"KES用TDE加密一遍,操作系统再用文件系统加密加密一遍",双重加密。功能上没问题,但性能嘛...你自己想。

龙蜥ANCK内核的一些新东西

顺便提一下龙蜥的ANCK内核,因为现在好多国产操作系统都是基于这个内核的。ANCK对ext4做了一些增强,比如hardlink约束放宽、jbd2后台checkpoint、慢事务追踪这些。这些增强对数据库表空间的IO行为是有影响的。

特别是jbd2后台checkpoint这个特性,它能让日志提交的延迟更加平滑,对数据库的写性能有好处。但有个前提——你的表空间得在ext4文件系统上才能享受到。XFS也有类似的优化,ANCK给XFS加了DAX reflink支持。

还有一个值得关注的:EROFS压缩文件系统。这个本来是为嵌入式和容器场景设计的,但现在有些国产操作系统把它用在只读表空间的场景。比如你的归档表空间,数据只读不写,放在EROFS上既能压缩节省空间,又能保证数据不被意外修改。但这个我还没在生产环境验证过,只停留在理论探讨阶段。

ANCK还加了国密驱动支持,海光HCT引擎和TPM/TCM/TDM/TPCM可信功能。这意味着在龙蜥内核上,你可以直接通过内核接口调用国密硬件加速,不需要走用户态的库。这对KES TDE的性能优化是个好消息——如果KES能够对接ANCK的国密内核接口,加密性能损耗应该能进一步降低。但目前我还不知道KES是否已经做了这个对接,这个可能需要等后续版本。

我总结一下踩坑经验

说了这么多乱七八糟的,我整理一下我自己踩过的坑,免得你们再踩:

路径大小写问题:在Linux/国产OS上,TEst3和test3是两个不同的目录,但在Windows上它们是同一个。跨平台迁移的时候,一定要统一路径命名规范,建议全部小写。CI/CD流程里可以加个检查:

# 扫描SQL脚本中路径包含大写字母的
grep -rn "LOCATION.*[A-Z]" *.sql

路径分隔符:别用\,统一用/。KES在Windows上也接受正斜杠,所以没必要冒险用反斜杠。

SELinux/安全策略:在国产OS上部署KES之前,先搞清楚安全策略。麒麟V10、凝思这些安全增强系统的SELinux策略比标准Linux严得多,提前做好目录的SELinux标签。

加密存储的启动顺序:如果你用了操作系统级加密 + KES TDE,确保启动顺序正确——先解密磁盘,再挂载文件系统,最后启动数据库。最好写个systemd的依赖关系。

属主一致性:特别是在加密设备挂载后,记得检查目录属主。用ls -ld看一眼,不对就chown。

性能测试:如果你用了TDE,一定要做性能基准测试,不要只信官方的5%数据。你的IO模式和硬件配置不同,结果可能差很远。

最后说两句

写到这里我想起来,其实关于KES表空间路径在不同国产操作系统上的行为差异,社区的讨论还是挺多的,但系统性的文档不多。金仓社区论坛上经常能看到"异构操作系统表空间高级管理"这类帖子,说明大家都在踩这个坑。

我觉得这里有个研究方向挺有意思的——就是怎么在数据库层面实现对不同操作系统文件系统行为的适配层。不是说简单地把\转成/,而是要处理大小写敏感性、权限模型、加密策略这些深层的差异。目前这个方向好像没什么人在做,但信创项目越来越多,异构环境越来越多,这个问题迟早得解决。

还有一点,关于加密存储。KES的TDE是数据库层面的加密,操作系统的dm-crypt是文件系统层面的加密,国产OS的文件级加密(比如麒麟的SM4文件加密)又是另一种。这三层加密怎么组合、怎么避免性能浪费、怎么管理密钥的生命周期——这些问题目前在实践中还没有特别成熟的最佳实践,大家都是在摸索。有些方案在实验室里跑得挺好,到了生产环境因为运维复杂度太高根本用不起来。这种"理论可行但实践落地困难"的困境,我觉得是当前信创数据库领域最需要突破的。

好了就说这么多吧,希望对你们有帮助。