古詩詞大全網 - 成語用法 - 妳真的知道如何設置數據庫連接池的大小嗎

妳真的知道如何設置數據庫連接池的大小嗎

前段時間在壹個老項目中經歷過壹個問題:壹個 Dubbo 服務,啟動的時候慢的要死,後來看日誌查原因整個過程壹直在初始化數據庫連接。壹看數據庫連接參數,連接池大小:1024。

很多入行晚的同學沒有經歷過手寫 JDBC 連接的日子。那個時候沒有數據庫連接池的概念,都是原生代碼壹頓搞,後來有了 iBATIS 之後 Java 開發的繁雜程度才逐漸減輕,也衍生 C3P0 數據庫連接池這種基礎的東西。羅馬不是壹天建成的,可是互聯網發展太快了,技術壓力逼迫下各種中間件被迫研發,大家加班加點搞出來各種高大上的腳手架,也成就很多 偉人。

數據庫連接使用 TCP 的方式,建立連接需要3次握手,釋放連接需要4次揮手,當今這種互聯網使用頻率下,如果每壹次訪問數據庫都重新建立連接,我估計妳們公司倒閉800次都不夠。

1. 數據庫連接的過程是怎樣的

Java 鼻祖 Sun 公司是想以壹套API統壹天下,奈何各個數據庫服務器廠商太給力統壹不了。無奈之舉是創建了壹個統壹的接口,提出壹套統壹接入的步驟,各個廠商實現接口,按照步驟加載自己的數據庫。所以現在的方案就是4板斧:

註冊驅動,為人所知的:Class.forName();

獲取Connection,成功即與數據庫建立連接;

拿到Statement對象,用於操作數據庫的CRUD;

獲取數據庫返回結果ResultSet。

大家應該都知道數據庫本身是壹個客戶端程序,只有啟動了才能連接。拿 MYSQL 舉例,我們在安裝並啟動了服務的機器上,命令行的方式輸入:mysql -uroot -p 即可連接當前數據庫。

MYSQL 連接方式有很多種,區分Unix系統 和 Windows 系統以及通用的連接方式,在這裏僅說兩種方式:壹種為 unix domain socket,另外壹種為基於 tcp/ip 協議,壹般我們如果遠程訪問數據庫肯定是基於 tcp/ip 的,但是如果我們在本機登錄就會分為使用 socket 還是 tcp/ip。

socket:mysql -uroot -p

tcp/ip:mysql -h127.0.0.1 -uroot -p

當數據庫服務器和應用服務器位於不同的主機時就要使用 tcp/ip 的方式建立連接。每壹個連接在操作系統中占用壹個線程來維護。建立連接也分為兩類:短連接和長連接。

短連接

所謂短連接就是指應用程序和數據庫通信完畢之後連接關閉。這種連接每次的操作就是:

發出請求--->建立連接--->操作數據--->釋放連接

這樣做的問題是:

頻繁的建立 / 釋放連接對數據庫來說增加了系統負擔;

應用程序每次操作數據庫的過程將會變得很慢;

應用系統每次建立連接都要占用壹個端口,頻繁的建立/釋放,每個被釋放的連接在發出釋放請求之後並不是馬上就執行,必須經歷壹個 FIN 階段的等待直到確認為止。所以在每秒幾千次數據庫請求的時候,應用服務器端口很有可能被消耗完。

長連接

長連接即在建立連接後壹直打開,直到應用程序關閉才釋放。使用長連接的好處是減少每次創建連接帶來的開銷。

對於應用服務器來說維持長連接的好處不言自明,但是對於數據庫服務器來說,過多的長連接則是災難。

MYSQL的TCP連接支持長連接,所以每次操作完數據庫,可以不必直接關掉連接,而是等待下次使用的時候在復用這個連接。所有的Socket長連接都是通過TCP自帶的ping來維持心跳(TCP保活),從而保持連接狀態,而我們熟悉的websocket,也正是通過TCP的心跳來維持連接不被中斷。

連接池

長連接的好處這麽大,自然大家都用長連接。慢慢就搞出壹套長連接維護的工具 - 數據庫連接池。

