1.配置只读路由

①配置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://WIN-14VNU7CGQO1.fnst.com: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://WIN-14VNU7CGQO2.fnst.com: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')));

配置完成后:使用 SELECT * FROM sys.availability_read_only_routing_lists 查看路由表

确认一下应该是下面的形式 :
A B
A A
B A
B B

为什么这么配置请分析如下过程
1.正常运行时候,A作为主副本,B作为辅助副本,客户端连接字符串指定数据源是侦听器地址
2.此时发送只读请求
3.侦听器收到只读数据请求,有主副本A来处理,主副本A发现是ReadOnly,就查询路由表,发现第一条符合,就把只读请求交给辅助副本B来处理
4.此时主副本A失效了,那么由AlwaysOn的高可用可知,会让辅助B作为了主副本,等原来的主副本A恢复之后,让A成为新的辅助副本(当然这些对客户端是透明的)
5.副本A恢复之后,再发送一条只读请求
6.此时侦听器使用主副本B来处理这个请求,如果不像上面的设置方法,就找不到B到A的路由,也就不能实现所谓的高可用

2.配置的确认
例如:有一个可用组testAG,其中有两个副本A和B,其中主副本为A,辅助副本为B,并且在AlwaysOn可用组内设定了Listener

A和B的配置如下:

3.测试只读路由
客户端程序中指定连接字符串:connectStr = "Data Source=tcp:193.160.26.30,1433;Initial Catalog=test;Integrated Security=True;ApplicationIntent=ReadOnly;MultiSubnetFailover=True";
重要参数说明:
DataSource:tcp:193.160.26.30,1433 这个填写的是侦听器的地址 
ApplicationIntent=ReadOnly 说明这个连接是一个只读意向的连接,这样的情况下,请求发送到主副本A上,主副本发现是只读的请求会先产看只读路由表,然后通过
主副本A转发到辅助副本B上

会出现的问题: 如果客户端这时候的连接字符串指定了ApplicationIntent=ReadOnly,它只表明这是一个只读意向的请求,但是不能保证请求一点是只读的,如果是写请求
就会出现失败的情况。所以在进行写操作的时候不能设置这个选项。

测试程序如下:

主副本: 192.168.24.28
辅助副本:192.168.24.32
侦听器:192.168.24.30:1433

代码如下:

namespace AlwaysonTest
{
public partial class Form1 : Form
{ public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
} private void btnInsert_Click(object sender, EventArgs e)
{ Thread t = new Thread(Write);
t.IsBackground = true;
t.Start(); } private void btnReadData_Click(object sender, EventArgs e)
{ Thread t = new Thread(Read);
t.IsBackground = true;
t.Start();
} public void Write()
{
string name = System.DateTime.Now.ToString();
//插入数据的时候,连接字符串不指定ReadOnly
string connectStrW = "Data Source=tcp:193.160.26.30,1433;Initial Catalog=test;Integrated Security=True;MultiSubnetFailover=True"; int count = Convert.ToInt32(textBox4.Text); using (SqlConnection conn = new SqlConnection(connectStrW))
{
for (var i = ; i <= count; i++)
{
conn.Open();//打开数据库
//创建数据库命令
SqlCommand cmd = conn.CreateCommand();
//创建查询语句 在写的操作过程中,写之前先读操作,测试不加ReadOnly时候只读路由有没有效果
cmd.CommandText = "select count(*) from test1";
int x = (int)cmd.ExecuteScalar();
//创建查询语句 Thread.Sleep();
cmd.CommandText = "Insert into test1 values" + '(' + '\'' + name + '\'' + ')';
cmd.ExecuteNonQuery();
textBox1.Text = (x + i).ToString();
conn.Close();
}
} } public void Read()
{ //查询数据的时候,连接字符串指定ReadOnly
string connectStr = "Data Source=tcp:193.160.26.30,1433;Initial Catalog=test;Integrated Security=True;ApplicationIntent=ReadOnly;MultiSubnetFailover=True"; int count = Convert.ToInt32(textBox4.Text); for (var j = ; j <= count; j++)
{
Thread.Sleep();
using (SqlConnection conn = new SqlConnection(connectStr))
{
conn.Open();//打开数据库
//创建数据库命令
SqlCommand cmd = conn.CreateCommand();
//创建查询语句
cmd.CommandText = "select count(*) from test1";
int x = (int)cmd.ExecuteScalar();
textBox2.Text = x.ToString();
conn.Close();
}
} } }
}

检测结果:
开始之前,打开Sql Server Profiler进行数据的分析。

如下图所示,为了排除干扰,发现程序执行前是没有数据的读写的。

测试点一: 写操作不加ReadOnly限制,是不是能够在主副本写成功
结果如下图,

结论:因为只有主副本有操作记录,可以说明是在主副本进行写入成功的

测试点二:读操作加上ReadOnly限制,它的处理副本是主副本还是辅助副本(清除上次记录)
结果如下图:

结论:左侧主副本的内容和我们的查询内容无关,右侧辅助副本全部都是我们的查询操作,所以可以证明存在ReadOnly的时候读操作都被辅助副本执行

测试点三:读操作不加ReadOnly限制,它的处理副本是主副本还是辅助副本
Read()操作中连接字符串去掉ApplicationIntent=ReadOnly,并清空上面操作信息,然后执行程序

