數(shù)據(jù)源連接池?cái)?shù)配置對執(zhí)行sql的影響

1 背景

? ? ? ? 目前java應(yīng)用很少使用jdbc直接連接數(shù)據(jù)庫執(zhí)行sql了,且數(shù)據(jù)庫連接是創(chuàng)建讳苦、關(guān)閉比較耗時(shí)的資源带膜,池技術(shù)的引用數(shù)據(jù)源中是不可避免的。

使用數(shù)據(jù)庫連接池會提高應(yīng)用的性能鸳谜,但是如果配置失誤的話反而會適得其反膝藕,甚至引起應(yīng)用的宕機(jī)。

? ? ? ?前些日子發(fā)現(xiàn)有些明明很簡單的sql咐扭,很簡單芭挽,單次執(zhí)行很快滑废,但是有些時(shí)候執(zhí)行時(shí)間卻是數(shù)倍的變化。

2 設(shè)定與準(zhǔn)備

? ?設(shè)立單獨(dú)的測試數(shù)據(jù)庫袜爪,使用公司云主機(jī)

? ?一條sql蠕趁,執(zhí)行時(shí)間是68ms左右

? ?使用druid連接池進(jìn)行測試,配置:初始連接數(shù)辛馆、最小連接數(shù)妻导、最大連接數(shù)

? ?使用newFixedThreadPool連接池模擬并發(fā)情況

? ?監(jiān)控指標(biāo):連接池活動的連接、空閑的連接怀各,獲取連接的時(shí)間倔韭、sql執(zhí)行時(shí)間、執(zhí)行總時(shí)間瓢对,線程等待數(shù)據(jù)源等待的線程(ps:獲取改數(shù)量或影響連接池的性能寿酌,這里暫不考慮)

3 程序結(jié)果與解讀

程序:

