1.配置只读路由

  1. ①配置A副本的只读路由属性(ReadOnly代表‘只读意向’)
  2. ALTER AVAILABILITY GROUP [testAG]
  3. MODIFY REPLICA ON N'WIN-14VNU7CGQO1' WITH (SECONDARY_ROLE (ALLOW_CONNECTIONS = READ_ONLY));
  4. ②配置A副本的只读路由URL
  5. ALTER AVAILABILITY GROUP [testAG]
  6. MODIFY REPLICA ON N'WIN-14VNU7CGQO1' WITH (SECONDARY_ROLE (READ_ONLY_ROUTING_URL = N'tcp://WIN-14VNU7CGQO1.fnst.com:1433'));
  7. ③配置B副本的只读路由属性
  8. ALTER AVAILABILITY GROUP [testAG]
  9. MODIFY REPLICA ON N'WIN-14VNU7CGQO2' WITH (SECONDARY_ROLE (ALLOW_CONNECTIONS = READ_ONLY));
  10. ④配置B副本的只读路由URL
  11. ALTER AVAILABILITY GROUP [testAG]
  12. MODIFY REPLICA ON N'WIN-14VNU7CGQO2' WITH (SECONDARY_ROLE (READ_ONLY_ROUTING_URL = N'tcp://WIN-14VNU7CGQO2.fnst.com:1433'));
  13. ⑤配置A副本作为主副本时候的只读路由表
  14. ALTER AVAILABILITY GROUP [testAG]
  15. MODIFY REPLICA ON N'WIN-14VNU7CGQO1' WITH (PRIMARY_ROLE (READ_ONLY_ROUTING_LIST=('WIN-14VNU7CGQO2','WIN-14VNU7CGQO1')));
  16. ⑥配置B副本作为主副本时候的只读路由表
  17. ALTER AVAILABILITY GROUP [testAG]
  18. 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 查看路由表

  1. 确认一下应该是下面的形式
  2. A B
  3. A A
  4. B A
  5. 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,它只表明这是一个只读意向的请求,但是不能保证请求一点是只读的,如果是写请求
就会出现失败的情况。所以在进行写操作的时候不能设置这个选项。

测试程序如下:

  1. 主副本: 192.168.24.28
  2. 辅助副本:192.168.24.32
  3. 侦听器:192.168.24.30:1433

代码如下:

  1. namespace AlwaysonTest
  2. {
  3. public partial class Form1 : Form
  4. {
  5.  
  6. public Form1()
  7. {
  8. InitializeComponent();
  9. Control.CheckForIllegalCrossThreadCalls = false;
  10. }
  11.  
  12. private void btnInsert_Click(object sender, EventArgs e)
  13. {
  14.  
  15. Thread t = new Thread(Write);
  16. t.IsBackground = true;
  17. t.Start();
  18.  
  19. }
  20.  
  21. private void btnReadData_Click(object sender, EventArgs e)
  22. {
  23.  
  24. Thread t = new Thread(Read);
  25. t.IsBackground = true;
  26. t.Start();
  27. }
  28.  
  29. public void Write()
  30. {
  31. string name = System.DateTime.Now.ToString();
  32. //插入数据的时候,连接字符串不指定ReadOnly
  33. string connectStrW = "Data Source=tcp:193.160.26.30,1433;Initial Catalog=test;Integrated Security=True;MultiSubnetFailover=True";
  34.  
  35. int count = Convert.ToInt32(textBox4.Text);
  36.  
  37. using (SqlConnection conn = new SqlConnection(connectStrW))
  38. {
  39. for (var i = ; i <= count; i++)
  40. {
  41. conn.Open();//打开数据库
  42. //创建数据库命令
  43. SqlCommand cmd = conn.CreateCommand();
  44. //创建查询语句 在写的操作过程中,写之前先读操作,测试不加ReadOnly时候只读路由有没有效果
  45. cmd.CommandText = "select count(*) from test1";
  46. int x = (int)cmd.ExecuteScalar();
  47. //创建查询语句
  48.  
  49. Thread.Sleep();
  50. cmd.CommandText = "Insert into test1 values" + '(' + '\'' + name + '\'' + ')';
  51. cmd.ExecuteNonQuery();
  52. textBox1.Text = (x + i).ToString();
  53. conn.Close();
  54. }
  55. }
  56.  
  57. }
  58.  
  59. public void Read()
  60. { //查询数据的时候,连接字符串指定ReadOnly
  61. string connectStr = "Data Source=tcp:193.160.26.30,1433;Initial Catalog=test;Integrated Security=True;ApplicationIntent=ReadOnly;MultiSubnetFailover=True";
  62.  
  63. int count = Convert.ToInt32(textBox4.Text);
  64.  
  65. for (var j = ; j <= count; j++)
  66. {
  67. Thread.Sleep();
  68. using (SqlConnection conn = new SqlConnection(connectStr))
  69. {
  70. conn.Open();//打开数据库
  71. //创建数据库命令
  72. SqlCommand cmd = conn.CreateCommand();
  73. //创建查询语句
  74. cmd.CommandText = "select count(*) from test1";
  75. int x = (int)cmd.ExecuteScalar();
  76. textBox2.Text = x.ToString();
  77. conn.Close();
  78. }
  79. }
  80.  
  81. }
  82.  
  83. }
  84. }

