一、數據庫瓶頸解決方案
在大流量時,數據庫會成為系統瓶頸,其總體的解決方案如下:
1、項目架構使用緩存,90%請求攔截上游服務器 ———— 讀操作
2、數據歸檔處理 (把一些用戶不訪問的數據直接歸檔處理,緩解數據庫壓力)--使用master ,slave架構
3、停機擴容
影響數據庫性能因數:
1、服務器硬件
2、操作系統
3、存儲引擎
4、數據庫表結構(冗余設計)
5、SQL 語句
6、磁盤 IO
7、網卡流量
8、慢查詢
總結來看:
1、低效 SQL 語句
2、並發 cpu 的問題(SQL 並不支持多核心 cpu 並發模式執行,一個 SQL 語句只能在一個 cpu 進行執行)
3、連接數: max-connections
4、大表(數據多,字段多)
5、大事務
6、超高 cpu 使用率
其中大表、大事務、低效SQL都是屬於項目設計和開發時需要注意的,而連接數是需要進行提前設置好的。
二、連接數調優
首先從數據庫連接池選型上,目前比較主流的有HikariCP 和阿里的Druid,HikariCP讀性能很好,但是寫性能一般,阿里的Druid就比較均衡,無論讀寫都很好,因此使用了阿里的Druid。
相關的配置項如下所示,都加了注釋。
spring: application: name: sugo-seckill-web datasource: #url: jdbc:mysql://127.0.0.1:3306/shop?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true url: jdbc:mysql://172.20.10.14:3306/shop?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&connectionTimeout=3000&socketTimeout=1200 username: root password: root driver-class-name: com.mysql.jdbc.Driver druid: #初始化線程數 initial-size: 1 # 最小線程數 min-idle: 5 # 最大線程數 max-active: 10 # 獲取連接最大等待時間 max-wait: 1200 # 銷毀線程的間隔時間 time-between-eviction-runs-millis: 600000 # 配置一個連接在池中最大空閑時間,單位是毫秒 min-evictable-idle-time-millis: 300000 # 設置從連接池獲取連接時是否檢查連接有效性,true時,每次都檢查;false時,不檢查 test-on-borrow: true #設置往連接池歸還連接時是否檢查連接有效性,true時,每次都檢查;false時,不檢查 test-on-return: true # 設置從連接池獲取連接時是否檢查連接有效性,true時,如果連接空閑時間超過minEvictableIdleTimeMillis進行檢查,否則不檢查;false時,不檢查 test-while-idle: true # 檢驗連接是否有效的查詢語句。如果數據庫Driver支持ping()方法,則優先使用ping()方法進行檢查,否則使用validationQuery查詢進行檢查。(Oracle jdbc Driver目前不支持ping方法) validation-query: select 1 from dual # 是否長鏈接 keep-alive: true # 是否刪除異常連接 remove-abandoned: true # 異常連接的判斷條件(80毫秒沒有使用的連接,防止線程阻塞) remove-abandoned-timeout: 80 log-abandoned: true #打開PSCache,並且指定每個連接上PSCache的大小,Oracle等支持游標的數據庫,打開此開關,會以數量級提升性能,具體查閱PSCache相關資料 pool-prepared-statements: true max-pool-prepared-statement-per-connection-size: 20 # 配置間隔多久啟動一次DestroyThread,對連接池內的連接才進行一次檢測,單位是毫秒。 #檢測時: #1.如果連接空閑並且超過minIdle以外的連接,如果空閑時間超過minEvictableIdleTimeMillis設置的值則直接物理關閉。 #2.在minIdle以內的不處理。
三、連接池參數優化
其實數據庫連接池優化主要就是優化最大連接數、獲取連接等待時間、連接超時時間和會話超時時間四項,其他的就直接按照上述的參數配置即可,基本上不需要調整。
(一)壓測
使用jmeter進行壓測
1、創建一個線程組--數據庫連接池測試
2、添加--配置原件--JDBC Connection Configuration
需要配置連接池名字、最大連接數、最大等待時間等,還需要配置驗證sql、數據庫信息
然后還需要添加一下驅動包,在測試計划中添加jar包即可。
3、添加--取樣器--JDBC Request,需要添加連接池名字(mysql),sql語句,處理方式(這里選擇預處理),sql的參數和參數類型
4、添加--監聽器--結果樹
5、添加--監聽器--聚合報告
6、添加--監聽器--TPS
7、添加--監聽器--RT
(二)參數調整
1、max-active : 最大連接數
在數據庫連接池優化時,最重要的就是最大連接數的優化,太小太大都會影響性能,那么如何設置最大連接數,就成為優化的關鍵。
試驗: max-active = 10 , TPS 測試的結果如下所示:
試驗: max-active = 20 ,TPS 測試結果: TPS = 18000 <= max-active=10
試驗: max-active = 30 ,TPS 測試結果: TPS = 10000
結論: max-active 設置值范圍: 【10 ~ 20】
2、Max-wait
含義: 表示從連接池獲取連接的超時時間;單位是 ms ; 這個參數只管理獲取連接的超時時間。
獲取連接造成線程等待超時的原因:
(1)連接池未初始化(導致一開始獲取不到連接,導致超時)
(2)連接長時間使用,已經被釋放
(3)連接使用中,需要新建連接
(4)連接池中連接耗盡,需要等待用完后歸還;
推薦設置:內網狀態:max-wait=800 ms , 網絡狀態不是特別好,推薦設置大於等於 1200ms,因為 tcp 連接重試一般 1s;
例子:Max-wait = 0 – 無限等待,大量流量涌入后,導致線程池隊列非常長,看起來 TPS 上升了,實際上處理吞吐能力下降的;
3、連接屬性
(1)connectionTimeout : 配置建立 TCP 連接的超時時間,追加到連接后面即可;
(2)socketTimeout : 配置發送請求后,等待響應的超時時間,這里有個問題,如果建立了連接,但是在會話的時候,一直拿不到結果,那么該線程就一直阻塞,導致可用資源下降。
結論:Jdbc 請求連接后面:&connectionTimeout=3000&socketTimeout=1200