設計連接池也沒有多麽復雜,大致的步驟就是:

初始化連接;

業務取出連接;

業務發送請求;

放回連接。

除了上面的基本功能以外,還要處理並發問題,多數據庫服務器和多用戶,事務處理,連接池的配置與維護。大概就這些功能。有了連接池之後,連接的建立和釋放跟業務就沒有關系,交給交接池來維護。

2. MYSQL 能支持多少連接

MYSQL 的最大連接數在5.7版本中默認是151, 最大可以達到16384(2^14)。如何設置最大連接數在於妳的服務器性能,查看 MYSQL連接數信息命令如下:

mysql> show variables like '%max_connections%';

+-----------------+-------+

| Variable_name | Value |

+-----------------+-------+

| max_connections | 5050 |

+-----------------+-------+

1 row in set (0.00 sec)

我們生產環境MYSQL的最大連接數設置為 5050,註意不能設置的太小,太小造成的後果是連接失敗:“query failed Error 1040: Too many connections“ 錯誤。太大且當連接該數據庫的機器比較多的時候則會對當前MYSQL的性能產生影響。

MYSQL官網給出了壹個設置最大連接數的建議比例:

Max_used_connections / max_connections * 100% ≈ 85%

即已使用的連接數占總上限的85%左右,如果目前已使用的連接數與最大連接數比例小於10%那很顯然設置的過大。

查詢當前數據庫已建立連接數:

mysql> show status like 'Threads_connected';

+-------------------+-------+

| Variable_name | Value |

+-------------------+-------+

| Threads_connected | 89 |

+-------------------+-------+

1 row in set (0.00 sec)

Mysql的配置可以在全局變量中查詢和設置,相關的配置主要可以查詢下面這些:

配置

含義

Connections

嘗試連接Mysql的連接數,不管連接成功與否,該值都會+1

Threads_connected

已經建立的連接數,單節點下壹般小於最大連接池最大連接數

max_connections

Mysql限制的最大的可連接的數量

wait_timeout

即MYSQL長連接(非交互式)的最大生命時長,默認是8小時

interactive_timeout

長連接(交互式)的最大生命時長,默認是8小時

3. 連接池設置多少連接才合適

設置連接池的大小肯定不是越大越好,需要考慮的是當前服務所在機器的性能,網絡狀況,數據庫機器性能,數據庫特性等等。同時也要做到不浪費系統資源,內存,端口,同步信號量等等。

比如說應用服務器Tomcat設置的最大線程池缺省值200,最大假設每個線程會用到壹個數據庫連接,那麽線程池大小應該小於等於200。

另外需要考慮的是,每申請壹個長連接都會在物理網絡上建立壹個用於長連接維護的進程,而進程的執行跟物理機的CPU核數有關。理論上壹個8核的服務器將連接池設置為8最佳,每壹個核同時處理壹個線程,超過8的並發就有線程上下文切換的開銷。

這裏有壹個 Oracle 性能小組發布的簡短視頻,連接池測試分2個部分:測試視頻1 ,測試視頻2 。視頻中調整了線程池大小為2048的時候數據庫性能陡然下降,後面調整到144就恢復了。PostgreSQL提供了壹個設置預期線程池大小的公式:

connections = ((core_count * 2) + effective_spindle_count)

該公式來自於:/brettwooldridge/HikariCP/wiki/About-Pool-Sizing。

其中,core_count是CPU核心, effective_spindle_count 的含義是有效主軸數,如果妳的服務器使用的是帶有16個磁盤的RAID,那麽valid_spindle_count=16。它實質上是服務器可以管理多少個並行I / O請求的度量。旋轉硬盤壹次(通常)壹次只能處理壹個I / O請求,如果妳有16個,則系統可以同時處理16個I / O請求。

我想 Hikari 作為目前最優秀的數據庫連接池之壹,提出的這個公式還是經得起檢驗的。大家不妨在生產環境試試(出問題別找我)。

妳真的知道如何設置數據庫連接池的大小嗎

標簽:加班The帶來腳手架過多功能短連接建立連接復雜