记一次线上问题-Druid数据源配置失败

news2025/1/16 15:39:40

一、背景是这样的

        我们的服务是spring 服务。 数据库是mysql。     

        接到公司要求, mysql数据源配置(JDBCURL地址)

jdbc:mysql://IP:PORT/dbname?Unicode=true&characterEncoding=utf8&useSSL=false

        需要添加参数 allowMultiQueries=true。

        也就是变成

jdbc:mysql://IP:PORT/dbname?Unicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true

        配置是通过Apollo来动态实现的。

二、现象是这样的

        当修改了Apollo,点击发布以后。同时监控系统进行了报警。

        提示系统就出现了大量的 503错误。

        我们有5个服务进行了修改。 有两个服务出现了问题。 3个服务是没有问题的。

三、分析问题

        1、由于有3个服务是没有问题的, 所以第一反应不是因为修改Apollo导致的。

        2、怀疑是网关出了问题 。 检查发现网关是正常的。

        3、迅速查看了出问题的服务的日志。 出现了Error级的日志。如下

log: |2024-03-07 10:13:20.552|ERROR|||[Failed to invoke config change listener com.ctrip.framework.apollo.spring.annotation.ApolloAnnotationProcessor$1]-[c.c.f.a.internals.AbstractConfig.java:445]-[Apollo-Config-4]
org.springframework.boot.context.properties.ConfigurationPropertiesBindException: Error creating bean with name 'dataSource': Could not bind properties to 'DruidDataSourceWrapper' : prefix=spring.datasource.druid, ignoreInvalidFields=false, ignoreUnknownFields=true; nested exception is org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'spring.datasource.druid' to javax.sql.DataSource
	at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.bind(ConfigurationPropertiesBindingPostProcessor.java:110)
	at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(ConfigurationPropertiesBindingPostProcessor.java:93)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:416)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1686)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:407)
	at org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder.rebind(ConfigurationPropertiesRebinder.java:102)
	at org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder.rebind(ConfigurationPropertiesRebinder.java:84)
	at org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder.onApplicationEvent(ConfigurationPropertiesRebinder.java:128)
	at org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder.onApplicationEvent(ConfigurationPropertiesRebinder.java:50)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:400)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:354)Java

看到报错否定了第一个反应, 看来是由于这个数据源配置变化导致的。继续找到如下日志

        

Caused by: java.lang.IllegalStateException: Unable to set value for property url
	at org.springframework.boot.context.properties.bind.JavaBeanBinder$BeanProperty.setValue(JavaBeanBinder.java:323)
	at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:79)
	at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:62)
	at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:54)
	at org.springframework.boot.context.properties.bind.Binder.lambda$null$5(Binder.java:341)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1359)
	at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
	at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:499)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:486)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
	at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:531)
	at org.springframework.boot.context.properties.bind.Binder.lambda$bindBean$6(Binder.java:342)
	at org.springframework.boot.context.properties.bind.Binder$Context.withIncreasedDepth(Binder.java:441)
	at org.springframework.boot.context.properties.bind.Binder$Context.withBean(Binder.java:427)
	at org.springframework.boot.context.properties.bind.Binder$Context.access$400(Binder.java:381)
	at org.springframework.boot.context.properties.bind.Binder.bindBean(Binder.java:339)
	at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:278)
	at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:221)

正是提示我们刚修改的url set 失败。

4、下面检查了一下没有出问题的项目和出问题的项目配置之间的差距,发现

出问题的配置是:spring.datasource.druid.url = jdbc:mysql://***

没问题的配置是:spring.datasource.url = jdbc:mysql://***

那么锁定问题是druid在出现Apollo配置更新的时候出现了问题。

5、下一步就是赶紧重新启动服务。保证服务正常。 后续在测试环境复现问题,查找根本原因。

四、找到问题原因

