爲何數據庫鏈接很消耗資源 轉

開發應用程序久了,總想刨根問底,尤爲對一些有公共答案的問題。你們都能解釋,可是追根究底,都解釋不清。凡是都有爲何,並且用數字說明問題是最直觀的。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的文本協議,其中創建鏈接的過程具體以下:服務器

  • 第1步:創建TCP鏈接,經過三次握手實現;
  • 第2步:服務器發送給客戶端握手信息,客戶端響應該握手消息;
  • 第3步:客戶端發送認證包,用於用戶驗證,驗證成功後,服務器返回OK響應,以後開始執行命令;

用戶驗證成功以後,會進行一些鏈接變量的設置,好比字符集、是否自動提交事務等,其間會有屢次數據的交互。完成了這些步驟後,纔會執行真正的數據查詢和更新等操做。markdown

在本文的測試中,只用了5行代碼來創建鏈接,可是並無經過該鏈接去執行任何操做,因此在程序執行完畢以後,鏈接不是經過Connection.close()關閉的,而是因爲程序執行完畢,致使進程終止,形成與數據庫的鏈接異常關閉,因此最後會出現TCPRST報文。在這個最簡單的代碼中,沒有設置任何額外的鏈接屬性,因此在設置屬性上佔用的時間能夠認爲是最少的(其實,雖然咱們沒有設置任何屬性,可是驅動仍然設置了字符集、事務自動提交等,這取決於具體的驅動實現),因此整個鏈接所使用的時間能夠認爲是最少的。但從統計信息中能夠看出,在不包括最後TCPRST 報文時(由於該報文不須要服務器返回任何響應),可是其中仍需在客戶端和服務器之間進行往返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();
 

這樣的話,狀況發生了變化,主要體如今與數據庫鏈接的斷開,以下圖:

這裏寫圖片描述

  • 第1步:此時處於MySQL通訊協議階段,客戶端發送關閉鏈接請求,並且不用等待服務端的響應;
  • 第2步:TCP斷開鏈接,4次揮手完成鏈接斷開;

這裏是完整地完成了從數據庫鏈接的創建到關閉,整個過程花費了:

747.284311 - 747.100954 = 0.183357s = 183.357ms

這裏可能也有網絡情況的影響,比上述的225ms少了,可是也幾乎達到了200ms的級別。

那麼問題來了,想象一下這個場景,對於一個日活2萬的網站來講,假設每一個用戶只會發送5個請求,那麼一天就是10萬個請求,對於創建數據庫鏈接,咱們保守一點計算爲150ms好了,那麼一天當中花費在創建數據庫鏈接的時間有(還不包括執行查詢和更新操做):

100000 * 150ms = 15000000ms = 15000s = 250min = 4.17h

也就說天天花費在創建數據庫鏈接上的時間已經達到4個小時,因此說數據庫鏈接池是必須的嘛,並且當日活增長時,單單使用數據庫鏈接池也不能徹底保證你的服務可以正常運行,還須要考慮其餘的解決方案:

  • 緩存
  • SQL的預編譯
  • 負載均衡
  • ……

固然這不是本文的主要內容,本文想要闡述的核心思想只有一個,數據庫鏈接真的很耗時,因此不要頻繁的創建鏈接

相關文章
相關標籤/搜索