问题描述
最近在学习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安装目录执行如下启动操作时报错了。
代码语言:javascript复制cd nacos/bin
sh startup.sh -m standalone
报错信息如下:
代码语言:javascript复制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_password
和caching_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对其自带身份验证标记弃用