检测结果:
开始之前,打开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. 射频识别技术漫谈(4)——数据编码【worldsing 笔记】

    前已述及,射频识别技术中的调制方法一般使用调幅(AM),也就是将有用信号调制在载波的幅度上传送出去.这里的"有用信号"指用高低电平表示的数据"0"或" ...

  2. SpringMVC(一)

    开始学习SpringMVC了,就写下每次学习的内容,以及自己的理解.方便以后回顾知道自己哪里好哪里不好~~~ 一.目录 1.主目录如此: 2.target目录 二.文件 1.主要用到的几个文件夹(如主 ...

  3. 在idea中如何添加log日志

    1.首先下载log4的jar包,官方路径为:http://www.apache.org/dyn/closer.cgi/logging/log4j/1.2.17/log4j-1.2.17.zip 2.下 ...

  4. fastica matlab 转载

    FastICA工具箱1 http://chunqiu.blog.ustc.edu.cn/?p=68#comment-3512 FastICA代码网址如下:http://research.ics.aal ...

  5. 【转】linux中的cut/tr/join/split/xargs命令

    1. cut命令 cut命令用于从文件或者标准输入中读取内容并截取每一行的特定部分并送到标准输出. 截取的方式有三种:一是按照字符位置,二是按照字节位置,三是使用一个分隔符将一行分割成多个field, ...

  6. jqueryui.position.js源代码分析

    近期要写前端组件了.狂砍各种组件源代码,这里分析一款jqueryui中的posistion插件,注意,它不是jqueryui widget,首先看下源代码整体结构图 1.看到$.fn.position ...

  7. 【转】C++对象内存分配问题

    原文:http://blog.csdn.net/c504665913/article/details/7797859 如果一个人自称为程序高手,却对内存一无所知,那么我可以告诉你,他一定在吹牛.用C或 ...

  8. JS字符处理

    JS取整 1.toFixed(num)(ps:num为保留小数点后几位) 自定义保留小数点后几位,进行四舍五入.严格来说,这个函数不属于取整,但是当num=0时,也就是取整了,所以一起放到这里,方便查 ...

  9. WINAPI 变量(2861个)

    WINAPI 变量(2861个)   这是从 c:\Program Files\Windows Kits\8.1\Include\um\WinUser.h 这个文件 中提取的 CTRL+F 查看变量所 ...

  10. iOS开发——数据持久化Swift篇&通用文件存储

    通用文件存储 import UIKit class ViewController: UIViewController { @IBOutlet weak var textField: UITextFie ...