360SDN.COM

首页/Tomcat/列表

Tomcat数据源(二)

来源:Tomcat那些事儿  2017-09-11 11:50:39    评论:0点击:

接上文

Tomcat 的数据源(一)

本文以Tomcat8.5.15的数据源源码为基础,重点分析的是相比较Tomcat7做出了哪些修订和调整。

一、异常

测试应用迁移到tomcat8后,访问抛出了异常:java.lang.AbstractMethodError: com.mysql.jdbc.Connection.isValid(I)Z。

先简单看一下这个问题:在第一次使用数据源时,数据源触发初始化。在数据源创建的过程中,Tomcat7和Tomcat8都会对连接工厂的配置进行校验:

Connection conn = null;

try {

conn = (Connection) connectionFactory.makeObject();

connectionFactory.activateObject(conn);

connectionFactory.validateConnection(conn);

connectionFactory.passivateObject(conn);

}

finally {

connectionFactory.destroyObject(conn);

}

这相当于把一个数据库连接的生命周期走一遍,确保配置无误,排除以后可能暴露的隐藏问题。在Tomcat8的校验过程中,会调用Connection的isValid方法,该方法在jdk6时引入,属于JDBC4.0的范围。而笔者之前使用的mysql jdbc驱动比较老旧,调用isValid方法时抛出运行时异常,更新为最新的mysql-connector-java-5.1.42-bin后问题解决。由此我们可以了解到,Tomcat8的默认DBCP数据源不支持低版本的数据库驱动。

二、获取连接与归还连接

Tomcat8中数据源的创建过程与Tomcat7大同小异,多了一个jmx注册的过程。实际上JMX注册在Context启动时的资源配置的过程中已经注册完成了,该步骤直接跳出。DBCP 2依赖于Commons Pool 2,对性能的提升也是依赖于Commons Pool 2 的改进,下面我们重点看下数据源连接获取和归还的过程。

看到GenericObjectPool的borrowObject方法的第一眼就发现相比较前一版本的多处同步代码块,borrowObject方法内部已经找不到synchronized同步块。其原因就是存储对象的对象池实现由原来的CursorableLinkedList更换为了LinkedBlockingDeque。因此,Tomcat7中通过同步方法allocate进行空闲池与请求队列的“碰撞”转换为了Tomcat8中对线程安全的LinkedBlockingDeque的依赖,这里顺便说一句LinkedBlockingDeque是使用了重入锁来保证线程安全。归还连接的returnObject方法也相似。

三、性能测试

按上面分析看,DBCP2好像也没有做出大幅提高性能的架构改进,那么编写一个小程序测试下性能吧,主要代码如下:

private long doTest(DataSource ds) throws Exception{

        CyclicBarrier barrier=new CyclicBarrier(THREAD_NUM+1);

        for(int i=0;i<THREAD_NUM;i++){

            new Thread(new DataSourceTestThread(barrier,ds)).start();

        }

        barrier.await();

        long start=System.currentTimeMillis();

        System.out.println("start test");

        barrier.await();

        long end=System.currentTimeMillis();

        System.out.println("end test,cost:"+(end-start));

        return end-start;

    }

    private class DataSourceTestThread implements Runnable{

        ......

        @Override

        public void run() {

            try {

                barrier.await();

                for(int i=0;i<GET_PER_THREAD;i++){

                    Connection conn=dataSource.getConnection();

                    PreparedStatement statement=conn.prepareStatement("select 1");

                    statement.execute();

                    statement.close();

                    conn.close();

                }

                barrier.await();

            } catch (Exception e) {

                e.printStackTrace();

            }

        }

    }

代码写的比较简陋,如没有将close方法放到finally中,测试中Tomcat7与Tomcat8配置相同:连接池配置为最大连接数100,最大空闲数为-1不限制,其他默认;测试程序的并发线程数为64,单线程循环次数为10000次,mysql在本机,Windows系统,机器为i7 5500U。相关配置片段如下:

<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"

maxActive="100"  (tomcat8此处为maxTotal) maxIdle="-1" maxWaitMillis="10000" username="root" password="root"  riverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/test?useSSL=true"/>

测试结果为:


耗时

Tomcat7

30s

Tomcat8

56s

WTF?说好的更高性能呢?通过jstack分析,发现有部分线程在执行连接的isValid方法,也就是本文开篇遇到的相似的问题。追踪此堆栈发现,Tomcat8竟然是默认配置testOnBorrow为true的,这样每次获取连接时都会执行isValid方法,性能高才怪啊。添加testOnBorrow="false"属性,重新测试,发现Tomcat8耗时在30s左右。

那么,是否就可以认为在当前环境下Tomcat7与Tomcat8的数据源实现性能相当呢?其实笔者在这里埋了一个坑,我们在做性能对比的时候,通常会采用控制变量法,如本次测试中可以认为数据源实现是唯一变量。此时,我们需要尽量排除外部环境带来的干扰。

测试代码中执行了select 1的数据库查询,一方面mysql会与Tomcat争夺系统资源(mysql不在本机时,若性能瓶颈在mysql同样会导致测试结果不正确),另一方面数据库查询的耗时会掩盖真正的测试结果。我们把Statement执行相关的代码注释掉,重新测试,结果为Tomcat8(耗时0.8s)领先Tomcat7(耗时1.5s)约90%;修改为最大连接数为线程数一半(32)时,Tomcat8(耗时0.8s)领先Tomcat7(耗时3s)约250%。

四、总结一下

我们使用了一大半篇幅进行了性能对比测试,讲了对比测试中的注意点。DBCP2.X通过引入concurrent包擦除了大面积的synchronize的使用,从而使代码性能得到了大幅提高,无锁化编程或者将锁的粒度切到最小使我们编写高性能程序的目标。

☆★☆更多精彩内容☆★☆


一台机器上安装多个Tomcat 的原理(回复001)

监控Tomcat中的各种数据 (回复002)

启动Tomcat的安全机制(回复003)

乱码问题的原理及解决方式(回复007)

Tomcat 日志工作原理及配置(回复011)

web.xml 解析实现(回复 012)

线程池的原理( 回复 014)

Tomcat 的集群搭建原理与实现 (回复 015)

类加载器的原理 (回复 016)

类找不到等问题 (回复 017)

代码的热替换实现(回复 018)

Tomcat 进程自动退出问题 (回复 019)

为什么总是返回404? (回复 020)

...


               iOS赞赏通道



PS: 对于一些 Tomcat常见问题,在公众号的【常见问题】菜单中,有需要的朋友欢迎关注查看。

觉得本文对你有帮助?请分享给更多人支持一下吧,谢谢

关注『 Tomcat那些事儿  』 ,发现更多精彩文章!了解各种常见问题背后的原理与答案。深入源码,分析细节,内容原创,欢迎关注。

阅读原文

为您推荐

友情链接 |九搜汽车网 |手机ok生活信息网|ok生活信息网|ok微生活
 Powered by www.360SDN.COM   京ICP备11022651号-4 © 2012-2016 版权