1、测试环境进行了测试,没有发现问题。认真一看发现出问题的服务在测试并没有配置成 spring.datasource.druid.url 而是 spring.datasource.url。 所以, 在测试环境没有出问题。

2、在测试环境配置成druid的方式。进行测试。果然复现了问题。

过程是这样的

首先:Apollo的配置变化的Listener接收到变化事件。触发了更新Spring容器内Bean 的操作(公司自己的starter)。

代码如下:

  @ApolloConfigChangeListener
    public void onChange(ConfigChangeEvent changeEvent) {
        Set<String> changedKeys = changeEvent.changedKeys();
        if (null != changedKeys) {
            Iterator var3 = changedKeys.iterator();

            while(var3.hasNext()) {
                String key = (String)var3.next();
                ConfigChange change = changeEvent.getChange(key);
                log.info("apollo配置变更,[{}]发生[{}]变更:[{}]==>[{}]", new Object[]{key, change.getChangeType(), change.getOldValue(), change.getNewValue()});
            }
        }

        this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
        if (null != this.refreshScope) {
            this.refreshScope.refreshAll(); 
        }

    }

然后会走到Apollo代码里面,使用反射调用对应Bean的set 方法,对Apollo 配置变化的key进行重新设置。

  ReflectionUtils.makeAccessible(method);
    String[] namespaces = annotation.value();
    String[] annotatedInterestedKeys = annotation.interestedKeys();
    Set<String> interestedKeys = annotatedInterestedKeys.length > 0 ? Sets.newHashSet(annotatedInterestedKeys) : null;
    ConfigChangeListener configChangeListener = new ConfigChangeListener() {
      @Override
      public void onChange(ConfigChangeEvent changeEvent) {
        ReflectionUtils.invokeMethod(method, bean, changeEvent); //这一行就在日志异常中能看到了,也是从这里找到的原因
      }
    };

这里的 invokeMethod 会调用对应的set 方法。 这里对应的就是 DruidAbstractDataSource类里面的setUrl

 public void setUrl(String jdbcUrl) {
        if (StringUtils.equals(this.jdbcUrl, jdbcUrl)) {
            return;
        }

        if (inited) {
            throw new UnsupportedOperationException();
        }

        if (jdbcUrl != null) {
            jdbcUrl = jdbcUrl.trim();
        }

        this.jdbcUrl = jdbcUrl;

        // if (jdbcUrl.startsWith(ConfigFilter.URL_PREFIX)) {
        // this.filters.add(new ConfigFilter());
        // }
    }

在这里我们发现了         if (inited) 这个条件, 一旦出现true , 那么就会跑出异常。 这也就是根本原因。原来 Druid 在进行数据源配置的时候会判断当前是否已经进行了初始化 。 如果已经inited,就不允许在进行重新设置。 

查看了    if (inited) 这个条件 同时出现在很多其他的地方。比如设置数据库用户名、设置密码。都存在这个限制。 

3、进一步看一下, inited 在什么时候会发生改变。

在init 的时候,设置为true 。在restart 的时候会设置为false:

public void restart() throws SQLException {
        lock.lock();
        try {
            if (activeCount > 0) {
                throw new SQLException("can not restart, activeCount not zero. " + activeCount);
            }
            if (LOG.isInfoEnabled()) {
                LOG.info("{dataSource-" + this.getID() + "} restart");
            }

            this.close();
            this.resetStat();
            this.inited = false;
            this.enable = true;
            this.closed = false;
        } finally {
            lock.unlock();
        }
    }

也就是说, 修改Apollo配置的时候,并不会restart  druid数据源。 导致设置失败。

致辞问题发现并解决,后续使用过程中需要注意。当然修改Apollo其他配置不会导致这个问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1496808.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SkyWalking 本地启动以及闪退问题

1. 下载包 Downloads | Apache SkyWalking SkyWalking APM包含OAP和UI Java Agent 就是Java 的探针 2. 运行 UI 默认端口是 8080&#xff0c; OAP 默认端口是 11800&#xff08;grpc&#xff09;12800&#xff08;http&#xff09; 如果占用可以修改配置文件 UI 项目的配…

