Nacos启动时报错No DataSource set排查

问题描述

最近在学习Nacos组件,使用的是最新版本:2.2.3。
在本地虚拟机CentOS 8.5.2111环境中安装Nacos,并使用standalone模式启动,同时配置使用外部MySQL数据库,MySQL版本为:8.0.34。
关于数据库的配置参数如下:

spring.sql.init.platform=mysql
db.num=1
db.url.0=jdbc:mysql://192.168.2.100:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai
db.user.0=nacos
db.password.0=nacos

上述配置参数都是参考Nacos官方手册来进行的。

进入到nacos安装目录执行如下启动操作时报错了。

cd nacos/bin
sh startup.sh -m standalone

报错信息如下:

cat ../logs/start.out

2023-07-28 22:31:42,401 ERROR Application run failed

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'configOpsController' defined in URL [jar:file:/root/opt/nacos/target/nacos-server.jar!/BOOT-INF/lib/nacos-config-2.2.3.jar!/com/alibaba/nacos/config/server/controller/ConfigOpsController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'externalDumpService': Invocation of init method failed; nested exception is ErrCode:500, ErrMsg:Nacos Server did not start because dumpservice bean construction failure :
No DataSource set
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1372)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1222)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:745)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:423)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1317)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306)
	at com.alibaba.nacos.Nacos.main(Nacos.java:35)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
	at org.springframework.boot.loader.PropertiesLauncher.main(PropertiesLauncher.java:467)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'externalDumpService': Invocation of init method failed; nested exception is ErrCode:500, ErrMsg:Nacos Server did not start because dumpservice bean construction failure :
No DataSource set
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:160)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:440)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1796)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1391)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1311)
	at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
	... 27 common frames omitted
Caused by: com.alibaba.nacos.api.exception.NacosException: Nacos Server did not start because dumpservice bean construction failure :
No DataSource set
	at com.alibaba.nacos.config.server.service.dump.DumpService.dumpOperate(DumpService.java:261)
	at com.alibaba.nacos.config.server.service.dump.ExternalDumpService.init(ExternalDumpService.java:61)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389)
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333)
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157)
	... 40 common frames omitted
Caused by: java.lang.IllegalStateException: No DataSource set ## 从报错信息看似乎没有设置数据源
	at org.springframework.util.Assert.state(Assert.java:76)
	at org.springframework.jdbc.support.JdbcAccessor.obtainDataSource(JdbcAccessor.java:86)
	at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:376)
	at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:465)
	at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:475)
	at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:508)
	at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:515)
	at com.alibaba.nacos.config.server.service.repository.extrnal.ExternalConfigInfoPersistServiceImpl.findConfigMaxId(ExternalConfigInfoPersistServiceImpl.java:632)
	at com.alibaba.nacos.config.server.service.dump.processor.DumpAllProcessor.process(DumpAllProcessor.java:51)
	at com.alibaba.nacos.config.server.service.dump.DumpService.dumpConfigInfo(DumpService.java:318)
	at com.alibaba.nacos.config.server.service.dump.DumpService.dumpOperate(DumpService.java:230)
	... 48 common frames omitted

从启动日志信息看,似乎是数据源未设置,但是明明已经设置了数据源啊???另外很神奇的是偶尔有启动成功的时候!至此开始懵逼了。

逐步分析并解决

单纯从启动日志start.out的信息看,得不到任何有价值的提示,于是又转到nacos.log,所幸在这里得到了一些有价值的异常信息。

Caused by: com.mysql.cj.exceptions.UnableToConnectException: Public Key Retrieval is not allowed
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:61)
	at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:85)
	at com.mysql.cj.protocol.a.authentication.CachingSha2PasswordPlugin.nextAuthenticationStep(CachingSha2PasswordPlugin.java:130)
	... 160 common frames omitted

于是先Google一下,确实有人也碰到这个问题:Connection Java - MySQL : Public Key Retrieval is not allowed
解决办法:在JDBC连接url上设置参数allowPublicKeyRetrieval=true

进一步了解才知道参数allowPublicKeyRetrieval的具体用法,官方解释如下:

大意就是:如果MySQL账户使用的认证模式为sha256_password,则客户端与服务器端在传递信息的时候必须要保护密码,基于一些安全性的原因该参数默认值为false,但是这样就会导致MySQL客户端与服务器端无法正常建立连接。因此,在确保MySQL服务器在一个安全的网络环境下,不会遭受到中间人攻击时可以将该参数值设置为true,这样才能让客户端与服务端正常连接。

另外,从MySQL服务器这一侧来讲,默认提供了2种认证插件,即:sha256_passwordcaching_sha2_password
而且,从MySQL 8.0.34之后默认的认证插件为caching_sha2_password,这个也可以从MySQL的变量值看出来,如下:

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.34    |
+-----------+
1 row in set (0.00 sec)

mysql> select @@default_authentication_plugin;
+---------------------------------+
| @@default_authentication_plugin |
+---------------------------------+
| caching_sha2_password           |
+---------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql>

根据MySQL官方手册可以知道,认证插件caching_sha2_password的功能实际上是插件sha256_password的超集,也是使用sha256_password模式进行用户认证,所以这就跟客户端连接参数allowPublicKeyRetrieval的用法联系在了一起。

至此,问题源头得到梳理并解决!

最后总结

我看网上也有人遇到类似的问题,参考:
nacos配置mysql数据源启动出现No DataSource set的问题
nacos启动失败,No DataSource set
nacos启动报错出现no datasource set或者Access denied for user ‘root‘@‘localhost‘ (using password: YES)

虽然从nacos的报错日志来看都有一个No DataSource set的信息,但是原因却各自不同,要想找到真正的原因,需要从nacos.log文件种去寻找有明确意义的提示信息。
注意:nacos.log日志文件记录的信息会比start.out记录的信息更加详细,所以在nacos启动失败时一定要从nacos.log分析可能的原因,切记!

最后,如果无法从日志找到任何线索,就只能手动去debug源码啦,参考:IntelliJ IDEA中运行Nacos官方源码

【参考】
Connection Java - MySQL : Public Key Retrieval is not allowed
MySQL .NET Connection String Options
6.4.1.3 SHA-256 Pluggable Authentication
MySQL 8.0.34对其自带身份验证标记弃用

posted @ 2023-07-29 00:27  nuccch  阅读(10407)  评论(1编辑  收藏  举报