• 我踩过的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

    在客户端进行测试:

    读过程:

    写过程:

  • 相关阅读:
    【Spark亚太研究院系列丛书】Spark实战高手之路-第一章 构建Spark集群(第五步)(13)
    【Spark亚太研究院系列丛书】Spark实战高手之路-第一章 构建Spark集群(第五步)(12)
    【Spark亚太研究院系列丛书】Spark实战高手之路-第一章 构建Spark集群(第五步)(11)
    【Spark亚太研究院系列丛书】Spark实战高手之路-第一章 构建Spark集群(第五步)(10)
    【Spark亚太研究院系列丛书】Spark实战高手之路-第一章 构建Spark集群(第五步)(9)
    【Spark亚太研究院系列丛书】Spark实战高手之路-第一章 构建Spark集群(第五步)(8)
    获取文件CRC和MD5
    Delphi系统托盘组件 TTrayIcon 简介
    如何调试delphi的Access violation at address错误
    Eclipse导入Gradle时报错:SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable
  • 原文地址:https://www.cnblogs.com/dcz2015/p/5519179.html
Copyright © 2020-2023  润新知