我踩過的Alwayson的坑!


最近被sql server Alwayson高可用組和讀寫分離,弄得神魂顛倒,身心俱疲。遇到了下面一些問題,提醒自己也給后來人做些記錄。


EntityFramework支不支持Alwayson?

起因:

因為要進行數據庫的優化,所以想在現有的sql server基礎上采用微軟的Alwayson解決方案,實現讀寫分離把數據庫的壓力減小一下。

之前兩篇文章關於Alwayson的都是建立在直接使用Ado.net的基礎上,因為EF也是基於Ado.net的orm所以,我認為也是支持Alwayson的。

寫一個測試程序吧:

代碼很簡單,我就省略了注釋,數據庫有三個字段如下:

USE [test]
GO

/****** Object:  Table [dbo].[test1]    Script Date: 2016/05/23 10:43:41 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[test1](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [name] [datetime] NULL,
    [test_id] [int] NULL,
 CONSTRAINT [PK_test1] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
        private void button1_Click(object sender, EventArgs e)
        {
            using (testEntities dbcontext = new testEntities())
            {
                try 
                {
                    
                    var list = (from info in dbcontext.test1
                                select info).ToList();

                    dataGridView1.DataSource = list;
                }
               catch (Exception ex) 
                { 
                    //do nothing
                }

            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            var count = Convert.ToInt32(textBox1.Text);
            using (testEntities dbcontext = new testEntities())
            {
                for(var i = 1 ; i <= count;i++)
                {
                    test1 t = new test1()
                    {
                        name = System.DateTime.Now,
                        test_id = i
                    };

                    dbcontext.test1.Add(t);
                }
                dbcontext.SaveChanges();
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            using (testEntities dbcontext = new testEntities())
            {
                var item = dbcontext.test1.Where(p => p.id != 0);

                dbcontext.test1.RemoveRange(item);

                dbcontext.SaveChanges();
                
            }
        }

環境簡介:

1.主副本:193.160.26.28

2.輔助副本:193.160.26.32

3.偵聽器:193.160.26.30

4.客戶端:10.167.218.27

 

DB First方式連接字符串:(怎么做可以自行查詢)

①不進行讀寫分離的時候

連接字符串如下:

 <connectionStrings>
   <add name="testEntities" 
     connectionString="metadata=res://*/test.csdl|res://*/test.ssdl|res://*/test.msl;provider=System.Data.SqlClient;provider connection string=&quot;data sou     rce=tcp:193.160.26.30,1433;initial catalog=test;persist security info=True;user id=sa;password=123456;&quot;" providerName="System.Data.EntityClient"/>
  </connectionStrings>

期待結果:可以讀,可以寫,並且都是在主副本上進行的。

實際結果:

上圖說明,不使用只讀的時候,和我們的期待結果一致。

 

2.采用只讀路由

修改連接字符串如下:

<connectionStrings>
<add name="testEntities" connectionString="metadata=res://*/test.csdl|res://*/test.ssdl|res://*/test.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=tcp:193.160.26.30,1433;initial catalog=test;persist security info=True;user id=sa;password=123456;ApplicationIntent=ReadOnly;MultiSubnetFailover=True&quot;" providerName="System.Data.EntityClient"/>
</connectionStrings>

 期待結果:能讀取(輔助副本),不能寫入(因為設定了只讀)

 實際結果:讀取和寫入的時候出現了如下的錯誤:

 

如上圖所示:

在建立與服務器的連接時出錯。 在連接到 SQL Server 時,在默認的設置下 SQL Server 不允許遠程連接可能會導致此失敗。(訪問接口: TCP 訪問接口,錯誤: 0 - 無法識別這種主機)(.Net SqlClient 數據訪問接口)

為什么呢?

I.最先猜想到的是sql Client的問題,是不是不支持ReadOnly,查了一下msdn,上面解釋如下:

https://msdn.microsoft.com/zh-cn/library/system.data.sqlclient(v=vs.110).aspx  意思就是4.0以上版本是支持 ApplicationIntent 的值。可能的值為 ReadWrite 和 ReadOnly

查看一下:目前使用的sql Client,是支持的。

 