Vue中如何处理用户权限?

在前端开发中&#xff0c;处理用户权限是非常重要的一个方面。Vue作为一种流行的前端框架&#xff0c;提供了很多便捷的方式来管理用户权限。本文将介绍一些Vue中处理用户权限的方法 1. 使用路由守卫 Vue Router提供了一个功能强大的功能&#xff0c;即导航守卫&#xff08;N…

如何使用宝塔面板搭建Discuz并结合cpolar实现远程访问本地论坛

文章目录 前言1.安装基础环境2.一键部署Discuz3.安装cpolar工具4.配置域名访问Discuz5.固定域名公网地址6.配置Discuz论坛 前言 Crossday Discuz! Board&#xff08;以下简称 Discuz!&#xff09;是一套通用的社区论坛软件系统&#xff0c;用户可以在不需要任何编程的基础上&a…

OpenAI-Sora学习手册

通过Sora看2024红利&#xff1a;文生视频&#xff0c;虽然AI不一定是风口&#xff0c;但一定是未来深入到生活工作&#xff0c;乃至思考的必备工具。 目录 Sora介绍 Sora基础介绍 Sora官方网址 Sora的价值 1.物理世界的交互 2.创意世界的绽放 3.多角色、更精准、更细节…

全志D1s开发板裸机开发之坏境搭建

环境搭建 开发板介绍 张天飞老师编写的《RISC-V体系结构编程与实践》&#xff0c;里面的源码是基于 QEMU 模拟器的&#xff0c;可以认为它是一款虚拟的开发板。如果需要在真实开发板上学习&#xff0c;可以使用百问网的 DongshanPI-D1S 开发板。 DongshanPI-D1S 是百问网推出…

大语言模型的知识融合(ICLR2024)

一、写作动机&#xff1a; 虽然从头开始训练大型语言模型&#xff08;LLMs&#xff09;可以生成具有独特功能和优势的模型&#xff0c;但这种方法成本高昂&#xff0c;而且可能导致功能冗余。 二、主要贡献&#xff1a; 入了 LLMs 知识融合的概念&#xff0c;旨在结合现有 LL…

Python基于opencv的人脸识别上课签到考勤系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

一图看懂:什么是“新质生产力”?

◆2023年9月&#xff0c;首次提出“新质生产力”。 ◆2024年1月&#xff0c;强调“加快发展新质生产力&#xff0c;扎实推进高质量发展”。 ◆2024年3月&#xff0c;《政府工作报告》中提出&#xff0c;要大力推进现代化产业体系建设&#xff0c;加快发展新质生产力。充分发挥…

黄坤朋:沉浸声系统技术方案和调试| 演讲嘉宾公布

一、3D 音频分论坛 3D 音频分论坛将于3月27日同期举办&#xff01; 3D音频技术不仅能够提供更加真实、沉浸的虚拟世界体验&#xff0c;跨越时空的限制&#xff0c;探索未知的世界。同时&#xff0c;提供更加丰富、立体的情感表达和交流方式&#xff0c;让人类能够更加深入地理解…

Xilinx 7系列 FPGA硬件知识系列(一)——FPGA选型参考

目录 1.1 Xilinx-7系列产品的工艺级别 ​编辑1.2 Xilinx-7系列产品的特点 1.2.1 Spartan-7系列 1.2.2 Artix-7系列 1.2.3 Kintex-7系列 1.2.4 Virtex-7系列 1.3 Xilinx-7系列FPGA对比 1.3.1 DSP资源柱状图 ​1.3.2 Block RAM资源柱状图 ​1.3.3 高速串行收…

【Java设计模式】八、装饰者模式

