開發應用程序久了,總想刨根問底,尤爲對一些有公共答案的問題。你們都能解釋,可是追根究底,都解釋不清。凡是都有爲何,並且用數字說明問題是最直觀的。java
本文主要想探究一下鏈接數據庫的細節,尤爲是在Web
應用中要使用數據庫來鏈接池,以避免每次發送一次請求就從新創建一次鏈接。對於這個問題,答案都是一致的,創建數據庫鏈接很耗時,可是這個耗時是都多少呢,又是分別在哪些方面產生的耗時呢?mysql
本文以鏈接MySQL
數據庫爲例,由於MySQL
數據庫是開源的,其通訊協議是公開的,因此咱們可以詳細分析創建鏈接的整個過程。sql
在本文中,消耗資源的分析主要集中在網絡上,固然,資源也包括內存、CPU等計算資源,使用的編程語言是
Java
,可是不排除編程語言也會有必定的影響。數據庫
首先先看一下鏈接數據庫的Java
代碼,以下:編程
Class.forName("com.mysql.jdbc.Driver");
String name = "shine_user";
String password = "123";
String url = "jdbc:mysql://172.16.100.131:3306/clever_mg_test";
Connection conn = DriverManager.getConnection(url, name, password);
// 以後程序終止,鏈接被強制關閉
而後經過Wireshark分析整個鏈接的創建過程,以下:緩存
在上圖中顯示的鏈接過程當中,能夠看出MySQL
的通訊協議是基於TCP
傳輸協議的,並且該協議是二進制協議,不是相似於HTTP
的文本協議,其中創建鏈接的過程具體以下:服務器
TCP
鏈接,經過三次握手實現;用戶驗證成功以後,會進行一些鏈接變量的設置,好比字符集、是否自動提交事務等,其間會有屢次數據的交互。完成了這些步驟後,纔會執行真正的數據查詢和更新等操做。markdown
在本文的測試中,只用了5行代碼來創建鏈接,可是並無經過該鏈接去執行任何操做,因此在程序執行完畢以後,鏈接不是經過Connection.close()
關閉的,而是因爲程序執行完畢,致使進程終止,形成與數據庫的鏈接異常關閉,因此最後會出現TCP
的RST
報文。在這個最簡單的代碼中,沒有設置任何額外的鏈接屬性,因此在設置屬性上佔用的時間能夠認爲是最少的(其實,雖然咱們沒有設置任何屬性,可是驅動仍然設置了字符集、事務自動提交等,這取決於具體的驅動實現),因此整個鏈接所使用的時間能夠認爲是最少的。但從統計信息中能夠看出,在不包括最後TCP
的RST
報文時(由於該報文不須要服務器返回任何響應),可是其中仍需在客戶端和服務器之間進行往返7次,也就是說完成一次鏈接,能夠認爲,數據在客戶端和服務器之間須要至少往返7次,從時間上來看,從開始TCP的三次握手,到最終鏈接強制斷開爲止(不包括最後的RST
報文),總共花費了:網絡
10.416042 - 10.190799 = 0.225243s = 225.243ms!!!負載均衡
這意味着,創建一次數據庫鏈接須要225ms,而這仍是還能夠認爲是最少的,固然花費的時間可能受到網絡情況、數據庫服務器性能以及應用代碼是否高效的影響,可是這裏只是一個最簡單的例子,已經足夠說明問題了!
因爲上面是程序異常終止了,可是在正常的應用程序中,鏈接的關閉通常都是經過Connection.close()
完成的,代碼以下:
Class.forName("com.mysql.jdbc.Driver");
String name = "shine_user";
String password = "123";
String url = "jdbc:mysql://172.16.100.131:3306/clever_mg_test";
Connection conn = DriverManager.getConnection(url, name, password);
conn.close();
這樣的話,狀況發生了變化,主要體如今與數據庫鏈接的斷開,以下圖:
MySQL
通訊協議階段,客戶端發送關閉鏈接請求,並且不用等待服務端的響應;這裏是完整地完成了從數據庫鏈接的創建到關閉,整個過程花費了:
747.284311 - 747.100954 = 0.183357s = 183.357ms
這裏可能也有網絡情況的影響,比上述的225ms少了,可是也幾乎達到了200ms的級別。
那麼問題來了,想象一下這個場景,對於一個日活2萬的網站來講,假設每一個用戶只會發送5個請求,那麼一天就是10萬個請求,對於創建數據庫鏈接,咱們保守一點計算爲150ms好了,那麼一天當中花費在創建數據庫鏈接的時間有(還不包括執行查詢和更新操做):
100000 * 150ms = 15000000ms = 15000s = 250min = 4.17h
也就說天天花費在創建數據庫鏈接上的時間已經達到4個小時,因此說數據庫鏈接池是必須的嘛,並且當日活增長時,單單使用數據庫鏈接池也不能徹底保證你的服務可以正常運行,還須要考慮其餘的解決方案:
SQL
的預編譯固然這不是本文的主要內容,本文想要闡述的核心思想只有一個,數據庫鏈接真的很耗時,因此不要頻繁的創建鏈接。