[SQL Server] AlwaysOn with HAproxy

這篇來看看我如何在AlwaysOn中使用HAproxy,看看是否可以更有效利用Readable secondary。

我之前在SQL2016/2017 AG架構下,我實際透過application(NetCore and NetFramework)測試發現,

必須設定connectionstring中的pooling=false(預設true)才不用真正結束db session,

就有Load-Balancing效果,但這結果我並不意外,畢竟,connection pool是client在handle,

但我還是想測試看看透過HAproxy是否可以更有效率的進行Load-Balancing。

Note:

不使用connection pool對效能有滿大影響,

我以前對connection pool測試文章和XACT_Abort如何影響connection也可以參考看看

[C#][Tips]Dispose是否影響Connection Pooling?

[C#][Tips]如何確定Connection Pooling裡的Connection有效性

[SQL Server]Talking about XACT_ABORT

 

 

由於我們打算採取讀寫分離(AP至少有兩種以上connectionstring),

我為了讓AG中所有Secondary可以更有效利用,

所以我決定在既有AlwaysOn AG架構中加入HAproxy,看看是否能夠在更有效利用Secondary資源。

 

之前我已經在HAproxy設定好兩台的secondary sql server,透過HAproxy管理頁面確認如下

確認AG’s health

 

架構大概如下圖

 

測試:下面我會同時執行三個console

const string Connectionstringwithag = "Server=192.168.137.5;database=AdventureWorks2017;user id=sa;password=xxxx;Application Name=LoadBalanceWithAG;ApplicationIntent=ReadOnly;Timeout=60;";
        const string Connectionstringwithvip = "Server=192.168.137.238;database=AdventureWorks2017;user id=sa;password=xxxx;Application Name=LoadBalanceWithVIP;Timeout=60;";
        static void Main(string[] args)
        {
            var t1 = Task.Factory.StartNew(() =>
              {
                  SelectMSSQL(Connectionstringwithag);
              });
 
            var t2 = Task.Factory.StartNew(() =>
              {
                  SelectMSSQL(Connectionstringwithvip);
              });
            Task.WaitAll(new Task[] { t1, t2 });
            Console.WriteLine("Completed!");
            Console.ReadLine();
        }
 
        static void SelectMSSQL(string connectionstring)
        {
            var builder = new SqlConnectionStringBuilder(connectionstring);
            string sqlstatement = @"          
            SELECT TOP 1
                  [Schema]      
            FROM [dbo].[DatabaseLog]
                 union all
            select 'Current Server:'+@@SERVERNAME as [SERVERNAME]";
            int i = 0;
            while (i < 6)
            {
                try
                {
                    using (SqlConnection cn = new SqlConnection(connectionstring))
                    {
                        cn.Open();
                        using (SqlCommand cmd = new SqlCommand(sqlstatement, cn))
                        {
                            cmd.CommandType = System.Data.CommandType.Text;
                            using (SqlDataReader dr = cmd.ExecuteReader())
                            {
                                while (dr.Read())
                                {
                                    Console.WriteLine($"Result:{dr[0].ToString()} from {builder.ApplicationName}");
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Exception:{ex.Message}");
                }
                i++;
            }
            Console.WriteLine($"Done from :{builder.ApplicationName}");
        }

 

第一個console

使用VIP的都存取 WIN2K16D\SQL2K17

使用AG的都存取 WIN2K16C\SQL2K17

 

第二個console

使用VIP的都存取 WIN2K16C\SQL2K17

使用AG的都存取 WIN2K16C\SQL2K17

 

第三個console

使用VIP的都存取 WIN2K16D\SQL2K17

使用AG的都存取 WIN2K16D\SQL2K17

 

 

結果

使用VIP: WIN2K16D\SQL2K17 => WIN2K16C\SQL2K17 => WIN2K16D\SQL2K17

使用AG: WIN2K16C\SQL2K17 => WIN2K16C\SQL2K17 => WIN2K16D\SQL2K17

 

看來結果大同小異,雖然這次測試,HAproxy可以更有效利用Secondary資源,

但相對也要付出整合維護HAproxy成本,是否要使用就見仁見智了。

 

參考

[SQL SERVER]SQL2016-設定Alwayson AG Load Balance

[SQL Server] Config SQL Server 2017 availability group on Windows

[CentOS] Install and tuning HAproxy1.8