数据库连接池有什么用?

我们开发连接数据库的时候,经常是使用连接池,比如常见的c3p0,那么为什么要使用连接池呢,第一反应就是可以节约创建销毁socket的成本,那节约多少呢?除了这些还有什么其他的好处呢,下面自己动手做个连接实验。

客户端

一台普通Mac笔记本
JDBC-[mysql/mysql-connector-java “6.0.4”]
C3P0-[com.mchange/c3p0 “0.9.2.1”]
JDK 1.8

服务端

Centos 6.4刀片机
Mysql5.7

测试clojure脚本如下(不想看代码 可以直接忽略往下看)


(ns dbtest.core
	(:require [dbtest.dbrepo :as r]
	  )
	(:import [java.util UUID]))

(def text "XXX本来有很长的东西")

(defn lauch
	[limit is-pool]
	(dotimes [n limit]
		(if is-pool
			(try (r/insert-book-withpool (.toString (UUID/randomUUID)) (str "use-pool" n text) ))
			(try (r/insert-book (.toString (UUID/randomUUID)) (str n text) )))))

(defn go-test
	([nthread]
		(go-test nthread 10000 false))
	([nthread limit is-pool]
		(dotimes [n nthread]
			(future (lauch limit is-pool)))))

(ns dbtest.dbrepo
	(:use [dbtest.dbconf])
	(:require [clojure.java.jdbc :as j]
	  ))


(declare insert-stat)

(defn insert-book
  [name text]
  (let [s-time (System/currentTimeMillis) 
  		result (j/insert! cur-db-spec :bookinfo {:name name :text text})]
  	(insert-stat (-> result first :generated_key) s-time (- (System/currentTimeMillis) s-time))))


(defn insert-stat
	[biz-id start-time cost-time]
	(j/insert! cur-db-spec :bookstat 
		{:biz_id biz-id :start_time start-time :cost_time cost-time}))


(defn insert-book-withpool
  [name text]
  (let [s-time (System/currentTimeMillis) 
  		result (j/insert! (db-connection) :bookinfo {:name name :text text})]
  	(insert-stat (-> result first :generated_key) s-time (- (System/currentTimeMillis) s-time))))

测试逻辑如下:
首先有个目标表bookinfo,里面有两个字段,一个是32位长的字符串字段name(有唯一键约束),一个是1000位长的大字段text。
每次只做一个动作就是插入一条记录内容基本一致,但是又区分.每次插入前后记下时间戳,并计算得出此次数据插入所花时间(无事务),存入bookstat统计表中。

几个重要参数:nThread->几个线程,limit->插入多少次, is-pool->是否使用连接池
测试用例为:5,10,20,50个线程,每个线程插入200次,使用或者不使用连接池

最后得出的结果

取所有结果的平均数
不使用线程的用时(ms) 78.9(5线程) 106.8(10线程) 164.3(20线程) 310.5(50线程)
使用了线程的用时(ms) 51.9(5线程) 56.9(10线程) 67.3(20线程) 148.7(50线程)

取所有结果top100(最耗时的100)的平均数
不使用线程的用时(ms) 126.1(5线程) 228.1(10线程) 506.4(20线程) 3863.4(50线程)
使用了线程的用时(ms) 102.4(5线程) 176.6(10线程) 314.6(20线程) 903.4(50线程)

可以看出整体平均值上,使用了连接池省去了创建销毁的成本,但时间相对而言也就快了1倍,整体的吞吐量并没有我们想的那么糟糕,可是从下面top100的数据就可以看出另外一个端倪,那就是连接池的随着并发量的上升,插入更加稳定,可以想象如果一条数据插入操作的RT是4秒左右(峰值可能还要糟糕),那么整个操作响应、体验将变得很差,甚至直接调用超时了。

最后通过测试总结一下自己的感悟:任何系统的连接操作都是有上限的,当到达危险水位的时候(并发度很高、RT很大),那么对这个系统一定要做好连接的管理,如果没有就像上面不使用线程池的结果一样,甚至会引发系统瘫痪假死,导致业务全线不可用。虽然我们很多时候不用关心连接管理,都有相应连接模块处理,但是了解连接管理是一个系统的闸门这个思想,或许会在某天帮助你完成一个更健壮的架构

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>