postgreSql最佳配置詳解(connection 申請、回收策略)


一、引子

合理配置一個應用的數據庫參數,使其運行良好,這很重要。本文以某務中台的生產環境為例,從Apollo上拔下來一套配置,分析是否合理。

二、MybatisPlus配置

由於我們使用Apollo配置參數,所以分兩部分:1.個體配置 2.全局配置

2.1 mybatisplus個體配置

mybatis-plus.mapper-locations = classpath*:/mapper/*Mapper.xml  mapper文件地址匹配
mybatis-plus.type-aliases-package =xx.po 映射的實體包路徑,
mybatis-plus.tenant-config.ignoretable = table1,table2
mybatis-plus.auth-config = []
mybatis-plus.global-config.sql-parser-cache = true 緩存sql解析

2.2 mybatis-plus全局配置

mybatis-plus.mapper-locations = classpath:/mapper/*Mapper.xml  mapper文件地址匹配
mybatis-plus.configuration.map-underscore-to-camel-case = true    下划線轉駝峰
mybatis-plus.global-config.logic-delete-value = true  邏輯已刪除值
mybatis-plus.global-config.logic-not-delete-value = false  邏輯未刪除值
mybatis-plus.max-query-records-size = 10000 

三、Datasource配置

3.1 dataSource個體配置

=========數據庫配置=========
spring.datasource.connectionProperties = druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 通過connectProperties屬性來打開mergeSql功能;慢SQL記錄5秒

spring.datasource.type = com.alibaba.druid.pool.DruidDataSource 使用德魯伊連接池
spring.datasource.driver-class-name = org.postgresql.Driver 驅動類名
spring.datasource.url = xx  數據庫連接url
spring.datasource.username = ${dbUserName} 用戶名
spring.datasource.password = ${dbPassword} 密碼
spring.datasource.minIdle = 5 最小空閑連接數 5
spring.datasource.initialSize = 5 初始連接數 5
spring.datasource.maxActive = 100 最大連接數
spring.datasource.maxWait = 60000 獲取連接等待超時的時間 60s=1分鍾

spring.datasource.filters = stat,wall 監控統計攔截,用於監控界面sql統計
spring.datasource.poolPreparedStatements = false 是否啟用緩存PreparedStatements  
spring.datasource.maxPoolPreparedStatementPerConnectionSize = 20 指定每個連接上preStatement緩存數---》未生效!!!

 

=========健康檢查=========
spring.datasource.validationQuery = SELECT 1 連接池的健康檢查SQL
spring.datasource.testOnBorrow = false 申請連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能。
spring.datasource.testOnReturn = false 歸還連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能
spring.datasource.testWhileIdle = true 建議配置為true,不影響性能,並且保證安全性。申請連接的時候檢測,如果空閑時間大於timeBetweenEvictionRunsMillis,執行validationQuery檢測連接是否有效。

#每timeBetweenEvictionRunsMillis毫秒檢查一次連接池中空閑的連接,把空閑時間超過minEvictableIdleTimeMillis毫秒的連接斷開,直到連接池中的連接數到minIdle為止
spring.datasource.minEvictableIdleTimeMillis = 300000 最小可驅逐空閑時間,連接保持空閑而不被驅逐的最長時間,單位是毫秒 300s=5分鍾
spring.datasource.timeBetweenEvictionRunsMillis = 60000 間隔多久才進行一次驅逐檢測,單位是毫秒 60s=1分鍾


=========連接超時=========
# 關閉abanded連接時輸出錯誤日志,預生產/生產不建議開啟,對性能影響
spring.datasource.logAbandoned = false
# 是否清除已經超過“removeAbandonedTimout”設置的無效連接。
spring.datasource.removeAbandoned = true 
# 連接超過指定時間未關閉,就會被強行回收 180s=3分鍾
spring.datasource.removeAbandonedTimeoutMillis = 180000  

四、源碼剖析

看完配置,大家心里還是懵逼對吧,參數如何生效,druid到底如何運行?

下面,帶着問題,深入源碼,直接剖析druid如何申請連接、釋放連接、連接泄露檢查。

4.1.申請連接

最終跟進到DruidDataSource的getConnectionDirect(long maxWaitMillis),獲取得到連接后,validationQuery有效性檢查,源碼如下:

1.testOnBorrow =true,先直接校驗,執行validationQuery,失敗就關閉連接JdbcUtils.close(realConnection);

2.testWhileIdle=true,如果testOnBorrow =false, 測試空閑的連接,執行validationQuery,失敗就關閉連接JdbcUtils.close(realConnection);

3.removeAbandoned=true,如果開啟了泄露回收:把連接添加進Map<DruidPooledConnection, Object> activeConnections 。供泄露回收時使用。

分支1和2只會有一個執行。

4.2.釋放連接

德魯伊連接池在獲取連接時,會調用一次DruidDataSource的init()。方法中createAndStartDestroyThread()開啟了一個銷毀線程。

銷毀連接的線程包含了run(),如下:

在一個for空條件循環中,根據配置的timeBetweenEvictionRunsMillis連接檢測間隔時間,執行一次DestroyTask.run()就休眠一次間隔時間。未設置默認60s。(實際源碼中定義了60spublic static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = 60 * 1000L;,所以用戶未設置,默認60s,上圖中else分支sleep1秒不會執行到)

追蹤DestroyTask.run()如下:

2個步驟:

  1. shrink()收縮校驗
  2. removeAbandoned()連接泄露移除

shrink()收縮校驗

DruidDataSource內部定義了DruidConnectionHolder[] 類型的3個數組:

  • 1.connections:可用連接數組。申請連接就從這里數組隊尾拿連接。
  • 2.evictConnections:待移除連接數組。
  • 3.keepAliveConnections:待保活檢測數組。

塞進數組

shrink()中計算出需要校驗的數量checkCount,執行收縮校驗核心邏輯:

  • 校驗物理連接的超時時間phyTimoutMills:超時放入evictConnections中,等待移除。
  • 空余時間大於minEvictableIdleTimeMillis(受保最小空閑時間),並且索引(poolingCount)小於checkCount的連接則放入evictConnections;
  • 空余時間大於minEvictableIdleTimeMillis(受保最小空閑時間),並且索引大於checkCount的連接,假若空余時間大於maxEvictableIdleTimeMillis則放入evictConnections,否則放入keepAliveConnections中進行keepAlive檢測。

如下圖:

數組處理

1.evictConnections:待移除連接數組。使用JdbcUtils.close()  關閉連接。

2.keepAliveConnections:待保活檢測數組。根據配置的validationQuery查詢SQL執行連接可用性校驗。校驗通過后再put(holder)塞進connections可用連接數組。

4.3.泄露連接移除

如果開啟了removeAbandoned ,執行removeAbandoned()。移除泄露連接邏輯如下:

實際上,就是對可能的連接泄露(打開連接后長時間不關閉)兜底。

1)遍歷活躍連接Map<DruidPooledConnection, Object> activeConnections。

2)跳過運行中的連接,running定義:執行SQL前賦值true ,執行完后置false。---》問題1得到答案,不會暴力關閉執行中的連接。

3)如果當前連接已連接時間>=removeAbandonedTimeoutMillis ,直接從activeConnections map 中移除。

這里消耗性能主要兩步驟:

  • 1.內存中記錄+移除泄露連接
  • 2.打印相關日志的IO---》logAbandoned=false 可關閉寫日志

spring 的druid 連接池一般不會造成泄露。如果出現連接泄露,應該找到問題解決。---》問題2得到答案,目前關閉了寫日志,就剩下了第一點“內存占用+過濾的性能”成本,要求不高的場景可以作為兜底方案使用。如果項目已穩定,推薦關閉。

五.分析&總結

本節為我們根據:申請、釋放連接相關的參數配置,剖析策略是否合理。

5.1 配置分析

spring.datasource.testOnBorrow = false 申請連接時執行validationQuery檢測連接是否有效

spring.datasource.testOnReturn = false 歸還連接時執行validationQuery檢測連接是否有效

spring.datasource.testWhileIdle = true testOnBorrow=false時才生效,申請連接的時候檢測,如果空閑時間大於timeBetweenEvictionRunsMillis,執行validationQuery檢測連接是否有效。

spring.datasource.initialSize = 5 初始連接數 5

spring.datasource.maxActive = 100 最大連接數

spring.datasource.minIdle = 5 最小空閑連接數 5

timeBetweenEvictionRunsMillis= 60000 60s=1分鍾檢測一次

minEvictableIdleTimeMillis=300000 300s=5分鍾 最小空閑不移除時間

maxEvictableIdleTimeMillis 未設置最大空閑移除時間,默認DEFAULT_MAX_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 60L * 7 = 7小時。

keepAlive: 未設置保活開關,默認false關閉。不執行保活測試策略。

上述配置對應的策略:

1.初始策略

初始5個連接,最多可開啟100個連接。

2.申請策略

申請連接的時候檢測,如果連接空閑時間大於1分鍾(檢測間隔時間),執行validationQuery檢測連接是否有效。---》這里可確保我們空閑時間超過1分鍾的連接,校驗后使用。

3.回收策略

每一分鍾執行一次檢測,策略如下:

1.連接空閑小於5分鍾,不移除。

2.連接空閑大於5分鍾,保留”minIdle設置的5個idle連接”,可移除(總數-5)個連接。

3.連接空閑大於7小時,可移除“minIdle設置的5個idle連接”。---》因為沒有設置maxEvictableIdleTimeMillis ,默認空閑7小時后才會移除。不過一共就5個倒也沒什么事。

4.連接空閑5分鍾~7小時,由於沒開啟keepAlive保活開關,無法對“minIdle設置的5個idle連接”保活測試。-->minIdle設置的5個idle連接,這段時間一直不回收,也不做保活測試,連接是否有效無法保證。

5.2總結

1.現有項

removeAbandoned=true 開啟連接泄露檢測,要求不高的場景可以作為兜底方案使用。如果項目已穩定,推薦關閉。

2.可添加項

phyTimeoutMillis:看需要開啟。物理超時時間。不管空閑時間,超時直接移除。---》這個是終極兜底方案,可以確保超時強制移除。

maxEvictableIdleTimeMillis:建議開啟,實現精細化控制。

keepAlive: 建議開啟。可針對“minIdle設置的空閑連接”,進行保活測試,從而提升連接的質量。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM