数据源10min自动断开连接导致查询抛异常(未获取可用连接)

由于个人能力有限,本文章仅仅代表本人想法,若有不对请即时指出,若有侵权,请联系本人。

1 背景

工作中引入druid来管理数据源连接,由于数据源每隔10分钟强制管理空闲超过10分钟的连接,导致每隔10分钟出现1次获取不到有效连接异常。业务请求量非常少(1h可能来一次请求)。因此,研究了一下druid源码,以及相应的解决方案。
(1)设置maxEvictableIdleTimeMillis为300000,这样5分钟之后强制剔除空闲超过5分钟的连接。
新来的请求重新建立新的连接。
优点: 适合定时任务或者请求量特别特别少的业务场景
(2)保活
keepAlive: true
keepAliveBetweenTimeMillis: 120000
优点: 持续保存有效连接,及时响应业务请求
缺点: 持有成本

2 技术实战

2.1 druid引入以及默认配置

引入maven <dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.23</version></dependency>
// spi融入到springboot框架
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfig
ure
@Configuration
@ConditionalOnProperty(name = "spring.datasource.type",havingValue = "com.alibaba.druid.pool.DruidDataSource",matchIfMissing = true)
@ConditionalOnClass(DruidDataSource.class)
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties({DruidStatProperties.class, DataSourceProperties.class})
@Import({DruidSpringAopConfiguration.class,DruidStatViewServletConfiguration.class,DruidWebStatFilterConfiguration.class,DruidFilterConfiguration.class})
public class DruidDataSourceAutoConfigure {private static final Logger LOGGER = LoggerFactory.getLogger(DruidDataSourceAutoConfigure.class);@Bean@ConditionalOnMissingBean({DruidDataSourceWrapper.class,DruidDataSource.class,DataSource.class})public DruidDataSourceWrapper dataSource() {LOGGER.info("Init DruidDataSource");return new DruidDataSourceWrapper();}
}
@ConfigurationProperties("spring.datasource.druid")
public class DruidDataSourceWrapper extends DruidDataSource implements InitializingBean {xxx
}
// 查看DruidAbstractDataSource类的属性// 默认初始化连接池=0public static final int DEFAULT_INITIAL_SIZE = 0;// 默认最大连接池=6public static final int DEFAULT_MAX_ACTIVE_SIZE = 8;// 默认最大的空闲连接池=8public static final int DEFAULT_MAX_IDLE = 8;// 默认最小的空闲连接池=0public static final int DEFAULT_MIN_IDLE = 0;// 默认最长的获取连接等待时间-1public static final int DEFAULT_MAX_WAIT = -1;// 默认validation_query=nullpublic static final String DEFAULT_VALIDATION_QUERY = null;// 默认当应用向连接池申请连接时,连接池不判断这条连接是否是可用的。public static final boolean DEFAULT_TEST_ON_BORROW = false;// 默认当一个连接使用完归还到连接池时不进行验证public static final boolean DEFAULT_TEST_ON_RETURN = false;// 默认进行空闲时检测public static final boolean DEFAULT_WHILE_IDLE = true;// 默认检查空闲连接的频率 1minpublic static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = 60 * 1000L;// 默认连接出错后重试时间间隔 0.5spublic static final long DEFAULT_TIME_BETWEEN_CONNECT_ERROR_MILLIS = 500;public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3;public static final int DEFAULT_TIME_CONNECT_TIMEOUT_MILLIS = 10_000;// 默认连接超时时间10spublic static final int DEFAULT_TIME_SOCKET_TIMEOUT_MILLIS = 10_000;// 默认剔除空闲连接最小的等待时间public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 30L;// 默认剔除空闲连接最大的等待时间public static final long DEFAULT_MAX_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 60L * 7;// 默认物理连接超时时间public static final long DEFAULT_PHY_TIMEOUT_MILLIS = -1;// 默认自动提交事务protected volatile boolean defaultAutoCommit = true;