结论:在不加ReadOnly选项的时候,读操作全部有主副本进行了处理

测试点四:写操作加上ReadOnly限制,能够被主副本进行处理

在Write()中连接字符串中加上ApplicationIntent=ReadOnly,清空上面操作记录,执行程序

结论:上图可以知道,在写操作的时候,如果有ReadOnly会报错

AlwaysOn实现只读路由的更多相关文章

  1. SQL 2012 alwayson设置只读路由

    ALTER AVAILABILITY GROUP [sqlmaxiangqianbd]  MODIFY REPLICA ON   N'maxiangqian1' WITH   (SECONDARY_R ...

  2. sql server alwayson 可用性组 只读路由的设置

    昨天晚上学习了[SQL Server 2012实施与管理实战指南]的第三章,于是今天想在前段时间建的那个alwayson 可用性组测试环境上也配置一下只读路由,尝试实现读写分离. 按照书中的方法,执行 ...

  3. SQL Server Alwayson配置两个节点加共享文件夹仲裁见证

    标签:MSSQL/节点和共享文件夹多数 概述 之前讲过多数节点的仲裁配置,多数节点一般3个节点以上的奇数个节点:常见的是使用3个节点节点多了也是浪费因为Alwayson的只读路由只能利用到一个只读副本 ...

  4. SQL Server ->> 高可用与灾难恢复(HADR)技术 -- AlwaysOn可用性组(理论篇)

    因为篇幅原因,AlwaysOn可用性组被拆成了两部分:理论部分和实战部分.而实战部分又被拆成了准备工作和AlwaysOn可用性组搭建. 三篇文章各自的链接: SQL Server ->> ...

  5. 虚IP解决程序连只读服务器故障漂移

    目前公司有一套核心交易数据库配置了AlWaysON,SQL 2012版本, 1主4从, 其从库(8,14, 8.15) 这2台只读的从数据库服务器, 后台程序和wms等很多程序,都是直接配置IP连接这 ...

  6. 从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn)

    从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn) 第一篇http://www.cnblogs.com/lyhabc/p/4678330.html第二篇http://w ...

  7. (转) 从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn)

    原文地址: http://www.cnblogs.com/lyhabc/p/4682986.html 这一篇是从0开始搭建SQL Server AlwaysOn 的第三篇,这一篇才真正开始搭建Alwa ...

  8. SQL Server AlwaysOn

    标签:SQL SERVER/MSSQL SERVER/数据库/DBA/高性能解决方案 概述 环境: 域服务器:windows server 2008 R2 SP1,192.168.2.10 DNS:1 ...

  9. [AlwaysOn Availability Groups]排查:AG配置

    排查AG配置 本文主要用来帮助排查在AG配置时出现的问题,包括,AG功能被禁用,账号配置不正确,数据库镜像endpoint不存在,endpoint不能访问. Section Description A ...

随机推荐

  1. Java Collections Framework

    集合OR 容器 通常我们会用数组去保存一些基本数据类型,数组是编译器支持的类型,但是数组的一个明显缺点就是具有固定尺寸,而在一般情况下,只有在程序运行的时候,我们才能知道要保存的具体数目. Java类 ...

  2. 问题-Delphi控件选择卡自动选择与滚动方法

    问题现象: 在D7的控件工具条中每次要手动点向左向右很累,有没有方法可以自动移动.   问题解决: REGEDIT4 [HKEY_CURRENT_USER\Software\Borland\Delph ...

  3. mlock家族:锁定物理内存

    Start Page Index History Last Change mlock家族:锁定物理内存 系统调用 mlock 家族允许程序在物理内存上锁住它的部分或全部地址空间.这将阻止Linux 将 ...

  4. A Tour of Go Exercise: Fibonacci closure

    Let's have some fun with functions. Implement a fibonacci function that returns a function (a closur ...

  5. like用法

    SQL:btitle like '%"+keyword+"%' 存储过程:keyword like ''%'+@keyword+'%'' 直接查找:name like '%wang ...

  6. java入门学习(十一)逻辑运算符和位运算符

    请关注我的博客:www.taomaipin.com 家里有急事 暂停了几天,抱歉,现在呢开始说说java的运算语句和运算符 如果想利用java的运算语句 那么就离不开java的运算符,前面第九章讲了j ...

  7. Win7 U盘安装Ubuntu16.04 双系统

    Win7系统下安装Ubuntu系统,主要分为三步: 第1步:制作U盘启动盘 第2步:安装Ubuntu系统 第3步:创建启动系统引导 第1步:制作U盘启动盘 1.下载Ubuntu16.04安装镜像,官网 ...

  8. NSThead

    每个iOS应用程序都有个专门用来更新显示UI界面.处理用户的触摸事件的主线程,因此不能将其他太耗时的操作放在主线程中执行,不然会造成主线程堵塞(出现卡机现象),带来极坏的用户体验.一般的解决方案就是将 ...

  9. NUMBER_GET_NEXT

    1. SNRO /SNUM创建一个流水号对象 CALL FUNCTION 'NUMBER_RANGE_ENQUEUE' EXPORTING OBJECT = '' EXCEPTIONS FOREIGN ...

  10. 【转】Android 全屏方案(隐藏NavigationBar)

    http://www.07net01.com/2015/04/822292.html 在android4.0及其以上的版本中,出现了一个很屌的东西,叫做Navigation Bar,它和Status ...