文章目录 0、背景1、装饰者模式2、案例3、使用场景4、源码中的实际应用 0、背景 有个快餐店&#xff0c;里面的快餐有炒饭FriedRice 和 炒面FriedNoodles&#xff0c;且加配菜后总价不一样&#xff0c;计算麻烦。如果单独使用继承&#xff0c;那就是&#xff1a; 类爆炸不说&a…

浅谈漏洞扫描技术

1. 什么是漏扫 漏洞扫描技术是指利用已有的漏洞数据库&#xff0c;使用扫描匹配的方式对计算机系统进行脆弱性检测&#xff0c;从而实现漏洞发现的一种安全防护手段&#xff0c;漏洞扫描的结果可以用于指导网安的管理人员及时处理系统中的漏洞&#xff0c;防患于攻击之前。 漏…

使用YOLOv7进行视频实时姿态估计

本文基于YOLOv7进行人体姿态的实时估计,并附录完整代码。 概述 YOLO(You Only Look Once)是一种用于目标检测的方法论,同时也是构建于该方法论之上的一系列模型。 自2015年YOLOv1诞生以来,其作者相继提出了YOLOv2(YOLO9000)和YOLOv3等后续版本,并在随后的几年里,深度…

【微信小程序】屏幕适配

在网页中一般是使用 rem 单位&#xff0c;它能够根据html的字号大小自动改变尺寸&#xff0c;开发者可以动态的计算屏幕尺寸&#xff0c;然后根据屏幕大小的不同设置html的字号 小程序解决适配使用 rpx 单位&#xff0c;它能够根据屏幕大小自动进行转换。 每一个机型的宽度和高…

如何制作一份精美的数据分析可视化报告?详细教程

在数据可视化分析的最后阶段&#xff0c;所有的分析、研究、推导以及得出的结论&#xff0c;都汇总成了一份详实的报告。这份报告不仅是对整个数据分析旅程的总结&#xff0c;更是向读者展示这段旅程所取得的成果。 那么&#xff0c;数据分析报告该如何制作呢&#xff1f;不用…

2024年软件设计师全套资料

2024年5月软件设计师全套视频、历年真题及解析、历年真题视频解析、教材、模拟题、重点笔记等资料 1、2023年11月、2022年、2021年全套教程精讲视频。 2、软件设计师2009-2023年5月历年真题及解析&#xff08;综合知识、案例分析&#xff09;、2009-2023历年真题视频解析。 3…

VMware永久授权终结,该如何转移阵地减少损失

2023年&#xff0c;随着VMware被博通&#xff08;Broadcom&#xff09;收购&#xff0c;VMware产品停止了永久订阅&#xff0c;仅以按年付费订阅的形式提供服务。这无疑是增加了客户在VMware的使用成本&#xff0c;也给VMware的未来带来众多不确定因素。 2024年2月Broadcom终止…

全球IT外包的趋势与发展

随着全球化进程的不断深化&#xff0c;IT外包已经成为众多企业的关键战略之一。IT外包是将企业的信息技术需求委托给第三方服务提供商&#xff0c;以在成本、效率和核心业务专注方面取得优势。在全球化的大背景下&#xff0c;IT外包的发展呈现出一系列新的趋势。 首先&#xff…

使用移动云短信服务发送普通短信与模板短信

今天使用到了用移动云短信服务发送短信功能,顺便记录下 apid,secretKey和集团名称分别为如下图用户名,密码,所属分组 package com.keyou.proj.authentication.service.utils;import cn.hutool.crypto.SecureUtil; import cn.hutool.http.HttpRequest; import cn.hutool.json.J…

有营收再分成,这样的创业你接受么?

今天收到一位客户的询盘&#xff0c;以为要部署系统结果竟然是邀请我做技术合伙人。虽然我已经从小白变成了千年狐狸&#xff0c;听到这个消息还是有点小激动。本着无功不受禄的原则先问了下客户的技术诉求&#xff1a;搭建一套外包系统论坛在线课程&#xff0c;等到有了第一笔…