Nacos 3.1.0适配国产数据库实战:达梦、金仓与openGauss迁移全指南
2026/9/18 16:35:12 网站建设 项目流程

前段时间做信创适配,手头有个微服务项目要从MySQL整体迁到国产关系型数据库,注册中心和配置中心用的是Nacos。一开始以为把连接串改一改就能跑,结果真动起手来才发现,Nacos从2.x到3.x变化不小,3.1.0适配国产数据库这件事,远不是换个驱动那么简单。

这篇文章就围绕Nacos 3.1.0适配国产数据库这件事,把我在实际项目中踩过的坑、验证过的方案、改过的配置、编译过的插件,完整梳理一遍。整个过程以达梦、人大金仓、openGauss三个国产关系型数据库为主要适配目标,顺带聊聊TiDB、OceanBase这类兼容MySQL协议的数据库怎么做。如果你是做基础软件国产化替换、微服务架构改造的,尤其是负责注册中心、配置中心迁移的,这篇文章应该能帮你省不少时间。

1. 项目背景与整体适配思路

1.1 为什么3.1.0这个版本值得单独适配

先说个容易忽视的点:Nacos 3.1.0和2.x在存储层上的差异非常大。很多人以为Nacos只是个配置中心,底层数据库无非是存几行配置、服务实例注册信息,随便换个库都行。但Nacos 3.x引入了更完善的控制台、更复杂的元数据管理、新的服务发现模型,表结构、SQL语句、事务处理方式都和2.x不一样了。

我在适配时翻了3.1.0的源码,发现它默认的数据库脚本、Mapper XML里的SQL方言、分页写法等,很多地方是面向MySQL写的。比如配置发布时的历史版本记录、灰度配置的存储、服务实例的心跳续约数据,这些操作在3.x里更频繁,对数据库的事务隔离级别、自增主键处理、SQL语法兼容性要求也更高。

所以做3.1.0的国产数据库适配,不只是把驱动JAR换掉、把URL改一下,而是要解决三类问题:

  • 驱动层兼容:国产数据库的JDBC驱动类名、URL格式、连接参数和MySQL不同。
  • SQL方言兼容:Nacos内置的SQL语句在MySQL下没问题,但换到达梦、金仓这类不完全兼容MySQL语法的数据库上就会报错。
  • 构建与插件机制适配:Nacos从2.2之后支持数据源插件扩展,适配国产数据库需要利用或扩展这个插件机制。

1.2 适配方案选型:协议兼容与源码改造两条路

关于适配方案,我当时列了三个选项,挨个分析后选了第二个。这三条路分别是:

第一,直接用MySQL协议兼容的数据库。像TiDB、OceanBase这类数据库,因为兼容MySQL协议,Nacos基本不用改,驱动用MySQL的,连接串改一改就能跑。这个方案成本最低,但如果项目要求必须用达梦、金仓这类自研数据库,就走不通。

第二,基于Nacos的数据源插件机制,自定义实现国产数据库的方言适配。Nacos本身提供了一组SPI接口,比如DataSourcePlugin,允许接入自定义数据源。在这条路里,需要自己编译插件、打包驱动、改配置。代价是工作量大一些,但适配完之后不依赖MySQL协议,是真真正正接入了国产库。

第三,直接改Nacos源码,把内置SQL全部改成目标数据库方言。这个方案最彻底,但维护成本极高,Nacos每次升级都要重新合并代码,不建议采用。

我实际采用的是第二条,同时结合第一条的思路,用MySQL协议的库先跑通功能,再逐步切换到达梦、金仓上做完整验证。这篇文章后面讲的内容,主要也是围绕这个方案展开的。

2. 适配前的环境准备与依赖替换

2.1 版本清单与环境确认

动手之前,先把版本对齐这件事做好。我在项目里用的是一套比较新的组合,建议你也按这个思路去确认自己的版本,不要想当然。

我本机环境是这样的:

  • Nacos版本:3.1.0(源码包和发行包我都用到了,编译插件用源码,部署用发行包)
  • JDK版本:17(Nacos 3.x要求JDK 8以上,但官方实际上推荐JDK 17,控制台编译、插件编译都更稳)
  • Maven版本:3.8+
  • 目标数据库:达梦8(试用版)、人大金仓V8R6、openGauss 5.0,后面还用了TiDB 6.5做对照
  • Nacos部署方式:单机模式先验证,后续再上集群

