• <button id="eiyoe"><acronym id="eiyoe"></acronym></button>
    <em id="eiyoe"></em>

  • <rp id="eiyoe"><acronym id="eiyoe"><input id="eiyoe"></input></acronym></rp>
      查看: 154|回復: 0
      上一主題 下一主題

      詳解.NET數據庫連接池

      79910

      主題

      0

      好友

      積分

      離線 發信

      跳轉到指定樓層
      樓主
      發表于 2021-09-17 10:50 | 只看該作者 | 倒序瀏覽
      目錄
      • 前置知識背景
        • 1. .NET數據庫連接池的背景
        • 2. .NET 數據庫連接池的表現
        • 3. .NET是如何形成數據庫連接池的?
        • 4. 連接池中的連接什么時候被移除?
      • .NET 如何清空連接池?

        一般我們的項目中會使用1到2個數據庫連接配置,同程藝龍的數據庫連接配置被收攏到統一的配置中心,由DBA統一配置和維護,業務方通過某個字符串配置拿到的是Connection對象。

        DBA能在對業務方無侵入的情況下,給業務方切換備份數據庫,之后DBA要求舊連接池必須立即被清空, 那么問題來了: dotnet能不能立即清空連接池? 注意我用得是清空,而不是釋放連接。

        如果有同學不知道DBA做這個要求的目的,那我亂幌攏br data-filtered="filtered" /> 應用程序不再使用舊連接時,理論上你的連接池要被完全清空,因為單純的釋放連接,只會讓連接池中的Connection處于Sleep狀態,依舊維持了短時間的物理連接,這個短時間其實是不必要的占用,影響了舊連接數據庫的吞吐量。

        前置知識背景

        回答這個問題之前, 我們還是先研究一下.NET數據庫連接池。

        1. .NET數據庫連接池的背景

        數據庫連接是一個耗時的行為,大多數應用程序只使用1到幾種數據庫連接,為了最小化打開連接的成本,ado.net使用了一種稱為連接池的優化技術。

        2. .NET 數據庫連接池的表現

        數據庫連接池減少了必須打開新連接的次數,池程序維護了數據庫物理連接。

        通過為每個特定的連接配置保持一組活動的連接對象來管理連接。

        每當應用程序嘗試Open連接,池程序就會在池中找到可用的連接,如果有則返回給調用者;
        應用程序Close連接對象時,池程序將連接對象返回到池中(Sleep), 這個連接可以在下一次Open調用中重用。

        看黑板,下面是這次的重點:

        3. .NET是如何形成數據庫連接池的?

        只有相同的連接配置才能被池化,.NET為不同的配置維護了不同的連接池。

        相同的配置限制為:
        進程相同、
        連接字符串相同、
        連接字符串關鍵key順序相同。
        (同一連接提供的關鍵字順序不同將被分到不同的池)。

        連接池中的可用連接的數量由連接字符串Max Pool Size決定。

        在一個應用程序中,有如下代碼:

        using (SqlConnection connection = new SqlConnection(  
          "Integrated Security=SSPI;Initial Catalog=Northwind"))  
            {  
                connection.Open();
                // Pool A is created.  
            }  
          
        using (SqlConnection connection = new SqlConnection(  
          "Integrated Security=SSPI;Initial Catalog=pubs"))  
            {  
                connection.Open();
                // Pool B is created because the connection strings differ.  
            }  
          
        using (SqlConnection connection = new SqlConnection(  
          "Integrated Security=SSPI;Initial Catalog=Northwind"))  
            {  
                connection.Open();
                // The connection string matches pool A.  
            }

        上面創建了三個Connection對象,但是只形成了兩個數據庫連接池。

        還是以上代碼,如果有兩個相同的應用程序,理論上就形成了四個數據庫連接池。

        4. 連接池中的連接什么時候被移除?

        連接池中的連接空閑4-8 分鐘,池程序會移除這個連接。

        應用程序下線,連接池直接被清空。

        .NET 如何清空連接池?

        有了以上知識背景

        我們再來回顧一下 DBA的要求,切換原連接配置的時候,清空連接池。

        我從官方文檔找到
        .NET提供了
        ClearAllPools、ClearPool靜態方法用于清空連接池。

        • ClearAllPools: 清空與這個DBProvider相關的所有連接池
        • ClearPool(DBConnection conn) 清空與這個連接對象相關的連接池

        很明顯,我們這次要使用ClearPool(DBConnection conn) 方法。

        光說不練不驗證,不是我的風格。

        天錘壓測/queryapi 產生一個包含大量連接對象的連接池;
        適當的時候,/clearpoolapi清空連接池。

         public class MySqlController : Controller
            {
                // GET: MySql
                [Route("query")]
                public string Index()
                {
                    var s = "User ID=teinfra_neo_netreplay;Password=123456;DataBase=teinfra_neo_netreplay;Server=10.100.41.196;Port=3980;Min Pool Size=1;Max Pool Size=28;CharSet=utf8;";
                    using (var conn = new MySqlConnection(s))
                    {
                        var comm = conn.CreateCommand();
                        comm.CommandText = "select count(*) from usertest;";
                        conn.Open();
                        var ret = comm.ExecuteScalar();
        
                        comm.CommandText = "select count(*) from information_schema.PROCESSLIST WHERE HOST like  '10.22.12.245%';";
                        var len = comm.ExecuteScalar();
                        return $"查詢結果:{ret} ,順便查一下當前連接池的連接對象個數: {len}";
                    };
                }
        
                [Route("clearpool")]
                public string Switch()
                {
                    var s = "User ID=teinfra_neo_netreplay;Password=123456;DataBase=teinfra_neo_netreplay;Server=10.100.41.196;Port=3980;Min Pool Size=1;Max Pool Size=28;CharSet=utf8;";
                    using (var conn = new MySqlConnection(s))
                    {
                        conn.Open();
                        MySqlConnection.ClearPool(conn);
                    };
        
                    using (var conn = new MySqlConnection(s))
                    {
                        conn.Open();
                        var comm = conn.CreateCommand();
                        comm.CommandText = "select count(*) from information_schema.PROCESSLIST WHERE HOST like  '10.22.12.245%';";
                        var len = comm.ExecuteScalar();
                        return $"之前已經清空連接池, 此次查詢連接池有 {v1}  個連接對象";
                    }
        
                }
            }
        

        1. 經過壓測工具

        2. mysql數據庫對比

        mysql的連接數查詢命令, (host是web服務器IP):
        select * from information_schema.PROCESSLIST WHERE HOST like '10.22.12.245%';

        3. 調用/clearpoolapi,清空連接池

        bingo,清空連接池的理論得到驗證。

        干貨旁白

        這是我在同程藝龍最近爬的比較深的坑位,
        我從本次實踐中理解了.NET數據庫連接池的定義方式、并配套掌握了DBProvider 對于.net連接數的查詢定位方式。

        對祖傳代碼的改造,.NET數據獲取組件SDK 確實提高了原數據庫的吞吐量。

        希望本文設計考量、理論+論證的行文思路對于讀者有所幫助, 再次感謝有心讀者取關、再關注。

        到此這篇關于詳解.NET數據庫連接池的文章就介紹到這了,更多相關.NET數據庫連接池內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

        來源:http://www.jb51.net/article/219795.htm