2.2 项目初始化执行

        @Bean@ConditionalOnMissingBean({DruidDataSourceWrapper.class,DruidDataSource.class,DataSource.class})public DruidDataSourceWrapper dataSource() {LOGGER.info("Init DruidDataSource");return new DruidDataSourceWrapper();}public DruidDataSource() {this(false);// 默认非公平锁}public DruidDataSource(boolean fairLock) {super(fairLock);// 接受从系统参数传递的配置configFromPropeties(System.getProperties());}// 初始化非公平锁public DruidAbstractDataSource(boolean lockFair) {lock = new ReentrantLock(lockFair);notEmpty = lock.newCondition();empty = lock.newCondition();}
@ConfigurationProperties("spring.datasource.druid")
public class DruidDataSourceWrapper extends DruidDataSource implements InitializingBean {xxx@Overridepublic void afterPropertiesSet() throws Exception {xxxinit();//进行初始化,这时候会调用com.alibaba.druid.pool.DruidDataSource#init}xxx
}
public void init() throws SQLException {if (inited) {return;}// bug fixed for dead lock, for issue #2980DruidDriver.getInstance();final ReentrantLock lock = this.lock;try {lock.lockInterruptibly();} catch (InterruptedException e) {throw new SQLException("interrupt", e);}boolean init = false;try {if (inited) {return;}initStackTrace = Utils.toString(Thread.currentThread().getStackTrace());this.id = DruidDriver.createDataSourceId();if (this.id > 1) {long delta = (this.id - 1) * 100000;connectionIdSeedUpdater.addAndGet(this, delta);statementIdSeedUpdater.addAndGet(this, delta);resultSetIdSeedUpdater.addAndGet(this, delta);transactionIdSeedUpdater.addAndGet(this, delta);}if (this.jdbcUrl != null) {this.jdbcUrl = this.jdbcUrl.trim();initFromWrapDriverUrl();}initTimeoutsFromUrlOrProperties();for (Filter filter : filters) {filter.init(this);}if (this.dbTypeName == null || this.dbTypeName.length() == 0) {this.dbTypeName = JdbcUtils.getDbType(jdbcUrl, null);}DbType dbType = DbType.of(this.dbTypeName);if (JdbcUtils.isMysqlDbType(dbType)) {boolean cacheServerConfigurationSet = false;if (this.connectProperties.containsKey("cacheServerConfiguration")) {cacheServerConfigurationSet = true;} else if (this.jdbcUrl.indexOf("cacheServerConfiguration") != -1) {cacheServerConfigurationSet = true;}if (cacheServerConfigurationSet) {this.connectProperties.put("cacheServerConfiguration", "true");}}if (maxActive <= 0) {throw new IllegalArgumentException("illegal maxActive " + maxActive);}if (maxActive < minIdle) {throw new IllegalArgumentException("illegal maxActive " + maxActive);}if (getInitialSize() > maxActive) {throw new IllegalArgumentException("illegal initialSize " + this.initialSize + ", maxActive " + maxActive);}if (timeBetweenLogStatsMillis > 0 && useGlobalDataSourceStat) {throw new IllegalArgumentException("timeBetweenLogStatsMillis not support useGlobalDataSourceStat=true");}if (maxEvictableIdleTimeMillis < minEvictableIdleTimeMillis) {throw new SQLException("maxEvictableIdleTimeMillis must be grater than minEvictableIdleTimeMillis");}if (keepAlive && keepAliveBetweenTimeMillis <= timeBetweenEvictionRunsMillis) {throw new SQLException("keepAliveBetweenTimeMillis must be greater than timeBetweenEvictionRunsMillis");}if (this.driverClass != null) {this.driverClass = driverClass.trim();}initFromSPIServiceLoader();resolveDriver();initCheck();this.netTimeoutExecutor = new SynchronousExecutor();initExceptionSorter();initValidConnectionChecker();validationQueryCheck();if (isUseGlobalDataSourceStat()) {dataSourceStat = JdbcDataSourceStat.getGlobal();if (dataSourceStat == null) {dataSourceStat = new JdbcDataSourceStat("Global", "Global", this.dbTypeName);JdbcDataSourceStat.setGlobal(dataSourceStat);}if (dataSourceStat.getDbType() == null) {dataSourceStat.setDbType(this.dbTypeName);}} else {dataSourceStat = new JdbcDataSourceStat(this.name, this.jdbcUrl, this.dbTypeName, this.connectProperties);}dataSourceStat.setResetStatEnable(this.resetStatEnable);connections = new DruidConnectionHolder[maxActive];evictConnections = new DruidConnectionHolder[maxActive];keepAliveConnections = new DruidConnectionHolder[maxActive];nullConnections = new DruidConnectionHolder[maxActive];SQLException connectError = null;if (createScheduler != null && asyncInit) {for (int i = 0; i < initialSize; ++i) {submitCreateTask(true);}} else if (!asyncInit) {// init connectionswhile (poolingCount < initialSize) {try {PhysicalConnectionInfo pyConnectInfo = createPhysicalConnection();DruidConnectionHolder holder = new DruidConnectionHolder(this, pyConnectInfo);connections[poolingCount++] = holder;} catch (SQLException ex) {LOG.error("init datasource error, url: " + this.getUrl(), ex);if (initExceptionThrow) {connectError = ex;break;} else {Thread.sleep(3000);}}}if (poolingCount > 0) {poolingPeak = poolingCount;poolingPeakTime = System.currentTimeMillis();}}createAndLogThread();createAndStartCreatorThread();createAndStartDestroyThread();// await threads initedLatch to support dataSource restart.if (createConnectionThread != null) {createConnectionThread.getInitedLatch().await();}if (destroyConnectionThread != null) {destroyConnectionThread.getInitedLatch().await();}init = true;initedTime = new Date();registerMbean();if (connectError != null && poolingCount == 0) {throw connectError;}if (keepAlive) {if (createScheduler != null) {// async fill to minIdlefor (int i = 0; i < minIdle - initialSize; ++i) {submitCreateTask(true);}} else {empty.signal();}}} catch (SQLException e) {LOG.error("{dataSource-" + this.getID() + "} init error", e);throw e;} catch (InterruptedException e) {throw new SQLException(e.getMessage(), e);} catch (RuntimeException e) {LOG.error("{dataSource-" + this.getID() + "} init error", e);throw e;} catch (Error e) {LOG.error("{dataSource-" + this.getID() + "} init error", e);throw e;} finally {inited = true;lock.unlock();if (init && LOG.isInfoEnabled()) {String msg = "{dataSource-" + this.getID();if (this.name != null && !this.name.isEmpty()) {msg += ",";msg += this.name;}msg += "} inited";LOG.info(msg);}}}

2.3 执行回收空闲连接

public class DestroyConnectionThread extends Thread {xxxpublic void run() {initedLatch.countDown();for (; !Thread.currentThread().isInterrupted(); ) {// 从前面开始删除try { // 若closed 为true,直接break停止执行if (closed || closing) {break;}// 每隔timeBetweenEvictionRunsMillis 执行一次if (timeBetweenEvictionRunsMillis > 0) {Thread.sleep(timeBetweenEvictionRunsMillis);} else {//每隔1s执行一次Thread.sleep(1000); //}if (Thread.interrupted()) {break;}destroyTask.run();} catch (InterruptedException e) {break;}}}}public class DestroyTask implements Runnable {public DestroyTask() {}@Overridepublic void run() {// 执行回收空闲连接shrink(true, keepAlive);if (isRemoveAbandoned()) {removeAbandoned();}}}// checkTime为true, keepalive默认为falsepublic void shrink(boolean checkTime, boolean keepAlive) {if (poolingCount == 0) {return;}final Lock lock = this.lock;try {lock.lockInterruptibly();} catch (InterruptedException e) {return;}boolean needFill = false;int evictCount = 0;int keepAliveCount = 0;int fatalErrorIncrement = fatalErrorCount - fatalErrorCountLastShrink;fatalErrorCountLastShrink = fatalErrorCount;try {if (!inited) {return;}final int checkCount = poolingCount - minIdle;final long currentTimeMillis = System.currentTimeMillis();// remaining is the position of the next connection should be retained in the pool.int remaining = 0;int i = 0;for (; i < poolingCount; ++i) {DruidConnectionHolder connection = connections[i];if ((onFatalError || fatalErrorIncrement > 0) && (lastFatalErrorTimeMillis > connection.connectTimeMillis)) {keepAliveConnections[keepAliveCount++] = connection;continue;}if (checkTime) {if (phyTimeoutMillis > 0) {long phyConnectTimeMillis = currentTimeMillis - connection.connectTimeMillis;if (phyConnectTimeMillis > phyTimeoutMillis) {evictConnections[evictCount++] = connection;continue;}}long idleMillis = currentTimeMillis - connection.lastActiveTimeMillis;if (idleMillis < minEvictableIdleTimeMillis&& idleMillis < keepAliveBetweenTimeMillis) {break;}// 当空闲时间 > 最小空闲时间if (idleMillis >= minEvictableIdleTimeMillis) {if (i < checkCount) {evictConnections[evictCount++] = connection;continue;// 当空闲时间 > 最大空闲时间} else if (idleMillis > maxEvictableIdleTimeMillis) {// 放到剔除空闲连接数组中,并且剔除数量+1evictConnections[evictCount++] = connection;continue;}}// 若开启了保活,并且空闲连接 >= 保活间隔时间if (keepAlive && idleMillis >= keepAliveBetweenTimeMillis&& currentTimeMillis - connection.lastKeepTimeMillis >= keepAliveBetweenTimeMillis) {keepAliveConnections[keepAliveCount++] = connection;} else {if (i != remaining) {// move the connection to the new position for retaining it in the pool.connections[remaining] = connection;}remaining++;}} else {if (i < checkCount) {evictConnections[evictCount++] = connection;} else {break;}}}// shrink connections by HotSpot intrinsic function _arraycopy for performance optimization.int removeCount = evictCount + keepAliveCount;if (removeCount > 0) {int breakedCount = poolingCount - i;if (breakedCount > 0) {// retains the connections that start at the break position.System.arraycopy(connections, i, connections, remaining, breakedCount);remaining += breakedCount;}// clean the old references of the connections that have been moved forward to the new positions.System.arraycopy(nullConnections, 0, connections, remaining, removeCount);poolingCount -= removeCount;}keepAliveCheckCount += keepAliveCount;if (keepAlive && poolingCount + activeCount < minIdle) {needFill = true;}} finally {lock.unlock();}if (evictCount > 0) {// 遍历所有需要剔除的空闲连接数组,将连接进行释放for (int i = 0; i < evictCount; ++i) {DruidConnectionHolder item = evictConnections[i];Connection connection = item.getConnection();JdbcUtils.close(connection);destroyCountUpdater.incrementAndGet(this);}// use HotSpot intrinsic function _arraycopy for performance optimization.System.arraycopy(nullConnections, 0, evictConnections, 0, evictConnections.length);}if (keepAliveCount > 0) {// keep orderfor (int i = keepAliveCount - 1; i >= 0; --i) {DruidConnectionHolder holder = keepAliveConnections[i];Connection connection = holder.getConnection();holder.incrementKeepAliveCheckCount();boolean validate = false;try {this.validateConnection(connection);validate = true;} catch (Throwable error) {keepAliveCheckErrorLast = error;keepAliveCheckErrorCountUpdater.incrementAndGet(this);if (LOG.isDebugEnabled()) {LOG.debug("keepAliveErr", error);}}boolean discard = !validate;if (validate) {holder.lastKeepTimeMillis = System.currentTimeMillis();boolean putOk = put(holder, 0L, true);if (!putOk) {discard = true;}}if (discard) {try {connection.close();} catch (Exception error) {discardErrorLast = error;discardErrorCountUpdater.incrementAndGet(DruidDataSource.this);if (LOG.isErrorEnabled()) {LOG.error("discard connection error", error);}}if (holder.socket != null) {try {holder.socket.close();} catch (Exception error) {discardErrorLast = error;discardErrorCountUpdater.incrementAndGet(DruidDataSource.this);if (LOG.isErrorEnabled()) {LOG.error("discard connection error", error);}}}lock.lock();try {holder.discard = true;discardCount++;if (activeCount + poolingCount + createTaskCount < minIdle) {needFill = true;}} finally {lock.unlock();}}}this.getDataSourceStat().addKeepAliveCheckCount(keepAliveCount);// use HotSpot intrinsic function _arraycopy for performance optimization.System.arraycopy(nullConnections, 0, keepAliveConnections, 0, keepAliveConnections.length);}if (needFill) {lock.lock();try {int fillCount = minIdle - (activeCount + poolingCount + createTaskCount);emptySignal(fillCount);} finally {lock.unlock();}} else if (fatalErrorIncrement > 0) {lock.lock();try {emptySignal();} finally {lock.unlock();}}}

2.3 全部收回连接后接受请求重新创建连接
在这里插入图片描述
在这里插入图片描述

    @Overridepublic DruidPooledConnection getConnection() throws SQLException {return getConnection(maxWait);}

打开druid监控页面,可以观察连接池的连接数量变化。当没有请求后,再过maxEvictableIdleTimeMillis 时间,发现连接池的连接数=0
在这里插入图片描述
在这里插入图片描述

2.4 设置keepAlive=true

      keepAlive: truekeepAliveBetweenTimeMillis: 120000timeBetweenEvictionRunsMillis: 5000 #关闭空闲连接间隔   5sminEvictableIdleTimeMillis: 120000 #连接保持空闲而不被驱逐的最小时间 2分钟maxEvictableIdleTimeMillis: 420000 #连接保持空闲而不被驱逐的最大时间 5分钟
            if (keepAlive && poolingCount + activeCount < minIdle) {needFill = true; //需要重建物理连接,保持minIdle数量}

登录druid控制台http://localhost:8080/druid/index.html
可以看到连接一直保持在minIdle量
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3D打印透气钢与传统透气钢的差异

透气钢作为一种集金属强度与透气性能于一体的特殊材料&#xff0c;在注塑模具领域扮演着关键角色&#xff0c;通过有效排除模具内困气&#xff0c;显著提升制品成型质量与生产效率。当前&#xff0c;市场上主流的透气钢产品多源自日本、美国&#xff0c;其高昂成本与技术壁垒限…

Golang | Leetcode Golang题解之第388题文件的最长绝对路径

题目&#xff1a; 题解&#xff1a; func lengthLongestPath(input string) (ans int) {n : len(input)level : make([]int, n1)for i : 0; i < n; {// 检测当前文件的深度depth : 1for ; i < n && input[i] \t; i {depth}// 统计当前文件名的长度length, isFi…

生成艺术,作品鉴赏:物似主人形

2001年&#xff0c;当21岁的我&#xff0c;还在恒基伟业当高级工程师时。我有一个女同事&#xff0c;她有个特别大的杯子用来喝水&#xff0c;不夸张的说&#xff0c;是那种我从来没见过的大杯子&#xff0c;由于她是很大只的那种&#xff0c;她便自嘲说&#xff1a;「物似主人…

【Kubernetes部署篇】二进制搭建K8s高可用集群1.26.15版本(超详细,可跟做)

文章目录 一、服务器环境信息及部署规划1、K8S服务器信息及网段规划2、服务器部署架构规划3、组件版本信息4、实验架构图 二、初始化环境操作1、关闭防火墙2、配置本地域名解析3、配置服务器时间保持一致4、禁用swap交换分区(K8S强制要求禁用)5、配置主机之间无密码登录6、修改…

JVM2-JVM组成、字节码文件、类的生命周期、类加载器

Java虚拟机的组成 Java虚拟机主要分为以下几个组成部分&#xff1a; 类加载子系统&#xff1a;核心组件类加载器&#xff0c;负责将字节码文件中的内容加载到内存中运行时数据区&#xff1a;JVM管理的内存&#xff0c;创建出来的对象、类的信息等内容都会放在这块区域中执行引…

RelativeLayout相对布局

activity_relative_layout.xml <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"150dp…

QT QGraphicsView实现预览图片显示缩略图功能

QT QGraphicsView实现预览图片显示缩略图功能QT creator Qt5.15.2 头文件&#xff1a; #ifndef TGRAPHICSVIEW_H #define TGRAPHICSVIEW_H#include <QGraphicsView> #include <QMainWindow> #include <QObject> #include <QWidget>class TGraphicsVie…

Oracle 客户端 PL/SQL Developer 15.0.4 安装与使用

目录 官网下载与安装 切换中文与注册 连接Oracle数据库 tnsnames.ora 文件使用 Oracle 客户端 PL/SQL Developer 12.0.7 安装、数据导出、Oracle 执行/解释计划、for update。 官网下载与安装 1、官网&#xff1a;https://www.allroundautomations.com/products/pl-sql-d…

P01-何谓Java方法

P01-何谓Java方法 一、System.out.println()分析 二、剖析方法 谈到方法&#xff0c;我就突然想到了c函数&#xff1a; 其实&#xff1a;Java 方法和 C 函数在许多方面确实有类似之处&#xff0c;但它们也存在一些显著的差异。下面是它们的一些共同点和不同点&#xff1a; 共同…

DORIS - DORIS简介

前言 本博文基于DORIS的2.1.5版本。apache-doris-2.1.5-bin-x64.tar.gz 是什么&#xff1f; DORIS官网 Apache Doris 是一款基于 MPP 架构的高性能、实时的分析型数据库&#xff0c;以高效、简单、统一的特点被人们所熟知&#xff0c;仅需亚秒级响应时间即可返回海量数据下的…

【第0004页 · 递归】生成括号对

【前言】本文以及之后的一些题解都会陆续整理到目录中&#xff0c;若想了解全部题解整理&#xff0c;请看这里&#xff1a; 第0004页 生成括号对 今天这题有点难绷&#xff0c;从某种程度上来说应该是第二次写这个问题了&#xff0c;但还是卡住了&#xff0c;现在我们来看一下…

安防视频汇聚平台EasyCVR启动后无法访问登录页面是什么原因?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台基于云边端一体化架构&#xff0c;兼容性强、支持多协议接入&#xff0c;包括国标GB/T28181协议、部标JT808、GA/T1400协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大华SDK、华为SDK、宇视SDK、乐橙SDK、萤石云SDK等…

设计模式之适配器模式:软件世界的桥梁建筑师

一、什么是适配器模式 适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff08;Structural Pattern&#xff09;&#xff0c;通过将类的接口转换为客户期望的另一个接口&#xff0c;适配器可以让不兼容的两个类一起协同工作。其核心思想是通过一个…

SQL 语言简明入门:从历史到实践

SQL&#xff08;Structured Query Language&#xff09;是数据库领域的核心语言。自20世纪70年代中期由IBM公司开发以来&#xff0c;SQL已经成为全球最广泛使用的数据库管理语言。 本文将以简洁明了的方式为您介绍SQL的历史、基本结构、核心语言组成以及其独特的特点和书写规则…

Cookie对象的缺陷与应对策略

Cookie对象的缺陷与应对策略 1. 安全性问题&#xff1a;Cookie是明文的2. 存储限制&#xff1a;浏览器对Cookie数量和大小有限制3. 性能影响&#xff1a;Cookie携带过多增加网络流量4. 数据类型限制&#xff1a;Cookie的value值只能是字符串 &#x1f496;The Begin&#x1f4…

华为2024 届秋招招聘——硬件技术工程师-电源方向-机试题(四套)(每套四十题)

华为 2024 届秋招——硬件-电源机试题&#xff08;四套&#xff09;&#xff08;每套四十题&#xff09; 岗位——硬件技术工程师 岗位意向——电源 真题题目分享&#xff0c;完整版带答案(有答案和解析&#xff0c;答案非官方&#xff0c;未仔细校正&#xff0c;仅供参考&am…

bbr 和 inflight 守恒的收敛原理

先看 bbr&#xff0c;以 2 条流 bw 收敛为例&#xff0c;微分方程组如下&#xff1a; { d x d t C ⋅ g ⋅ x g ⋅ x y − x d y d t C ⋅ g ⋅ y g ⋅ y x − y \begin{cases} \dfrac{dx}{dt}C\cdot\dfrac{g\cdot x}{g\cdot xy}-x\\\ \dfrac{dy}{dt}C\cdot\dfrac{g\cdot y…

Python酷库之旅-第三方库Pandas(113)

目录 一、用法精讲 496、pandas.DataFrame.kurtosis方法 496-1、语法 496-2、参数 496-3、功能 496-4、返回值 496-5、说明 496-6、用法 496-6-1、数据准备 496-6-2、代码示例 496-6-3、结果输出 497、pandas.DataFrame.max方法 497-1、语法 497-2、参数 497-3、…

element的el-date-picker组件实现只显示年月日时分,不显示秒

需求&#xff1a;使用element的el-date-picker组件&#xff0c;只显示时分&#xff0c;不消失秒 效果&#xff1a; 解决方法&#xff1a; <el-date-pickerv-model"ruleForm.startTime"type"datetime"placeholder"开始时间"format"yyyy-…

分支和循环(上)

目录 1. if语句 1.1 if ​1.2 else 1.3 分支中包含多条语句 1.4 嵌套if 1.5 悬空else问题 2. 关系操作符 3. 条件操作符 4. 逻辑操作符 4.1 逻辑取反操作符 4.2 逻辑与运算符 4.3 逻辑或运算符 4.4 连续:闰年的判断 4.5 短路 5. switch语句 5.1 if语句和switch…