加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_泰州站长网 (http://www.0523zz.com/)- 视觉智能、AI应用、CDN、行业物联网、智能数字人!
当前位置: 首页 > 站长学院 > MySql教程 > 正文

高性能数据库连接池的内幕

发布时间:2018-11-02 15:26:20 所属栏目:MySql教程 来源:Java高级架构技术
导读:副标题#e# 【新产品上线啦】51CTO播客,随时随地,碎片化学习 摘要 如何打造高性能的数据库连接池框架,可以从哪些角度进行优化,连接池的大量优化实践如何为你的系统保驾护航,本专题将带你走进连接池的世界,为你一一揭晓。 大家可能会有这样疑问:连接池

每个schema里面所有的连接会按照autocommit进行分组。 分为自动提交(autocommit=true) 和非自动提交(autocommit=false)。获取连接时优先获取相同autocommit的分组里的连接,如果没有可用连接则从另外一个分组中获取连接,业务操作执行完后,再归还到对应的分组里面。该种机制避免了开启事务多执行的两条事务语句。

锁性能优化

连接池的通用功能:

高性能数据库连接池的内幕

连接池主要包含五部分:获取连接,归还连接,定时任务,维护组件及资源池

获取连接:

1:获取超时:如果超过规定时间未获取到连接,则会抛出异常

2:有效性检查:当从资源池里面获取到资源,需要检查该资源的有效性,如果失效,再次获取连接。避免执行业务的时候报错。

3:创建连接:可以同步创建,也可以异步创建。

归还连接:

1:归还连接:比如需要检查最大空闲数,确定是物理关闭还是归还到连接池

2:销毁连接: 可同步销毁也可异步销毁

定时任务:

1:空闲检查:主要是检查空闲连接,连接空闲超过一定时间,则会关闭连接。

2:最小连接数控制:一般会设置最小连接数。保证当前系统里面最小的连接数。如果不够,则会新建连接。

组件维护:

1:连接状态控制:空闲,使用,删除等状态控制

2:异常处理:对JDBC访问的异常统一处理,如果异常与连接相关,则会将该连接销毁掉。

3:缓存:避免对SQL重复解析,PrepareStatement机制下,会对SQL解析的对象进行缓存。

4:JDBC封装:对JDBC进行了实现,真正的实现是底层的driver,比如MySQL-connector-java 。

资源池:

1:资源池是存放连接的地方,也是连接池最核心的地方。

2:所有的组件基本上都与资源池进行交互,对连接资源的竞争非常激烈。该处的性能将决定了整个连接池的性能。

3:一般资源池的实现是使用JDK提供的BlockingQueue。那么是否有方案可以进行无锁的设计,来避免竞争。

资源池无锁设计

高性能数据库连接池的内幕

获取连接大概流程:

1:从ThreadLocal里面获取连接,如果没有空闲连接,则从全局连接池(CopyOnWriteArrayList)中获取。

2:如果全局连接池中没有空闲连接,则会异步新建连接。

3:判定超时时间是否大于阈值,如果小于阈值,则进行自旋。否则进行park休眠。

4:连接建立成功后,会对park的线程进行唤醒

主要从四个方面实现了无锁的设计:ThreadLocal,CopyOnWriteArrayList,异步建立连接及自旋。

ThreadLocal

1:每个线程均有一个连接队列。该队列是全局队列的引用。

2:获取连接时先从ThreadLocal里面拿连接,如果连接是空闲状态,则使用。否则移除掉,再拿下一个,直到拿不到连接为止。

3:归还连接时,只需要归还到Threadlocal的队列里面,同时设置连接为空闲状态

4:如果使用BlockQueue,获取连接时调用poll,归还连接时调用offer,存在两次锁的竞争。优化后通过CAS避免了两次锁的开销(获取连接时,使用CAS置连接为非空闲状态;归还时,使用CAS置连接为空闲状态)

CopyOnWriteArrayList

1:该队列使用场景是:大量读,少量写的操作,并且存储的数据比较有限。而连接池的场景非常适合采用CopyOnWriteArrayList。

2:在获取连接或者归还连接时,只会通过CAS更改连接的状态,不会对连接池进行添加或者删除的操作。

3:一般连接池连接的个数比较可控,CopyOnWriteArrayList在写操作时会对所有连接进行拷贝,对内存影响不大。

异步建立连接

获取到连接后,判断一下是否有并发正在等待获取连接,如果有,则异步建立连接。避免下一个连接的等待。如果CopyOnWriteArrayList没有空闲连接,则异步建立连接。

自旋

该自旋比较类似于JDK对synchronized的自旋机制。如果发现超时时间大于设定的阈值(比如10微秒),则会进行线程挂起。如果小于设定的阈值,则重新获取连接,进行自选,避免线程的上下文切换带来的性能开销。。

优化小技巧

方法内联优化

1:每调用一次方法,线程便会新建一个栈帧,新建栈帧开销相对比较大

2:JIT在运行时会进行内联优化,多个方法使用一个栈帧,避免栈帧新建过多

3:JIT方法内联优化默认的字节码个数阈值是35个字节,低于35个字节,才会进行优化。(可通过-XX:MaxInlineSize=35进行设置)

高性能数据库连接池的内幕

通过修改上述代码,编译后字节码修改到34个字节,则可以满足内联的条件。

心跳语句选择

高性能数据库连接池的内幕

PrepareStatement模式选择

高性能数据库连接池的内幕

MySQL driver默认是client模式,如果需要开启server模式,需要设置 useServerPrepStmts=true 。PrepareStatement默认的client模式和Statement对于DB端没有区别。大家普遍理解PrepareStatement和Statement的区别是PrepareStatement可以避免SQL注入。但是避免SQL注入是如何做到的?

使用PrepareStatement设置参数的时候,比如调用setString(int parameterIndex, String x),本地会对设置的参数进行转义来避免SQL注入。

(编辑:云计算网_泰州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读