这里特别提醒一下,Nacos 3.x的默认鉴权、控制台登录这些功能,适配数据库时不要关闭。有些文档让你先把鉴权关掉方便调试,但3.x下某些操作在鉴权关闭时可能走不同的逻辑分支,反而掩盖了数据库兼容问题。我踩过一次,关掉鉴权后配置发布正常,一打开鉴权就报查询权限表失败,折腾了半天才发现是SQL大小写的问题。

2.2 数据库初始化:从MySQL脚本到国产库方言

Nacos发行包里自带的数据库脚本,比如mysql-schema.sql,默认放在distribution/conf目录下。这个脚本是MySQL语法写的,你不能直接拿到达梦、金仓上执行,得先做方言转换。

我第一步是建库和建用户。以达梦为例,建议创建独立用户和表空间,不要把Nacos的数据放到SYSDBA用户下。因为达梦对权限管理比较严格,Nacos连接数据库时如果使用SYSDBA,后续初始化表结构可能因为模式名不对而失败。具体操作大概是:

-- 达梦创建用户并指定表空间 CREATE TABLESPACE NACOS_TS DATAFILE 'NACOS_TS.DBF' SIZE 256; CREATE USER NACOS IDENTIFIED BY "nacos@123" DEFAULT TABLESPACE NACOS_TS; GRANT DBA TO NACOS;

这里要注意,达梦默认的DBA角色权限比较大,如果你们公司的DBA觉得风险高,可以只授予Nacos需要的增删改查、创建表、创建索引等权限,但那样需要额外排查权限点,比较费时间。我在实验环境直接用了DBA角色,生产环境建议让DBA评估最小权限。

接下来的重点是表结构脚本的转换。Nacos 3.1.0的表数量比2.x多了不少,涉及配置、服务、命名空间、用户、角色、权限、灰度、健康检查等模块。直接用工具转换的话,容易漏掉自增列、默认值、索引名这些细节。我建议用DBeaver或者DataGrip先把MySQL脚本里的ENGINE=InnoDB DEFAULT CHARSET=utf8mb4这种MySQL专属语法全局去掉,再逐段执行。

达梦方面,比较坑的一点是它对字段注释的处理。MySQL脚本里COMMENT 'xxx'写在字段定义后面,达梦8也能支持,但如果语句顺序不对,或者字段类型是LONGTEXT,达梦不认,要改成TEXTCLOB。Nacos的config_info表里content字段就是LONGTEXT,我当时改成了TEXT,实测达梦下完全够用,配置内容几MB以内的都没问题。

2.3 构建期替换:数据源插件与驱动JAR的处理

Nacos官方在设计上已经考虑到了多数据源扩展,但默认发行包只带了MySQL和Derby的插件。要接达梦、金仓这类库,需要自己构建插件并放到Nacos的plugins目录下。

我用的是源码构建方式。从GitHub拉取nacos-3.1.0源码后,在plugin/datasource目录下能看到几个子模块,其中nacos-datasource-plugin-ext就是给扩展数据源用的。我的做法是这样:

# 拉取源码并切换到3.1.0标签 git clone https://github.com/alibaba/nacos.git cd nacos git checkout 3.1.0 # 进入数据源扩展插件目录 cd plugin/datasource

然后修改nacos-datasource-plugin-extpom.xml,加入对应国产数据库的JDBC驱动依赖。以达梦为例,达梦官方驱动坐标不在中央仓库,得先手动安装到本地Maven仓库:

mvn install:install-file \ -Dfile=DmJdbcDriver18.jar \ -DgroupId=com.dameng \ -DartifactId=DmJdbcDriver \ -Dversion=8.1.2.192 \ -Dpackaging=jar

这里有个细节,不同达梦版本驱动包名会有差异,比如DmJdbcDriver18表示JDK1.8及以上版本编译的,如果你的Nacos跑在JDK17上,也要选对应的驱动。装完依赖后,在插件源码里新增一个数据源实现类,继承Nacos的AbstractDataSourcePlugin或者直接DataSourcePlugin接口。我当时写了一个DmDataSourcePlugin,核心就是返回达梦的DataSource,设置好驱动类、URL、用户名、密码。这个过程比想象的简单,主要工作量集中在SQL方言适配和后续的调试上。

插件构建完之后,把产物JAR和对应驱动JAR一起复制到Nacos发行包的plugins目录,修改application.properties指定数据源类型,再启动验证。这一步说起来轻松,实际操作中因为依赖冲突、SPI配置没生效导致的问题,我后面在踩坑章节会细讲。

3. 核心配置与SQL方言的适配细节

3.1 application.properties中的关键配置项