```

public class ConnectTest {

public static ThreadLocal timelocal =new ThreadLocal<>();

? ? @Test

public void test_druidConnectPool()throws SQLException {

final MyDruidDataSource dataSource =new MyDruidDataSource();

? ? ? ? Properties dbProperties =new Properties();

? ? ? ? dbProperties.put("druid.initialSize", "3");

? ? ? ? dbProperties.put("druid.minIdle", "3");

? ? ? ? dbProperties.put("druid.maxActive", "15");

? ? ? ? dbProperties.put("druid.maxWait", "5000");

? ? ? ? dbProperties.put("druid.timeBetweenEvictionRunsMillis", "90000");

? ? ? ? dbProperties.put("druid.minEvictableIdleTimeMillis", "1800000");

? ? ? ? dbProperties.put("druid.testOnBorrow", "false");

? ? ? ? dbProperties.put("druid.testOnReturn", "false");

? ? ? ? dbProperties.put("druid.testWhileIdle", "true");

? ? ? ? dbProperties.put("druid.name", "true");

? ? ? ? dbProperties.put("druid.url", "jdbc:mysql:///sieve?zeroDateTimeBehavior=convertToNull");

? ? ? ? dbProperties.put("druid.username", "");

? ? ? ? dbProperties.put("druid.password", "");

? ? ? ? dbProperties.put("druid.driverClassName", "com.mysql.jdbc.Driver");

? ? ? ? dataSource.setConnectProperties(dbProperties);

? ? ? ? try {

dataSource.init();

? ? ? ? }catch (SQLException e) {

e.printStackTrace();

? ? ? ? }

// 監(jiān)控線程

? ? ? ? ScheduledExecutorService cron= Executors.newScheduledThreadPool(1);

? ? ? ? cron.scheduleAtFixedRate(new Runnable(){

@Override

public void run() {

System.out.println(dataSource);

//? ? ? ? ? ? ? ? System.out.println(dataSource.getWaitThreadCount());

? ? ? ? ? ? }

},0,500, TimeUnit.MILLISECONDS);

//? ? ? ? // 增加鏈接線程

//? ? ? ? ScheduledExecutorService cron1= Executors.newScheduledThreadPool(1);

//? ? ? ? cron1.scheduleAtFixedRate(new Runnable(){

//

//? ? ? ? ? ? @Override

//? ? ? ? ? ? public void run() {

//? ? ? ? ? ? ? ? System.out.println(dataSource);

//? ? ? ? ? ? ? ? int i = dataSource.getMaxActive();

//? ? ? ? ? ? ? ? dataSource.setMaxActive(i+1);

//? ? ? ? ? ? }

//? ? ? ? },0,1500, TimeUnit.MILLISECONDS);

? ? ? ? int count =10000;

? ? ? ? final CountDownLatch latch =new CountDownLatch(count);

? ? ? ? ExecutorService executorService =? Executors.newFixedThreadPool(15);

? ? ? ? for (int i =0; i < count; i++) {

final int index = i;

? ? ? ? ? ? executorService.submit(new Runnable() {

@Override

public void run() {

try {

ConnectTest.ExceTime time =new ConnectTest.ExceTime();

? ? ? ? ? ? ? ? ? ? ? ? timelocal.set(time);

? ? ? ? ? ? ? ? ? ? ? ? time.setIndex(index);

//? ? ? ? ? ? ? ? ? ? ? exceSqlQuery(dataSource, "SELECT * FROM sieve.po_detail limit 1;");

? ? ? ? ? ? ? ? ? ? ? ? exceSqlUpdate(dataSource, "");

? ? ? ? ? ? ? ? ? ? }catch (Throwable e) {

e.printStackTrace();

? ? ? ? ? ? ? ? ? ? }

latch.countDown();

? ? ? ? ? ? ? ? }

});

? ? ? ? }

try {

latch.await();

? ? ? ? }catch (InterruptedException e) {

e.printStackTrace();

? ? ? ? }

try {

Thread.sleep(5000);

? ? ? ? }catch (InterruptedException e) {

e.printStackTrace();

? ? ? ? }

}

public void exceSqlUpdate(MyDruidDataSource dataSource, String sql) {

Connection con =null;

? ? ? ? PreparedStatement ps =null;

? ? ? ? try {

con = dataSource.getConnection(timelocal);

? ? ? ? ? ? ps = con.prepareStatement(sql);

? ? ? ? ? ? timelocal.get().setStartSqlTime(new java.util.Date().getTime());

? ? ? ? ? ? ps.execute(sql);

? ? ? ? ? ? timelocal.get().setEndSqlTime(new java.util.Date().getTime());

? ? ? ? }catch (Exception e) {

e.printStackTrace();

? ? ? ? }finally {

if (ps !=null) {

try {

ps.close();

? ? ? ? ? ? ? ? }catch (SQLException e) {

e.printStackTrace();

? ? ? ? ? ? ? ? }

}

if (con !=null) {

try {

con.close();

? ? ? ? ? ? ? ? }catch (SQLException e) {

e.printStackTrace();

? ? ? ? ? ? ? ? }

}

}

timelocal.get().calculationTime();

? ? ? ? timelocal.remove();

? ? }

static class ExceTime {

private int index;

? ? ? ? private long getConTime;

? ? ? ? private long startSqlTime;

? ? ? ? private long endSqlTime;

? ? ? ? public int getIndex() {

return index;

? ? ? ? }

public void setIndex(int index) {

this.index = index;

? ? ? ? }

public long getGetConTime() {

return getConTime;

? ? ? ? }

public void setGetConTime(long getConTime) {

this.getConTime = getConTime;

? ? ? ? }

public long getStartSqlTime() {

return startSqlTime;

? ? ? ? }

public void setStartSqlTime(long startSqlTime) {

this.startSqlTime = startSqlTime;

? ? ? ? }

public long getEndSqlTime() {

return endSqlTime;

? ? ? ? }

public void setEndSqlTime(long endSqlTime) {

this.endSqlTime = endSqlTime;

? ? ? ? }

public void calculationTime(){

System.out.println("編號:"+index+",獲取con與開始sql距離:" + (startSqlTime - getConTime) +", sql執(zhí)行時(shí)間:" + (endSqlTime - startSqlTime)

+",總時(shí)間:"+(endSqlTime - getConTime));

? ? ? ? }

}

public void exceSqlQuery(MyDruidDataSource dataSource, String sql) {

Connection con =null;

? ? ? ? PreparedStatement ps =null;

? ? ? ? try {

con = dataSource.getConnection();

? ? ? ? ? ? ps = con.prepareStatement(sql);

? ? ? ? ? ? ResultSet resultSet = ps.executeQuery(sql);

? ? ? ? ? ? analysisResultSet(resultSet);

? ? ? ? }catch (Exception e) {

e.printStackTrace();

? ? ? ? }finally {

if (ps !=null) {

try {

ps.close();

? ? ? ? ? ? ? ? }catch (SQLException e) {

e.printStackTrace();

? ? ? ? ? ? ? ? }

}

if (con !=null) {

try {

con.close();

? ? ? ? ? ? ? ? }catch (SQLException e) {

e.printStackTrace();

? ? ? ? ? ? ? ? }

}

}

}

private void analysisResultSet(ResultSet resultSet)throws SQLException {

List> objectList =new ArrayList<>();

? ? ? ? //獲得ResultSetMeataData對象

? ? ? ? ResultSetMetaData rsmd =null;

? ? ? ? rsmd = resultSet.getMetaData();

? ? ? ? int total_rows = rsmd.getColumnCount();

? ? ? ? while (resultSet.next()) {

List list =new ArrayList<>();

? ? ? ? ? ? //判斷數(shù)據(jù)類型&獲取value

? ? ? ? ? ? for (int i =0; i < total_rows; i++) {

String columnName = rsmd.getColumnLabel(i +1);

? ? ? ? ? ? ? ? try {

list.add(resultSet.getObject(columnName));

? ? ? ? ? ? ? ? }catch (Exception e) {

e.printStackTrace();

? ? ? ? ? ? ? ? }

}

objectList.add(list);

? ? ? ? }

System.out.println(Arrays.deepToString(objectList.toArray()));

? ? }

}

```

```

public class MyDruidDataSourceextends DruidDataSource {

public DruidPooledConnection getConnection(ThreadLocal local)throws SQLException {

local.get().setGetConTime(new Date().getTime());

? ? ? ? DruidPooledConnection connection =super.getConnection();

? ? ? ? return connection;

? ? }

}

```

a:

配置

初始連接數(shù)=3、最小連接數(shù)=3硕蛹、最大連接數(shù)=15 ? 并發(fā)線程=15 任務(wù)量=10000

結(jié)果

?????????????執(zhí)行總時(shí)間:4分10s ?

? ? ? ? ? ? 獲取連接平均時(shí)間:300ms左右醇疼,有少量600ms+ ??

????????????機(jī)器性能:cpu使用增加1%- 2% ?負(fù)載略有增加

總結(jié)

并發(fā)15對于連接池是3來說,是有一定獲取壓力的法焰,獲取對執(zhí)行sql有一定影響秧荆,時(shí)間影響為4倍

附件



b:

配置

初始連接數(shù)=3、最小連接數(shù)=3埃仪、最大連接數(shù)=3 ? 并發(fā)線程=50 任務(wù)量=10000

結(jié)果

執(zhí)行總時(shí)間:4分10s ?

獲取連接平均時(shí)間:1s+,有少量2s+乙濒,峰值5s+

機(jī)器性能:cpu使用增加1%- 2% ?負(fù)載略有增加,與a持平

總結(jié)

并發(fā)量50對于連接池?cái)?shù)量為3來說卵蛉,壓力巨大颁股,獲取對執(zhí)行sql有巨大壓力,時(shí)間影響為10+倍

附件


c:

配置

初始連接數(shù)=3傻丝、最小連接數(shù)=3甘有、最大連接數(shù)=15 ? 并發(fā)線程=15 任務(wù)量=10000

結(jié)果

執(zhí)行總時(shí)間:1分2s ?

獲取連接平均時(shí)間:1ms,在開始500次執(zhí)行的過程中有少量200ms葡缰,當(dāng)連接數(shù)=并發(fā)數(shù)時(shí)=15時(shí)亏掀,獲取連接不需要耗費(fèi)時(shí)間。

