<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官:為什么數(shù)據(jù)庫連接很消耗資源?

          共 2660字,需瀏覽 6分鐘

           ·

          2022-08-25 18:34

          點(diǎn)擊關(guān)注公眾號,Java干貨及時(shí)送達(dá)

          作者:lmy86263

          來源:blog.csdn.net/lmy86263/article/details/76165714

          開發(fā)應(yīng)用程序久了,總想刨根問底,尤其對一些有公共答案的問題。大家都能解釋,但是追根究底,都解釋不清。凡是都有為什么,而且用數(shù)字說明問題是最直觀的。
          本文主要想探究一下連接數(shù)據(jù)庫的細(xì)節(jié),尤其是在Web應(yīng)用中要使用數(shù)據(jù)庫來連接池,以免每次發(fā)送一次請求就重新建立一次連接。對于這個(gè)問題,答案都是一致的,建立數(shù)據(jù)庫連接很耗時(shí),但是這個(gè)耗時(shí)是都多少呢,又是分別在哪些方面產(chǎn)生的耗時(shí)呢?
          本文以連接MySQL數(shù)據(jù)庫為例,因?yàn)镸ySQL數(shù)據(jù)庫是開源的,其通信協(xié)議是公開的,所以我們能夠詳細(xì)分析建立連接的整個(gè)過程。
          在本文中,消耗資源的分析主要集中在網(wǎng)絡(luò)上,當(dāng)然,資源也包括內(nèi)存、CPU等計(jì)算資源,使用的編程語言是Java,但是不排除編程語言也會(huì)有一定的影響。
          首先先看一下連接數(shù)據(jù)庫的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);
          // 之后程序終止,連接被強(qiáng)制關(guān)閉

          然后通過Wireshark分析整個(gè)連接的建立過程,如下:
          在上圖中顯示的連接過程中,可以看出MySQL的通信協(xié)議是基于TCP傳輸協(xié)議的,而且該協(xié)議是二進(jìn)制協(xié)議,不是類似于HTTP的文本協(xié)議,其中建立連接的過程具體如下:
          • 第1步:建立TCP連接,通過三次握手實(shí)現(xiàn);
          • 第2步:服務(wù)器發(fā)送給客戶端握手信息,客戶端響應(yīng)該握手消息;
          • 第3步:客戶端發(fā)送認(rèn)證包,用于用戶驗(yàn)證,驗(yàn)證成功后,服務(wù)器返回OK響應(yīng),之后開始執(zhí)行命令;
          用戶驗(yàn)證成功之后,會(huì)進(jìn)行一些連接變量的設(shè)置,比如字符集、是否自動(dòng)提交事務(wù)等,其間會(huì)有多次數(shù)據(jù)的交互。完成了這些步驟后,才會(huì)執(zhí)行真正的數(shù)據(jù)查詢和更新等操作。
          在本文的測試中,只用了5行代碼來建立連接,但是并沒有通過該連接去執(zhí)行任何操作,所以在程序執(zhí)行完畢之后,連接不是通過Connection.close()關(guān)閉的,而是由于程序執(zhí)行完畢,導(dǎo)致進(jìn)程終止,造成與數(shù)據(jù)庫的連接異常關(guān)閉,所以最后會(huì)出現(xiàn)TCP的RST報(bào)文。在這個(gè)最簡單的代碼中,沒有設(shè)置任何額外的連接屬性,所以在設(shè)置屬性上占用的時(shí)間可以認(rèn)為是最少的(其實(shí),雖然我們沒有設(shè)置任何屬性,但是驅(qū)動(dòng)仍然設(shè)置了字符集、事務(wù)自動(dòng)提交等,這取決于具體的驅(qū)動(dòng)實(shí)現(xiàn)),所以整個(gè)連接所使用的時(shí)間可以認(rèn)為是最少的。但從統(tǒng)計(jì)信息中可以看出,在不包括最后TCP的RST 報(bào)文時(shí)(因?yàn)樵搱?bào)文不需要服務(wù)器返回任何響應(yīng)),但是其中仍需在客戶端和服務(wù)器之間進(jìn)行往返7次,也就是說完成一次連接,可以認(rèn)為,數(shù)據(jù)在客戶端和服務(wù)器之間需要至少往返7次,從時(shí)間上來看,從開始TCP的三次握手,到最終連接強(qiáng)制斷開為止(不包括最后的RST報(bào)文),總共花費(fèi)了:
          10.416042 - 10.190799 = 0.225243s = 225.243ms!!!
          這意味著,建立一次數(shù)據(jù)庫連接需要225ms,而這還是還可以認(rèn)為是最少的,當(dāng)然花費(fèi)的時(shí)間可能受到網(wǎng)絡(luò)狀況、數(shù)據(jù)庫服務(wù)器性能以及應(yīng)用代碼是否高效的影響,但是這里只是一個(gè)最簡單的例子,已經(jīng)足夠說明問題了!
          由于上面是程序異常終止了,但是在正常的應(yīng)用程序中,連接的關(guān)閉一般都是通過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();

          這樣的話,情況發(fā)生了變化,主要體現(xiàn)在與數(shù)據(jù)庫連接的斷開,如下圖:

          • 第1步:此時(shí)處于MySQL通信協(xié)議階段,客戶端發(fā)送關(guān)閉連接請求,而且不用等待服務(wù)端的響應(yīng);

          • 第2步:TCP斷開連接,4次揮手完成連接斷開;
          這里是完整地完成了從數(shù)據(jù)庫連接的建立到關(guān)閉,整個(gè)過程花費(fèi)了:
          747.284311 - 747.100954 = 0.183357s = 183.357ms
          這里可能也有網(wǎng)絡(luò)狀況的影響,比上述的225ms少了,但是也幾乎達(dá)到了200ms的級別。
          那么問題來了,想象一下這個(gè)場景,對于一個(gè)日活2萬的網(wǎng)站來說,假設(shè)每個(gè)用戶只會(huì)發(fā)送5個(gè)請求,那么一天就是10萬個(gè)請求,對于建立數(shù)據(jù)庫連接,我們保守一點(diǎn)計(jì)算為150ms好了,那么一天當(dāng)中花費(fèi)在建立數(shù)據(jù)庫連接的時(shí)間有(還不包括執(zhí)行查詢和更新操作):
          100000 * 150ms = 15000000ms = 15000s = 250min = 4.17h
          也就說每天花費(fèi)在建立數(shù)據(jù)庫連接上的時(shí)間已經(jīng)達(dá)到4個(gè)小時(shí),所以說數(shù)據(jù)庫連接池是必須的嘛,而且當(dāng)日活增加時(shí),單單使用數(shù)據(jù)庫連接池也不能完全保證你的服務(wù)能夠正常運(yùn)行,還需要考慮其他的解決方案:
          • 緩存
          • SQL的預(yù)編譯
          • 負(fù)載均衡
          • ……

          當(dāng)然這不是本文的主要內(nèi)容,本文想要闡述的核心思想只有一個(gè),數(shù)據(jù)庫連接真的很耗時(shí),所以不要頻繁的建立連接。

            

          1、社區(qū)糾紛不斷:程序員何苦為難程序員?
          2、該死的單元測試,寫起來到底有多痛?
          3、互聯(lián)網(wǎng)人為什么學(xué)不會(huì)擺爛
          4、為什么國外JetBrains做 IDE 就可以養(yǎng)活自己,國內(nèi)不行?區(qū)別在哪?
          5、相比高人氣的Rust、Go,為何 Java、C 在工具層面進(jìn)展緩慢?
          6、讓程序員早點(diǎn)下班的《技術(shù)寫作指南》

          點(diǎn)

          點(diǎn)

          點(diǎn)點(diǎn)

          點(diǎn)在看

          瀏覽 27
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日日日网站 | 午夜老司机福利 | 亚洲一卡二卡精品 | 日韩操逼内射 | 97中文字幕第二十二页 |