Nacos 3.1.0的数据库配置,在conf/application.properties里。默认情况下,如果你不配置数据库,Nacos会使用内嵌Derby。改成国产数据库后,核心配置项是这样的:

spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:dm://127.0.0.1:5236/NACOS?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf8 db.user.0=NACOS db.password.0=nacos@123

咦,为什么数据库是达梦,spring.datasource.platform却写的是mysql?这是一个很容易误导人的地方。

原因在于Nacos内部会按照platform的值去加载对应的SQL语句集合。Nacos源码里默认内置了mysqlderby两套SQL映射,插件机制还没有强大到把Mapper XML也完全外部化。所以我接达梦的时候,采取的思路是:数据源用达梦驱动,但SQL执行时依然走Nacos内置的MySQL方言集合。

这意味着什么呢?意味着达梦数据库要开启MySQL兼容模式,或者在SQL层面尽量兼容MySQL语法。达梦8在这方面做得还可以,特别是COMPATIBLE_MODE=MYSQL这个参数,建议在达梦的dm.ini里把兼容模式打开。不然的话,Nacos的Mapper XML里大量使用的LIMIT分页语法、反引号包裹的表名字段名、NOW()函数,达梦都会识别不了。

如果你用的是金仓或openGauss,同样走这个思路。金仓在kingbase.conf里有一个dbcompatibility参数,可以设为MySQL;openGauss也支持SET dbcompatibility = 'B'这样的兼容性设置。但要注意,即使开了兼容模式,某些查询仍然可能出现问题,这个我下面会重点讲。

3.2 达梦、金仓、openGauss的驱动差异对照

我把三个数据库的驱动信息整理成了一个对照表,方便你直接抄:

数据库JDBC驱动类URL格式默认端口注意事项
达梦8dm.jdbc.driver.DmDriverjdbc:dm://127.0.0.1:5236/NACOS5236需要开启MySQL兼容模式;驱动注意JDK版本
人大金仓V8R6com.kingbase8.Driverjdbc:kingbase8://127.0.0.1:54321/nacos54321基于PostgreSQL内核,部分PG函数可用
openGauss 5.0org.opengauss.Driverjdbc:opengauss://127.0.0.1:5432/nacos5432也是PG内核,但驱动需要下载对应版本
TiDB 6.5com.mysql.cj.jdbc.Driverjdbc:mysql://127.0.0.1:4000/nacos4000完全兼容MySQL协议,适配成本最低
OceanBase 4.xcom.mysql.cj.jdbc.Driverjdbc:mysql://127.0.0.1:2883/nacos2883MySQL模式基本兼容,需注意OB的分布式事务限制

驱动这一层,最容易踩的坑是版本不匹配。比如达梦驱动有DmJdbcDriver16DmJdbcDriver17DmJdbcDriver18的区别,对应不同JDK版本。金仓的驱动包版本如果和数据库服务端版本不一致,可能能连上,但执行复杂SQL时会出现奇怪的报错,比如ERROR: invalid input syntax for type oid

openGauss这边,由于Nacos 3.1.0运行在JDK17上,而openGauss官方驱动下载页提供的JDBC包有时候是JDK8编译的,理论上JDK17能跑,但如果你遇到IllegalAccessError,就要检查是不是驱动和JDK版本兼容性问题。

3.3 SQL方言兼容:分页、自增主键、保留字

这一节是全文核心中的核心,因为驱动和连接只是入场券,真正让Nacos跑起来的是那一堆SQL语句。我在适配过程中发现,Nacos 3.1.0内置SQL在国产数据库上主要暴露在三类问题上。

第一类是分页语法。Nacos有很多查询列表的SQL,比如配置列表、服务列表、历史版本列表,全部用了MySQL的LIMIT offset, size写法。达梦在非兼容模式下,分页要写成LIMIT size OFFSET offset,或者用TOP加嵌套查询。金仓呢,因为内核是PostgreSQL,如果设置了dbcompatibility=MySQLLIMIT offset, size这个写法能识别,但openGauss不一定,有时候必须写成LIMIT size OFFSET offset。所以我在验证时,专门把Nacos源码中所有的LIMIT ? , ?找出来,逐个在目标数据库里执行测试,确保数据库能接受这种写法。

第二类是自增主键。Nacos 3.x的表,比如config_info的主键id,用的是BIGINT AUTO_INCREMENT。达梦的IDENTITY列和MySQL的AUTO_INCREMENT行为不完全一致。在达梦里,即使你向表中显式插入自增列的值,后续自动增长也可能不会跳到最大值+1,这会导致配置ID冲突。我当时采取的办法是:把达梦表的自增列改成IDENTITY(1,1),并且在初始化脚本里显式重建序列,Nacos插入时不指定主键ID,让数据库自己分配。