II.不是sqlClinet的問題,又仔細看了一下錯誤的,host不能識別,考慮是不是DNS的問題,在客戶端使用cmd中的ping命令,ping一下偵聽器地址

在主副本或者輔助副本中ping一下:

感覺好像是DNS的問題:把程序拷貝到主副本或者輔助副本中執行:

結果:

讀過程:

讀過程沒出現問題。

寫過程:出現了只讀異常,貌似和我的期待結果一樣。

分析問題:

因為我的客戶端和兩天虛擬機從屬於不同的域賬戶,所以這可能就是問題的點。

解決問題:

怎么才能解決呢?

第一個方法:把客戶端加到和虛擬機同一個域當中,但是這樣做是很有風險的,不能保證每一個客戶端都和服務器在同一個域當中。所以我不能采用這樣的方式

第二個方法:仔細回覽了一下只讀路由配置的腳本, 下面是微軟官方提供的示例

ALTER AVAILABILITY GROUP [AG1]
 MODIFY REPLICA ON
N'COMPUTER01' WITH 
(SECONDARY_ROLE (ALLOW_CONNECTIONS = READ_ONLY));
ALTER AVAILABILITY GROUP [AG1]
 MODIFY REPLICA ON
N'COMPUTER01' WITH 
(SECONDARY_ROLE (READ_ONLY_ROUTING_URL = N'TCP://COMPUTER01.contoso.com:1433'));

在進行指定只讀路由的時候,發現他使用的是實例名字COMPUTER01.contoso.com,所以猜想可能和這個有關系,要使用IP地址估計問題就能解決

修改前一篇的只讀路由:http://www.cnblogs.com/dcz2015/p/5444438.html 如下:

①刪除只讀路由表:

ALTER AVAILABILITY GROUP [testAG]
MODIFY REPLICA ON N'WIN-14VNU7CGQO1' WITH
(
    PRIMARY_ROLE (READ_ONLY_ROUTING_LIST=NONE)
);
GO
ALTER AVAILABILITY GROUP [testAG]
MODIFY REPLICA ON N'WIN-14VNU7CGQO2' WITH
(
    PRIMARY_ROLE (READ_ONLY_ROUTING_LIST=NONE)
);
GO

②添加只讀路由:

--①配置A副本的只讀路由屬性(ReadOnly代表‘只讀意向’)                                                    
ALTER AVAILABILITY GROUP [testAG]                                                     
MODIFY REPLICA ON N'WIN-14VNU7CGQO1' WITH (SECONDARY_ROLE (ALLOW_CONNECTIONS = READ_ONLY));    
--②配置A副本的只讀路由URL ALTER AVAILABILITY GROUP [testAG] MODIFY REPLICA ON N'WIN-14VNU7CGQO1' WITH (SECONDARY_ROLE (READ_ONLY_ROUTING_URL = N'tcp://193.160.26.32:1433')); --③配置B副本的只讀路由屬性 ALTER AVAILABILITY GROUP [testAG] MODIFY REPLICA ON N'WIN-14VNU7CGQO2' WITH (SECONDARY_ROLE (ALLOW_CONNECTIONS = READ_ONLY));
--④配置B副本的只讀路由URL ALTER AVAILABILITY GROUP [testAG] MODIFY REPLICA ON N'WIN-14VNU7CGQO2' WITH (SECONDARY_ROLE (READ_ONLY_ROUTING_URL = N'tcp://193.160.26.28:1433')); --⑤配置A副本作為主副本時候的只讀路由表 ALTER AVAILABILITY GROUP [testAG] MODIFY REPLICA ON N'WIN-14VNU7CGQO1' WITH (PRIMARY_ROLE (READ_ONLY_ROUTING_LIST=('WIN-14VNU7CGQO2','WIN-14VNU7CGQO1'))); --⑥配置B副本作為主副本時候的只讀路由表 ALTER AVAILABILITY GROUP [testAG] MODIFY REPLICA ON N'WIN-14VNU7CGQO2' WITH (PRIMARY_ROLE (READ_ONLY_ROUTING_LIST=('WIN-14VNU7CGQO1','WIN-14VNU7CGQO2'))); GO

在客戶端進行測試:

讀過程:

寫過程:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM