数据库连接不稳定引发的事情

上段时间,遇到一个这样的问题,由于数据显示的原因,需要往Spring Boot项目中配置两个数据库连接池,一个是mysql,另外一个是amazon redshift。

情景

接着前言,当连上两个数据库后,发生一个问题,由于redshift主要定位是数据仓库,所以对于频繁的查询插入操作会比较慢,另外,由于redshift数据库连接数配置问题,会导致Druid连接被远程关闭。经常性会报500错误,实际是time_out。

其实这样原因也挺正常,remote拒绝连接,所以把我的连接关闭了。

Druid日志循环输出

由于数据库连接的关闭,Druid就循环尝试连接,当连接失败,就会循环记录error:

LOG.error("create connection OutOfMemoryError, out memory. ", e);

首先一个尝试连接的线程:

   @Override
        public void run() {
            runInternal();
        }

看runlnternal方法:

        private void runInternal() {
            for (;;) {

                // addLast
                lock.lock();
                try {
                    if (closed || closing) {
                        createTaskCount--;
                        return;
                    }

                    boolean emptyWait = true;

                    if (createError != null && poolingCount == 0) {
                        emptyWait = false;
                    }

                    if (emptyWait) {
                        // 必须存在线程等待,才创建连接
                        if (poolingCount >= notEmptyWaitThreadCount //
                                && !(keepAlive && activeCount + poolingCount < minIdle)
                                && !initTask) {
                            createTaskCount--;
                            return;
                        }

                        // 防止创建超过maxActive数量的连接
                        if (activeCount + poolingCount >= maxActive) {
                            createTaskCount--;
                            return;
                        }
                    }
                } finally {
                    lock.unlock();
                }

                PhysicalConnectionInfo physicalConnection = null;

                try {
                    physicalConnection = createPhysicalConnection();
                    setFailContinuous(false);
                } catch (OutOfMemoryError e) {
                    LOG.error("create connection OutOfMemoryError, out memory. ", e);

                    errorCount++;
                    if (errorCount > connectionErrorRetryAttempts && timeBetweenConnectErrorMillis > 0) {
                        // fail over retry attempts
                        setFailContinuous(true);
                        if (failFast) {
                            lock.lock();
                            try {
                                notEmpty.signalAll();
                            } finally {
                                lock.unlock();
                            }
                        }

                        if (breakAfterAcquireFailure) {
                            lock.lock();
                            try {
                                createTaskCount--;
                            } finally {
                                lock.unlock();
                            }
                            return;
                        }

                        this.errorCount = 0; // reset errorCount
                        if (closing || closed) {
                            createTaskCount--;
                            return;
                        }
                        createSchedulerFuture = createScheduler.schedule(this, timeBetweenConnectErrorMillis, TimeUnit.MILLISECONDS);
                        return;
                    }
                } catch (SQLException e) {
                    LOG.error("create connection SQLException, url: " + jdbcUrl, e);

                    errorCount++;
                    if (errorCount > connectionErrorRetryAttempts && timeBetweenConnectErrorMillis > 0) {
                        // fail over retry attempts
                        setFailContinuous(true);
                        if (failFast) {
                            lock.lock();
                            try {
                                notEmpty.signalAll();
                            } finally {
                                lock.unlock();
                            }
                        }

                        if (breakAfterAcquireFailure) {
                            lock.lock();
                            try {
                                createTaskCount--;
                            } finally {
                                lock.unlock();
                            }
                            return;
                        }

                        this.errorCount = 0; // reset errorCount
                        if (closing || closed) {
                            createTaskCount--;
                            return;
                        }
                        createSchedulerFuture = createScheduler.schedule(this, timeBetweenConnectErrorMillis, TimeUnit.MILLISECONDS);
                        return;
                    }
                } catch (RuntimeException e) {
                    LOG.error("create connection RuntimeException", e);
                    // unknow fatal exception
                    setFailContinuous(true);
                    continue;
                } catch (Error e) {
                    lock.lock();
                    try {
                        createTaskCount--;
                    } finally {
                        lock.unlock();
                    }
                    LOG.error("create connection Error", e);
                    // unknow fatal exception
                    setFailContinuous(true);
                    break;
                } catch (Throwable e) {
                    LOG.error("create connection unexecpted error.", e);
                    break;
                }

                if (physicalConnection == null) {
                    continue;
                }

                boolean result = put(physicalConnection);
                if (!result) {
                    JdbcUtils.close(physicalConnection.getPhysicalConnection());
                    LOG.info("put physical connection to pool failed.");
                }
                break;
            }
        }

runInternal中,可以看出,一个for的死循环,无限次尝试连接,所以失败就记录错误。
最终在console或者log文件里,将会有一大片日志。

我开始尝试寻找一个参数,能够设置尝试次数,如果超过多少次,就放弃重连,但是没有找到。。

在代码中,不过有一个这样参数:
breakAfterAcquireFailure

由名字可以知道,就是当连接失败,就不进行尝试重连,也就是这样完全放弃重试了。
该值默认是false,也就是默认尝试连接

尾声

当然最终的breakAfterAcquireFailure也无法满足我的要求,当然最终是换了另外一种思路解决这个问题,请看下一篇文章。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值