第三类是保留字和大小写问题。Nacos的SQL里大量使用反引号包裹表名、字段名,比如:

SELECT `data_id`, `group_id`, `tenant_id` FROM `config_info`

MySQL下这个写法没问题,但达梦、金仓默认会把不带引号的对象名转成大写存储,带反引号的内容又会按小写处理,两种模式混在一起就会导致表或视图不存在。解决思路是在数据库初始化阶段就把表建成小写名称,且在兼容模式下运行。如果表已经建成大写,那只能回炉重新建表。这里提醒一句:建表脚本执行前,先确认目标库的标识符大小写策略,免得做到一半推倒重来。

4. 踩坑实录与问题排查

4.1 Derby残留数据导致的启动失败

这是一个非常典型的坑。Nacos如果之前用默认配置启动过,会在用户目录下生成nacos-derby-data目录,里面是Derby的数据库文件。你切换到国产数据库后,如果配置没改干净,或者配置文件里还有一个spring.sql.init.platform之类的配置没覆盖,Nacos启动时还是会尝试初始化Derby,结果可能出现端口占用、Derby锁文件冲突、或者控制台里能看到旧数据的问题。

我排查这个问题时,看到一个现象:明明application.properties里已经配置了达梦的数据源,启动日志刚开始也显示连接了达梦,但控制台首页的旧配置还在。后来发现是用户目录下的Derby缓存没有清理,Nacos 3.1.0在启动流程里对Derby有额外的初始化动作。

解决办法很粗暴,每次切换数据库前,把nacos-derby-datanacos-derby.log这些缓存文件删干净。具体路径一般在用户目录下的nacos文件夹里。如果你用的是集群模式,还要注意每个节点的缓存都要清理,只清一台没用。

4.2 控制台中文乱码与字符集设置

配置中心存中文内容很常见,Nacos控制台展示配置时,对字符集很敏感。MySQL下默认utf8mb4就没什么问题,但到达梦上,如果表字符集是默认的GBK或者驱动连接参数没加characterEncoding=utf8,控制台会出现中文乱码,甚至保存带中文的配置时会报错。

我最终在连接串里加了一串参数才解决:

jdbc:dm://127.0.0.1:5236/NACOS?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull

这里zeroDateTimeBehavior=convertToNull也是必要的,因为Nacos里有些表的创建时间字段可能为0000-00-00 00:00:00,MySQL驱动默认会报错,达梦驱动虽然不报错,但加上这个参数可以避免一些边界情况。

另外,Nacos 3.1.0控制台本身的静态资源是UTF-8编码,但如果你给JVM传了-Dfile.encoding=GBK,日志和控制台接口返回的中文会有问题。建议启动参数里显式加上-Dfile.encoding=UTF-8

4.3 健康检查与心跳任务异常

服务注册之后,Nacos会对实例做健康检查。3.1.0的健康检查逻辑里涉及到数据库的读写操作,比如记录实例心跳时间、更新实例状态。我在达梦上遇到一个诡异的情况:服务能注册,控制台能看到实例,但过一会儿实例就被标记为不健康,日志里报数据库连接异常。

排查过程比较曲折,后来发现是达梦的连接空闲超时时间太短,Nacos的连接池里有些连接被数据库服务端断掉了,但客户端不知道,拿出来继续用就报错。解决办法是在达梦的服务端参数里把空闲连接回收时间调大,或者在连接串里开启驱动层面的自动重连。但自动重连这个功能,不同数据库驱动支持程度不一样,达梦驱动我实测是不太可靠的。所以更稳妥的办法是调大连接池的validation-query检测,并配合test-while-idle参数。

Nacos的数据源配置里,你可以在application.properties中增加:

db.pool.config.connectionTimeout=30000 db.pool.config.validationTimeout=10000

这样连接池在取连接时会先验证连接是否可用,能有效降低“连接已死但池里还在用”的概率。

4.4 常见问题速查表

我整理了一个速查表,都是我在这次适配中真实遇到或验证过的问题场景,你可以收藏一下,等真遇到的时候对照排查:

现象可能原因排查/解决思路
启动报table not found建表脚本没执行或表名大小写不一致重新执行转换后的建表脚本,确认表名小写
启动报driver not found驱动JAR没放到plugins目录,或坐标没打入插件检查plugins目录,确认插件JAR包含驱动类
控制台打开配置报SQLSyntaxErrorExceptionSQL方言不兼容,比如分页写法开启数据库MySQL兼容模式,或替换SQL为对应方言
服务注册成功但心跳失败数据库连接被服务端断开调大空闲超时,开启连接池连接检测
配置发布成功但查询列表为空事务隔离级别或配置信息读取SQL有问题查看Nacos日志的SQL执行详情,检查事务是否能正常提交
控制台登录后权限接口报错用户表、角色表数据没初始化检查usersrolespermissions三张表数据
字符集乱码表字符集或连接参数问题统一使用UTF8字符集,连接串加characterEncoding=utf8
集群模式下数据不同步插件未在集群所有节点生效集群每个节点都要放置插件和驱动,且版本保持一致

5. 回归验证与适配清单总结

5.1 功能回归测试怎么做才算合格

涉及注册中心和配置中心的迁移,回归验证不能随便点点就完事。我在完成达梦适配后,专门列了一个验证清单,覆盖Nacos 3.1.0最核心的几个使用场景:

  • 配置管理:新建配置、编辑配置、删除配置、导入导出配置、历史版本回滚、灰度配置发布。
  • 服务发现:服务注册、服务注销、临时实例心跳续约、持久实例注册、健康检查状态变化。
  • 权限控制:用户创建、角色绑定、权限配置、登录鉴权、控制台操作审计。
  • 集群一致性:多节点Nacos通过数据库共享数据,验证同一个配置在不同节点上的读取一致性。
  • 异常场景:杀掉一个Nacos节点、断掉数据库连接、重启Nacos进程后,数据能否恢复正常。

回归过程中我发现,国产数据库下最薄弱的环节是“灰度配置发布”和“配置导入导出”。灰度配置在Nacos 3.x里会操作灰度标签相关的表,表结构里有些字段长度比较长,在达梦下如果字段类型转换时没有对应好,存储时会报“字符串超出长度限制”。配置导入导出则涉及到复杂的批量SQL和临时表操作,达梦对临时表的处理方式和MySQL不同,容易在执行时报错。这两个功能一定要重点测。

5.2 这套适配方案的适用边界

很多朋友可能会问,这套适配方案能不能直接搬到生产环境?我的看法是,要看你的生产环境数据库内核是什么。

如果你的国产数据库是严格自研的,比如达梦、金仓,那么你大概率和我一样,需要走源码插件扩展这条路,并且要对Nacos内置SQL做充分的方言验证。如果你的国产数据库是开源内核衍生出来的,比如openGauss、某些基于PostgreSQL的国产化产品,那其实可以尝试用PostgreSQL方言来跑,而不是继续用MySQL兼容模式,但那样改动量会更大,因为Nacos官方没有内置PostgreSQL的Mapper XML,你需要把整套SQL都改掉,工作量不小。

我这里给一个实用建议:在选型阶段,优先和各数据库厂商的售前工程师确认他们对Nacos 3.x的支持情况。有些厂商已经提供了现成的适配包或部署方案,比自己从头搞要省力得多。比如我们后来用openGauss时,就发现社区里已经有了相关讨论和测试结果,直接站在别人的肩膀上把坑跳过去了。

5.3 插件化改造的长期维护体验

最后聊聊长期维护的问题。Nacos升级是大版本演进中绕不开的事,今天适配了3.1.0,明天出了3.2.0怎么办?

我这次的实践体会是,插件化改造本身就是为了降低升级维护成本。数据源插件、驱动JAR都放在plugins目录下,只要Nacos官方没有大幅改动数据源接口,新版本升级时大概率可以直接复用。但Nacos 3.x阶段接口还在演化,每次升级前一定要对比官方release notes里是否有数据源相关的breaking change。如果只是SQL语句层面的调整,那直接把新版发行包的conf目录覆盖,再替换插件,基本一分钟搞定。

我自己维护这个适配时会做一个小的变更记录,每次改了什么、为什么改、验证结果如何,都记下来。坚持这么做,后续排障和升级会轻松很多。

最后分享一个我实际操作中的体会:适配国产数据库这件事,真正的难点不在于驱动和配置,而在于你愿不愿意把Nacos的SQL一行一行地跑一遍、把控制台的每个功能点都点一遍。数据库兼容是个体力活,但只要环境准备充分、测试覆盖到位,3.1.0完全可以在国产关系型数据库上稳定运行。希望这篇文章能帮你少走几步弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询