機(jī)器性能:cpu使用增加4.7%-5.3%泛释,負(fù)載略有增加滤愕,與a相比增加5倍cpu使用率。

總結(jié)

連接池的連接動態(tài)增加會影響sql的執(zhí)行總時(shí)間胁澳,推薦:初始數(shù)=最小數(shù)=最大連接數(shù)该互。

當(dāng)連接數(shù)=并發(fā)數(shù)時(shí)=15時(shí),獲取連接不需要耗費(fèi)時(shí)間韭畸。

當(dāng)連接數(shù)增加時(shí)宇智,意味著數(shù)據(jù)庫會執(zhí)行更多的任務(wù)蔓搞,cpu使用率、負(fù)載都會升高随橘。

附件


4 總結(jié)

?可以看到喂分,數(shù)據(jù)庫連接池的設(shè)置會sql的執(zhí)行、數(shù)據(jù)庫的性能都是有很到影響的机蔗,過小會增加獲取連接的開銷蒲祈、過大會影響數(shù)據(jù)庫的cpu使用率。

當(dāng)然影響數(shù)據(jù)庫性能的因素還有很多萝嘁,流量也是一個很重要的方便梆掸,過大的流量也會使db宕機(jī),連接池也是對sql流量的一種限流措施牙言。qps與db性能要綜合考慮酸钦。

如果流量不大的話,并發(fā)=連接數(shù)可以達(dá)到qps的最大咱枉。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末卑硫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蚕断,更是在濱河造成了極大的恐慌欢伏,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亿乳,死亡現(xiàn)場離奇詭異硝拧,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)风皿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門河爹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人桐款,你說我怎么就攤上這事∫幕校” “怎么了魔眨?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長酿雪。 經(jīng)常有香客問我遏暴,道長,這世上最難降的妖魔是什么指黎? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任朋凉,我火速辦了婚禮,結(jié)果婚禮上醋安,老公的妹妹穿的比我還像新娘杂彭。我一直安慰自己墓毒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布亲怠。 她就那樣靜靜地躺著所计,像睡著了一般。 火紅的嫁衣襯著肌膚如雪团秽。 梳的紋絲不亂的頭發(fā)上主胧,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機(jī)與錄音习勤,去河邊找鬼踪栋。 笑死,一個胖子當(dāng)著我的面吹牛图毕,可吹牛的內(nèi)容都是我干的夷都。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼吴旋,長吁一口氣:“原來是場噩夢啊……” “哼损肛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起荣瑟,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤治拿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后笆焰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體劫谅,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年嚷掠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了捏检。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡不皆,死狀恐怖贯城,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情霹娄,我是刑警寧澤能犯,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站犬耻,受9級特大地震影響踩晶,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜枕磁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一渡蜻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦茸苇、人聲如沸排苍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纪岁。三九已至,卻和暖如春则果,著一層夾襖步出監(jiān)牢的瞬間幔翰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工西壮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留遗增,地道東北人。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓款青,卻偏偏與公主長得像做修,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子抡草,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法饰及,類相關(guān)的語法,內(nèi)部類的語法康震,繼承相關(guān)的語法燎含,異常的語法,線程的語...
    子非魚_t_閱讀 31,623評論 18 399
  • 本文包括傳統(tǒng)JDBC的缺點(diǎn)連接池原理自定義連接池開源數(shù)據(jù)庫連接池DBCP連接池C3P0連接池Tomcat內(nèi)置連接池...
    廖少少閱讀 16,741評論 0 37
  • 一腿短、事務(wù) 事務(wù)就是一個事情屏箍,組成這個事情可能有多個單元,要求這些單元橘忱,要么全都成功赴魁,要么全都不成功。在開發(fā)中钝诚,有事...
    野狗子嗷嗷嗷閱讀 2,805評論 0 6
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 3,810評論 0 11
  • 新婚夜被渣皇帝放鴿子,堂堂嫡女還被路邊撿來的小養(yǎng)女逆襲成為女主祈噪,一介皇后還被冷宮虐待最后上吊致死…… 冷眼睥睨,看...
    酷聽聽書閱讀 138評論 0 0