Linux 上配置 SQL Server Always On Availability Group

时间:2023-12-04 11:21:20

SQL Server Always On Availability Group 配置
步骤:
配置三台 Linux 集群节点
创建 Availability Group
配置 Cluster Resource Manager, 比如 Pacemaker
在集群中添加 Availability Groups
详细解说
1. 配置三台 Linux 集群节点
在集群中的三台服务器之间可以互相通信
安装 SQL Server
在 Linux 上,往集群管理器中添加集群资源时,一定是先建立集群资源,接着将新建的资源加入到集群中去。

所以建立 SQL Server Always On Availability Groups 也一样,先建立 AG, 完了之后添加到集群管理器( Cluster Manager )中去。

三台节点之间可以相互通信,该如何了解?

使用 ssh 可以相互无障碍地登录

设置每台计算机的机器名
加入同一个域
配置 RSA 使得无密码 ssh 登录
1 设置每台计算机的机器名

vi /etc/hostname
1
分别设置为 centos00, centos01, centos02.

centos00 为主库所在服务器节点

2 加入同一个域

作用就是了互相识别,假如 node1 , node2, node3 是我们新建的三台集群服务器,互为 Availability Groups 成员,且 node1 是主库,node2, node3 为从库,三台机器之间互相识别的方法有两种,一是加入同一个域; 二是在各自的 /etc/hosts 文件中,添加机器名和 IP 地址的映射:

127.0.0.1 localhost
::1 localhost

192.168.1.10 centos00
192.168.1.11 centos01
192.168.1.12 centos02
1
把以上的配置脚本放入各自服务器的 /etc/hosts 中去,不需要配置域即可互相识别。

安装 SQL Server 已有介绍,不展开了

2. 启动 AlwaysOn Availability Group 特性
/opt/mssql/bin/mssql-conf set hadr.hadrenabled 1
systemctl restart mssql-server
1
可以检查服务器是否启用了 hadr :

select serverproperty('HadrManagerStatus')
1
适用于: SQL Server 2012 (11.x) through SQL Server 2017.

提示 SQL Server 是否启用了高可用灾备特性:

0 = Not started, pending communication.

1 = Started and running.

2 = Not started and failed.

NULL = Input is not valid, an error, or not applicable.

开启 AlwaysOn_health 扩展事件(Extended Events),用来检测 Always On Availability Group 的故障所在:

ALTER EVENT SESSION  AlwaysOn_health ON SERVER WITH (STARTUP_STATE=ON);
GO
1
在每一台节点实例上都开启 AlwaysOn_health 扩展事件。

关于如何使用 AlwaysOn_health 扩展事件,另开一篇文章解释,详见有道与笔记中 SQL Server 目录下 eXtended Events(XE) 的操作文档。

3. 新建证书 (certificate)
证书(Certificate)的作用,是为了让 SQL Server Mirroring Endpoints 之间可以相互通信。

理念和两台 Linux 服务器之间无密通信一样,一个公钥,一个私钥。公钥用来核实私钥的有效性,分发到各个服务器上,作为访问远程服务的凭证。

新建 master key :

create master key encryption by password='MasterKey123.'
1
create master key 是 T-SQL 命令,不能直接在 shell 里面运行!

新建证书:

create certificate dbm_certificate with subject='dbm'
1
backup certificate dbm_certificate 
    to file='/var/opt/mssql/data/dbm_certificate.cer'
    with private key(
        file='/var/opt/mssql/data/dbm_certificate.pvk',
        encryption by password='PrivateKey123.')
1
现在有了公钥,私钥和证书,则需要保证所有的集群节点都有私钥和证书,如果没有则复制私钥和证书到相同目录下,以便之后的安装证书。

所以配置 AG 时,复制 dbm_certificate.cer, dbm_certificate.pvk 到其他两台节点相同目录下。

cd /var/opt/mssql/data
scp dbm_certificate.* root@centos01: /var/opt/mssql/data/
scp dbm_certificate.* root@centos02: /var/opt/mssql/data/
1
把这两个文件的权限赋给运行 ms sql server 服务的账户 mssql:

chown mssql:mssql dbm_certificate.*
1
4. 还原从库的证书
从库已经有了主库私钥的副本,这些副本可以还原出证书

create master key encryption by password='MasterKey123.'

create certificate dbm_certificate
    from file='/var/opt/mssql/data/dbm_certificate.cer'
    with private key(
        file='/var/opt/mssql/data/dbm_certificate.pvk',
        decryption by password='PrivateKey123.')
1
在所有的从库都执行上述的脚本,来创建证书。

其中会遇到一点小麻烦:

Msg 15208, Level 16, State 6, Server centos02, Line 1
The certificate, asymmetric key, or private key file is not valid or does not exist; or you do not have permissions for it.
1
mssql 是用来运行 sql server on linux 的账户,因此他需要被赋予可以访问证书和私钥文件的权限。

chown mssql:mssql dbm_certificate.*
1
证书是从主库上“移栽”过去的,那么从库是否也需要搭建自己的证书,“移栽”给主库使用呢?

5. 新建 mirroring endpoints
SQL Server AG 节点之间使用 TCP 通信,通过指定的端口传送消息。

create endpoint hadr_endpoint
    as TCP(Listener_port=5022)
    for database_mirroring (
        role=all,
        authentication=certificate dbm_certificate,
        encryption = required algorithm aes      
    )

alter endpoint hadr_endpoint state = started
1
打开 防火墙对 endpoint 对应的端口的支持。

firewall-cmd --zone=public --add-port=5022/tcp --permanent
    firewall-cmd --reload
1
6. 新建 AG (Availability Groups)
两种新建 AG 的方法:

3 份同步副本 (Three synchronous replicas)
2 份同步副本 + 1份配置副本(Two synchronous replicas plus a configuration replica)
这两种方法都可以保护数据和实现高可用性,但 3份同步副本的方法更能在主库失效的情况下,做出自动切换的动作,等待老主库回线之后,继续事务操作。

如果仅仅是实现保护数据的目的,那么直接采用 2 副本即可,还省去了集群管理器的配置。

搭建三副本同步的脚本:

create availability group [crmag]
    with (db_failover=on,cluster_type=external)
    for replica on 
        N'centos00'
        with (
            endpoint_url = N'tcp://centos00:5022',
            availability_mode=synchronous_commit,
            failover_mode=external,
            seeding_mode=automatic
            ),
         N'centos01'
        with (
            endpoint_url = N'tcp://centos01:5022',
            availability_mode=synchronous_commit,
            failover_mode=external,
            seeding_mode=automatic
            ),
         N'centos02'
        with (
            endpoint_url = N'tcp://centos02:5022',
            availability_mode=synchronous_commit,
            failover_mode=external,
            seeding_mode=automatic
            );

alter availability group [crmag]
        grant create any database ;
1
我们在这里指定了 external 的集群管理方式,那么就需要在 Linux 上安装独立的集群管理软件,通常用 Pacemaker. 但理论上也应该有其他的集群管理软件,比如 Mesos, Linux Cluster Manager(LCM) 等。

这是配置 Availability Group 中比较重要的一大步,有必要在这一步做一些测试来提早预知,是不是配置得有问题。

endpoint_url 被配置成了 namepipeline, 我觉得有必要修改一下:

create availability group [crmag]
    with (db_failover=on,cluster_type=external)
    for replica on 
        N'192.168.1.10'
        with (
            endpoint_url = N'tcp://192.168.1.10:5022',
            availability_mode=synchronous_commit,
            failover_mode=external,
            seeding_mode=automatic
            ),
         N'192.168.1.11'
        with (
            endpoint_url = N'tcp://192.168.1.11:5022',
            availability_mode=synchronous_commit,
            failover_mode=external,
            seeding_mode=automatic
            ),
         N'192.168.1.12'
        with (
            endpoint_url = N'tcp://192.168.1.12:5022',
            availability_mode=synchronous_commit,
            failover_mode=external,
            seeding_mode=automatic
            );

alter availability group [crmag]
        grant create any database ;
1
理论上所有 availability_mode 标记是 synchronous_commit 的节点,都需要同步完成之后,主库的事务才能被正确提交。但有一个参数可以控制从库副本同步的最小数量 - Required_Synchronized_Secondaries_To_Commit. 上面的配置看上去是要 2 个从库都同步之后,事务才会在主库提交,但如果配置了 required_synchronized_secondaries_to_commit 为1, 则只需要一台从库同步即可。

7. 连接从库与添加 AG 数据库
连接从库:

需要将集群中的从库,添加到 AG 中来,在每个从库上执行下面的命令:

ALTER AVAILABILITY GROUP [crmag]
    Join WITH(cluster_type=external);

ALTER AVAILABILITY GROUP [crmag]
    Grant Create Any Database ;
1
添加 AG 数据库:

选择性的添加我们要同步的数据库,使其实现三副本同步:

create database [crm];
alter database [crm] set recovery full ;

backup database [crm]
    to disk = N'/var/opt/mssql/data/crm.bak';

alter availability group [crmag]
    add database [crm]
1
验证同步情况:

select db_name(database_id)  as 'database'
    ,   synchronization_state_desc
from sys.dm_hadr_database_replica_states ;
1
到这里,数据库只是同步了名字,但数据表等还没有彻底完成节点之间的同步。

8. Pacemaker 的安装
在配置完毕 AG 的时候,一定要配置 Pacemaker.

以下六个步骤除了 pcs 第5步,其他都需要在集群中的每台节点上运行。

详细构建与解说可以查看【参考文章】。

1. 大致需要安装 2个软件和 1 个工具:

Pacemaker
Corosync
Pcsd
默认情况下,这三个软件都在自带的 repository 库中配置好了,只要执行安装即可:

yum install -y pacemaker,corosync,pcs
1
pcsd 是 pacemaker 的客户端命令执行程序,任何的功能都需要 pcsd 来启动和设置,pacemaker 是服务程序。当 pcsd, pacemaker 都配置好之后,使用命令 pcs 就可以用来和 pacemaker 交互了。所以 pcs 才是真正执行集群管理的程序软件,只要在其中一台节点上运行 pcs, 命令即将被送到各个节点去运行。

从安装的日志分析, corosync 会在安装 pacemaker 的时候一起安装,因此不需要特别去单独安装。pcs 是需要独立安装的。

MSDN 文档中规定,还需要安装额外的两个程序:

yum install -y fence-agents-all resource-agents
1
但 fency-agents-all 没有找到安装包,而 resource-agents 却已经安装完毕了。

2. 开启防火墙端口

firewall-cmd --permanent --add-service=high-availability
firewall-cmd --reload
1
如果没有 high availability 的配置,也可以指定端口:

TCP:ports 2224,3121,21064

UDP:port 5405

3. 设置用户密码

这个用户非常重要,他是创建集群的账户,有了他的存在,集群才能运行起来,和 sql server 安装用户要区分开来,实际上这两个用户需要分开建。

passwd hacluster
1
为了方便这里的用户密码和 sa 密码一致!

开启集群的重启回线设置
当节点失效了,修复后需要重新回到集群,这叫做回线。此功能需要设置:

systemctl enable pcsd 
systemctl start pcsd
systemctl enable pacemaker
1
5. 建立集群

pcs cluster auth centos00 centos01 centos02 -u hacluster -p l****n****6.

pcs cluster setup --name crmcluster centos00 centos1 centos02

pcs cluster start --all 
pcs cluster enable --all
1
配置授权的程序运行过长,而且中间经常有错误,比如失联,timeout等。尝试着多联几遍,发现效果并不理想,始终有一台机器失联。

所以尝试着想单台计算机节点去授权:

[huangyun@centos00 ~]$ pcs cluster auth centos00
Username: hacluster
Password: 
Please authenticate yourself to the local pcsd
Username: huangyun
Password: 
Port (default: 2224): 
Error: Access denied
1
换成 root.

###### 小结下集群的主要步骤:

pcs 的程序只要在其中一台运行即可

5.1 开启 pcs 程序:

systemctl enable pcsd
systemctl start pcsd
systemctl enable pacemaker

** 每台节点都需要执行
1
5.2 授权节点

pcs cluster auth centos00 centos01 centos02 -u hacluster -p l****n****6.
1
更建议换成:

pcs cluster auth centos00 centos01 centos02
1
5.3 设置集群属性: 集群名,节点名

pcs cluster setup --name crmcluster centos00 centos1 centos02
1
[root@centos00 huangyun]# pcs cluster setup --name crmcluster centos00 centos01 centos02
Destroying cluster on nodes: centos00, centos01, centos02...
centos02: Stopping Cluster (pacemaker)...
centos01: Stopping Cluster (pacemaker)...
centos00: Stopping Cluster (pacemaker)...
centos01: Successfully destroyed cluster
centos02: Successfully destroyed cluster
centos00: Successfully destroyed cluster

Sending 'pacemaker_remote authkey' to 'centos00', 'centos01', 'centos02'
centos00: successful distribution of the file 'pacemaker_remote authkey'
centos02: successful distribution of the file 'pacemaker_remote authkey'
centos01: successful distribution of the file 'pacemaker_remote authkey'
Sending cluster config files to the nodes...
centos00: Succeeded
centos01: Succeeded
centos02: Succeeded

Synchronizing pcsd certificates on nodes centos00, centos01, centos02...
centos00: Success
centos01: Success
centos02: Success
Restarting pcsd on the nodes in order to reload the certificates...
centos02: Success
centos00: Success
centos01: Success
1
5.4 开启集群服务

pcs cluster start 
pcs cluster enable 
1
6 安装 sql server resource agent

yum install mssql-server-ha
1
7. 配置 fencing(STONITH)

fencing 的作用是让失效的节点回线,一旦节点故障离线了,fencing 会引导节点重新回到集群。

STONITH: shoot the other node in the head

常规情况,fencing 特性是必须要在集群的节点中启动的。但如果处于测试的目的,可以不启动。可以尝试着去启动它,对于以后部署圣餐环境,是有好处的,相当于一次生产环境中部署的演练。在本文中为了方便快捷的部署,先将其关闭。

fencing 可以从两方面进行集群资源的控制,一是节点本身,二是节点上提供的资源,比如硬盘,SQL 服务等。

针对节点本身一级的控制:

pcs property set stonith-enabled=false
1
问题:

1 集群管理器(Cluster Manager)为什么不能集成 fencing 的功能?

2 集群资源与集群管理器之间的互动,依靠什么来接口?

3 fencing 的实现

8 集群“心跳”的设置

“心跳”(Heart Beat)的概念,在这里是指集群节点之间互相通信,检查健康状态和集群属性变更的机制。通过设置集群属性 cluster-recheck-interval 来确定“心跳” 的时间间隔。

一旦集群中的某一个节点下线(不能互相通信),集群管理器可以尝试着在一段时间(failure-timeout)后去重启这台节点。如果在这段时间内节点又有反应(能与集群互相通信)了,那么在接收到这个回线的信号之后,就取消重启先前标记为下线的节点。

pcs property set cluster-recheck-interval=2min
1
不建议把 cluster-recheck-interval 设置的过短,比如 60s; 一般 failure-timeout 可以设置的短一些,60s, 而 cluster-recheck-interval 要设置的比 failure-timeout 长一些。

pcs resource update [crmag] meta failure-timeout=60s
1
9 为 Pacemaker 设置 SQL Server Login 账户

use master 
go

CREATE LOGIN PaceMaker WITH PASSWORD='PMLoginPass123.'
ALTER SERVER ROLE sysadmin ADD MEMBER PaceMaker

GO
1
在每一台集群实例上都执行上面的命令。

[root@centos00 secrets]# cat login.bat
echo 'PaceMaker' >> ~/pacemaker-passwd
echo 'PMLoginPass123.' >> ~/pacemaker-passwd
mv ~/pacemaker-passwd /var/opt/mssql/secrets/passwd
chown root:root /var/opt/mssql/secrets/passwd
chmod 400 /var/opt/mssql/secrets/passwd
1
在每一台集群节点上执行上述脚本

10 创建 AG (Availability Groups)集群资源

pcs resource create crmag_cluster ocf:mssql:ag ag_name=crmag meta failure-timeout=30s master notify=true
1
11 创建虚拟 IP 地址

pcs resource create virtualip ocf:heartbeat:IPaddr2 ip=192.168.1.15
1
与我们的 SQL Server 实例所在节点的网段一致。

12 Add colocation constraint

pcs constraint colocation add virtualip crmag_cluster-master INFINITY with-rsc-role=master
1
INFINITY 一定是大写,但还是会遇到以下错误:

Error: Unable to update cib
Call cib_replace failed (-203): Update does not conform to the configured schema
<cib crm_feature_set="3.0.14" validate-with="pacemaker-2.10" epoch="10" num_updates="0" admin_epoch="0" cib-last-written="Tue Aug 21 23:16:35 2018" update-origin="centos00" update-client="cibadmin" update-user="root" have-quorum="0" dc-uuid="1">
  <configuration>
    <crm_config>
      <cluster_property_set id="cib-bootstrap-options">
        <nvpair id="cib-bootstrap-options-have-watchdog" name="have-watchdog" value="false"/>
        <nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="1.1.18-11.el7_5.3-2b07d5c5a9"/>
        <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"/>
        <nvpair id="cib-bootstrap-options-cluster-name" name="cluster-name" value="crmcluster"/>
        <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="false"/>
        <nvpair id="cib-bootstrap-options-cluster-recheck-interval" name="cluster-recheck-interval" value="2min"/>
      </cluster_property_set>
    </crm_config>
    <nodes>
      <node id="1" uname="centos00"/>
      <node id="2" uname="centos01"/>
      <node id="3" uname="centos02"/>
    </nodes>
    <resources>
      <master id="crmag_cluster-master">
        <primitive class="ocf" id="crmag_cluster" provider="mssql" type="ag">
          <instance_attributes id="crmag_cluster-instance_attributes">
            <nvpair id="crmag_cluster-instance_attributes-ag_name" name="ag_name" value="crmag"/>
          </instance_attributes>
          <meta_attributes id="crmag_cluster-meta_attributes">
            <nvpair id="crmag_cluster-meta_attributes-failure-timeout" name="failure-timeout" value="30s"/>
          </meta_attributes>
          <operations>
            <op id="crmag_cluster-demote-interval-0s" interval="0s" name="demote" timeout="10"/>
            <op id="crmag_cluster-monitor-interval-10" interval="10" name="monitor" timeout="60"/>
            <op id="crmag_cluster-monitor-interval-11" interval="11" name="monitor" role="Master" timeout="60"/>
            <op id="crmag_cluster-monitor-interval-12" interval="12" name="monitor" role="Slave" timeout="60"/>
            <op id="crmag_cluster-notify-interval-0s" interval="0s" name="notify" timeout="60"/>
            <op id="crmag_cluster-promote-interval-0s" interval="0s" name="promote" timeout="60"/>
            <op id="crmag_cluster-start-interval-0s" interval="0s" name="start" timeout="60"/>
            <op id="crmag_cluster-stop-interval-0s" interval="0s" name="stop" timeout="10"/>
          </operations>
        </primitive>
        <meta_attributes id="crmag_cluster-master-meta_attributes">
          <nvpair id="crmag_cluster-master-meta_attributes-notify" name="notify" value="true"/>
        </meta_attributes>
      </master>
      <primitive class="ocf" id="virtualip" provider="heartbeat" type="IPaddr2">
        <instance_attributes id="virtualip-instance_attributes">
          <nvpair id="virtualip-instance_attributes-ip" name="ip" value="192.168.1.15"/>
        </instance_attributes>
        <operations>
          <op id="virtualip-monitor-interval-10s" interval="10s" name="monitor" timeout="20s"/>
          <op id="virtualip-start-interval-0s" interval="0s" name="start" timeout="20s"/>
          <op id="virtualip-stop-interval-0s" interval="0s" name="stop" timeout="20s"/>
        </operations>
      </primitive>
    </resources>
    <constraints>
      <rsc_colocation id="colocation-virtualip-crmag_cluster-master-INFINITY" rsc="virtualip" score="INFINITY" with-rsc="crmag_cluster-master" with-rsc-role="master"/>
    </constraints>
  </configuration>
  <status>
    <node_state id="1" uname="centos00" in_ccm="true" crmd="online" crm-debug-origin="do_update_resource" join="member" expected="member">
      <lrm id="1">
        <lrm_resources>
          <lrm_resource id="crmag_cluster" type="ag" class="ocf" provider="mssql">
            <lrm_rsc_op id="crmag_cluster_last_0" operation_key="crmag_cluster_stop_0" operation="stop" crm-debug-origin="do_update_resource" crm_feature_set="3.0.14" transition-key="4:19:0:bbe48c11-1fd4-4db4-8a3c-2387213b6920" transition-magic="0:0;4:19:0:bbe48c11-1fd4-4db4-8a3c-2387213b6920" exit-reason="" on_node="centos00" call-id="11" rc-code="0" op-status="0" interval="0" last-run="1534864258" last-rc-change="1534864258" exec-time="379" queue-time="0" op-digest="049982ab688a8b6b8895d94c57abc084"/>
            <lrm_rsc_op id="crmag_cluster_last_failure_0" operation_key="crmag_cluster_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.0.14" transition-key="2:18:7:bbe48c11-1fd4-4db4-8a3c-2387213b6920" transition-magic="0:8;2:18:7:bbe48c11-1fd4-4db4-8a3c-2387213b6920" exit-reason="" on_node="centos00" call-id="6" rc-code="8" op-status="0" interval="0" last-run="1534864251" last-rc-change="1534864251" exec-time="5697" queue-time="0" op-digest="049982ab688a8b6b8895d94c57abc084"/>
            <lrm_rsc_op id="crmag_cluster_pre_notify_demote_0" operation_key="crmag_cluster_notify_0" operation="notify" crm-debug-origin="do_update_resource" crm_feature_set="3.0.14" transition-key="39:19:0:bbe48c11-1fd4-4db4-8a3c-2387213b6920" transition-magic="-1:193;39:19:0:bbe48c11-1fd4-4db4-8a3c-2387213b6920" exit-reason="" on_node="centos00" call-id="-1" rc-code="193" op-status="-1" interval="0" last-run="1534864257" last-rc-change="1534864257" exec-time="0" queue-time="0" op-digest="049982ab688a8b6b8895d94c57abc084"/>
            <lrm_rsc_op id="crmag_cluster_post_notify_demote_0" operation_key="crmag_cluster_notify_0" operation="notify" crm-debug-origin="do_update_resource" crm_feature_set="3.0.14" transition-key="40:19:0:bbe48c11-1fd4-4db4-8a3c-2387213b6920" transition-magic="-1:193;40:19:0:bbe48c11-1fd4-4db4-8a3c-2387213b6920" exit-reason="" on_node="centos00" call-id="-1" rc-code="193" op-status="-1" interval="0" last-run="1534864258" last-rc-change="1534864258" exec-time="0" queue-time="0" op-digest="049982ab688a8b6b8895d94c57abc084"/>
            <lrm_rsc_op id="crmag_cluster_pre_notify_stop_0" operation_key="crmag_cluster_notify_0" operation="notify" crm-debug-origin="do_update_resource" crm_feature_set="3.0.14" transition-key="38:19:0:bbe48c11-1fd4-4db4-8a3c-2387213b6920" transition-magic="-1:193;38:19:0:bbe48c11-1fd4-4db4-8a3c-2387213b6920" exit-reason="" on_node="centos00" call-id="-1" rc-code="193" op-status="-1" interval="0" last-run="1534864258" last-rc-change="1534864258" exec-time="0" queue-time="0" op-digest="049982ab688a8b6b8895d94c57abc084"/>
          </lrm_resource>
          <lrm_resource id="virtualip" type="IPaddr2" class="ocf" provider="heartbeat">
            <lrm_rsc_op id="virtualip_last_0" operation_key="virtualip_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.0.14" transition-key="2:21:7:bbe48c11-1fd4-4db4-8a3c-2387213b6920" transition-magic="0:7;2:21:7:bbe48c11-1fd4-4db4-8a3c-2387213b6920" exit-reason="" on_node="centos00" call-id="15" rc-code="7" op-status="0" interval="0" last-run="1534864392" last-rc-change="1534864392" exec-time="111" queue-time="0" op-digest="0dd9b6f76349bef9fdd7ec198ed70063"/>
          </lrm_resource>
        </lrm_resources>
      </lrm>
      <transient_attributes id="1">
        <instance_attributes id="status-1">
          <nvpair id="status-1-master-crmag_cluster" name="master-crmag_cluster" value="20"/>
        </instance_attributes>
      </transient_attributes>
    </node_state>
  </status>
</cib>
1
而正确的写法却是:

pcs constraint colocation add virtualip crmag_cluster-master INFINITY with-rsc-role=Master
1
大小写敏感!

13 排序约束

pcs constraint order promote crmag_cluster-master then start virtualip
> Adding crmag_cluster-master virtualip (kind: Mandatory) (Options: first-action=promote then-action=start)
1
注意点:
集群资源管理器:
Cluster Resource Manager 比如 Pacemaker

主从库架构配置:
SQL Server Standard 版本只能支持一主一从架构,除了高可用之外,并不支持只读操作,而 Enterprize 版本则可以支持 9 个副本架构,至多 3 个主库,8个从库结构。

集群种类以及故障转移模式:
Cluster Type 是 SQL Server 2017 来新进的特性,有 External 和 None 之分。

External 采用了 Pacemaker 配置。在这种配置下, FailOver 模式也必须是 External( 因此 Failover Mode 也是 SQL Server 2017 以来最新特性, 另外一种模式是 Automatic ).

None 就是不采用 Pacemaker 配置,即便服务器上配置了 Pacemaker, 只要不在 SQL Server AG 中配置 None, 也不会使用 Pacemaker 服务。

从库同步数量 :
required_synchronized_secondaries_to_commit:

AG 使用的配置中,最重要的一个便是它。它控制了与主库强一致性同步的副本数。设置了正确的值,自动故障转移才能顺利执行。根据《Design Data-Intensive Applications》书中介绍,主库的数据可以同步给多个从库,以保证高可用性。在这里,从库的设置便是使用了这个配置,所以它的值可以是以下 3 个:

0 - 没有设置必须同步的从库,自然不能在主库失效的情况下,自动切换从库为主库;

1 - 设置一个从库与主库保持同步,一旦主库失效就可以自动切换负载到从库上;

2 - 设置 2 个同步从库,如同 1 一样,可以自动切主从库。

关于这个主题,可以参考这篇文章,细节谈的更多:

Understand SQL Server resource agent for pacemaker

https://docs.microsoft.com/en-us/sql/linux/sql-server-linux-availability-group-ha?view=sql-server-2017#pacemakerNotify

Always On Availability Groups on Linux

https://docs.microsoft.com/en-us/sql/linux/sql-server-linux-availability-group-overview?view=sql-server-2017

随着阅读的深入,就像 Understand SQL Server resource agent for pacemaker 讲的那样,required_synchronized_secondaries_to_commit 指定的数值,并不仅仅是确切的同步副本数量,而是同步副本的数量 / 2 ,即如果集群的同步服务器数量是 3,那么required_synchronized_secondaries_to_commit 就被设置为 1。

这个设置在任何时间都有可能被修改,比如监控节点健康状态时,发现有节点失效了,就要重新计算。3台节点组成的集群,如果其中一个 secondary 节点失效了,那么就会重新计算和保存 required_synchronized_secondaries_to_commit 为1,即在从库副本数据没有更新完之前,主库是不可被访问的。 体现了副本对于可用性与数据保护的影响。

案例:

假如我们的集群是有 8 台节点组成的,其中 1 台是主库, 2 台是同步从库,剩下 5 台是副本节点。那么主库与同步从库之间的数据,始终是保持一致的,那么当其中一台从库失效之后,那么实际上只需要保持一台同步从库同步数据即可,此时 required_synchronized_secondaries_to_commit 即被 Pacemaker Resource Agent 强制设置为 1了。

而当主库失效的时候,必须要有同步库(包括主库和从库)数量减去 required_synchronized_secondaries_to_commit 数量来决定,收到多少个从库的回应,推选主库是有效的。

这里就要思考,如何指定 AG 架构是由 3台同步库(1主2从)组成的?

集群管理器:
集群由一组计算机组成,它提供了高可用和高并发架构。在 SQL Server 中集群的作用是高可用,即所有的工作负载都是引导到一台主机上,如果这台主机失效了,再切换到另一台主机上;在 Oracle RAC 集群中,则是多台计算机共同分担一部分工作负载,如果其中一台主机失效了,会自动切换到那台主机配对的从库上,以此同时保证高可用与高并发。

所以为 SQL Server 搭建的集群,集群管理器负责的事情就是判断失效以及之后的故障转移切换。

扩展下,如何保证集群管理器本身的高可用性?

如果仅仅是配置读写分离,那么可以不用依靠 集群管理器(Cluster Manager), 而仅仅配置 Read-Scale replica.

当然我们这里讨论的是对高可用环境搭建的流程,只读扩展(Read-Scale Replicas) 并不在讨论范围内。3 个同步库的搭建可以完成自动恢复节点,而不仅仅是自动故障时效转移。

测试用例:
实现故障自动切换

每一步配置过后,增加测试配置正确与否的步骤

在最终配置完毕 Availability Groups 的时候,发现数据库对象并不在 3 台集群节点之间同步,而且经常是 3 台节点上的 Availability Groups 中的数据库都无法访问了。

比如遇到新建的 CRMAG Availability Groups 一直对主库进行解析:

The state of the local availability replica in availability group ‘crmag’ has changed from ‘NOT_AVAILABLE’ to ‘RESOLVING_NORMAL’. The state changed because the local instance of SQL Server is starting up. For more information, see the SQL Server error log or cluster log. If this is a Windows Server Failover Clustering (WSFC) availability group, you can also see the WSFC management console.

从 Log 中发现了有趣的事件,即参加了 availability group 的数据库,并不是随着 instance 的启动而启动了,必须由 availaibility group 启动它。

2018-08-21 23:33:57.31 spid20s Skipping the default startup of database ‘crm’ because the database belongs to an availability group (Group ID: 65536). The database will be started by the availability group. This is an informational message only. No user action is required.

将所有的 extened events 记录的文件,都拿过来查查错,发现:

Network error code 0x102 occurred while establishing a connection; the connection has been closed. This may have been caused by client or server login timeout expiration. Time spent during login: total 97036 ms, enqueued 0 ms, network writes 0 ms, network reads 0 ms, establishing SSL 97034 ms, network reads during SSL 96934 ms, network writes during SSL 0 ms, secure calls during SSL 100 ms, enqueued during SSL 0 ms, negotiating SSPI 0 ms, network reads during SSPI 0 ms, network writes during SSPI 0 ms, secure calls during SSPI 0 ms, enqueued during SSPI 0 ms, validating login 0 ms, including user-defined login processing 0 ms. [CLIENT: 192.168.1.6]

与 Windows 下安装的异同:
Microsoft Distributed Transaction Coordinator(DTC) 还不能支持 Linux 版本的 SQL Server 2017 ,因此需要分布式事务的集群部署,还是要架构在 Windows 平台上

Linux 版本的 SQL Server 部署,使用的是 Pacemaker , 而不是 WSFC(windows server failover cluster). Pacemaker 不需要 Active Directory Domain Services(AD DS)

实现故障切换各有各自的方法

有些特定属性 比如 required_synchronized_secondaries_to_commit 只能通过 Pacemaker 来实现,而在 Windows 上是通过 T-SQL 也能实现的

参考文章:

MSDN 文档: https://docs.microsoft.com/en-us/sql/linux/sql-server-linux-setup?view=sql-server-2017
云和恩墨张乐奕的文章:https://blog.csdn.net/enmotech/article/details/80267170
https://docs.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker?view=sql-server-2017
SQL Server 镜像下载: https://packages.microsoft.com/
介绍在 Centos 上安装 SQL Server 的文章: https://www.rootusers.com/how-to-install-microsoft-sql-server-on-linux/
How to Set up Nginx High Availability with Pacemaker and Corosync on CentOS7 : https://www.howtoforge.com/tutorial/how-to-set-up-nginx-high-availability-with-pacemaker-corosync-on-centos-7
MSDN 官方文档之 - Always On Availability Groups on Linux : https://docs.microsoft.com/en-us/sql/linux/sql-server-linux-availability-group-overview?view=sql-server-2017
MSDN 官方文档之 - An overview of High Availability and Disaster Recovery solutions available for SQL Server https://blogs.msdn.microsoft.com/sql_pfe_blog/2013/06/15/an-overview-of-high-availability-and-disaster-recovery-solutions-available-for-sql-server/
配置 AG 过程遇到的问题集合:
1 两台建立在 台机上的 VM Ware 虚拟机,各自拥有一个 SQL Server 实例,且充当了集群中的从库副本;一台建立在笔记本上的 VM Ware 虚拟机,则充当了集群中的主库副本。在没有安装 pacemaker 的时候,主库上建立的数据库对象,总是不能实时的同步到2个从库中去,且2个从库的同步数据库总是处理不可访问的状态

消息 976,级别 14,状态 1,第 1 行
The target database, 'crm', is participating in an availability group and is currently not accessible for queries. Either data movement is suspended or the availability replica is not enabled for read access. To allow read-only access to this and other databases in the availability group, enable read access to one or more secondary availability replicas in the group.  For more information, see the ALTER AVAILABILITY GROUP statement in SQL Server Books Online.
1
2 使用台机上的 SSMS 可以无障碍的连接到从库,但连接主库总是掉线。而笔记本上的 SOS(Sql Operation Studio)连接3台都没事。不禁猜想,是主库的某一些设置,导致同步失效。

已成功与服务器建立连接,但是在登录过程中发生错误。 (provider: TCP Provider, error: 0 - 你的主机中的软件中止了一个已建立的连接。) (.Net SqlClient Data Provider)

有关帮助信息,请单击: http://go.microsoft.com/fwlink?ProdName=Microsoft%20SQL%20Server&EvtSrc=MSSQLServer&EvtID=10053&LinkId=20476

服务器名称: 192.168.1.10
错误号: 10053
严重性: 20
状态: 0

程序位置:

在 System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, DbConnectionPool pool, String accessToken, Boolean applyTransientFaultHandling, SqlAuthenticationProviderManager sqlAuthProviderManager)
在 System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
在 System.Data.ProviderBase.DbConnectionFactory.CreateNonPooledConnection(DbConnection owningConnection, DbConnectionPoolGroup poolGroup, DbConnectionOptions userOptions)
在 System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
在 System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
在 System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
在 System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
在 System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
在 System.Data.SqlClient.SqlConnection.Open()
在 Microsoft.SqlServer.Management.SqlStudio.Explorer.ObjectExplorerService.ValidateConnection(UIConnectionInfo ci, IServerType server)
在 Microsoft.SqlServer.Management.UI.ConnectionDlg.Connector.ConnectionThreadUser()
1
但也有可能是 SSMS 17 是比较新的版本,因此不是很稳定,第二次连接就连上了。

主库服务器启动后,接着启动从库的服务器,传输消息失败
Aug 23 07:02:03 centos01 sqlservr[1272]: [HADR TRANSPORT] AR[8FA8354D-F40F-44EF-A648-722A0ED4F90F]->[071D8AF0-0B68-4AA9-9041-A06B28FC2104] Session:[9DDF7B6B-312B-436F-97D1-6DA84DF0DBFF] CHadrTransportReplica State change from HadrSession_Configuring to HadrSession_Timeout - function [CHadrTransportReplica::TimeoutReplica]
Aug 23 07:02:03 centos01 sqlservr[1272]: [HADR TRANSPORT] AR[8FA8354D-F40F-44EF-A648-722A0ED4F90F]->[071D8AF0-0B68-4AA9-9041-A06B28FC2104] Setting Reconnect Delay to 30 s
Aug 23 07:02:33 centos01 sqlservr[1272]: CHadrTransportReplica::Reset called from function [CHadrTransportReplica::ReconnectTask], primary = 0, primaryConnector = 1
Aug 23 07:02:33 centos01 sqlservr[1272]: CHadrSession State with session ID A1044F08-E3F0-479E-8C23-22FA543E03A4 change from HadrSessionConfig_WaitingSynAck to HadrSessionConfig_ConfigRequest - function [CHadrSession::Reset]
Aug 23 07:02:33 centos01 sqlservr[1272]: [HADR TRANSPORT] AR[8FA8354D-F40F-44EF-A648-722A0ED4F90F]->[071D8AF0-0B68-4AA9-9041-A06B28FC2104] Session:[1168DDB5-5C01-41D7-B411-81FE9A075B81] CHadrTransportReplica State change from HadrSession_Timeout to HadrSession_Configuring - function [CHadrTransportReplica::Reset_Deregistered]
Aug 23 07:02:33 centos01 sqlservr[1272]: [HADR TRANSPORT] AR[8FA8354D-F40F-44EF-A648-722A0ED4F90F]->[071D8AF0-0B68-4AA9-9041-A06B28FC2104], Seesion:[1168DDB5-5C01-41D7-B411-81FE9A075B81] Queue Timeout (10) from [CHadrTransportReplica::Reset_Deregistered]
Aug 23 07:02:33 centos01 sqlservr[1272]: CHadrSession State with session ID 1168DDB5-5C01-41D7-B411-81FE9A075B81 change from HadrSessionConfig_ConfigRequest to HadrSessionConfig_WaitingSynAck - function [CHadrSession::GenerateConfigMessage]
Aug 23 07:02:43 centos01 sqlservr[1272]: [HADR TRANSPORT] AR[8FA8354D-F40F-44EF-A648-722A0ED4F90F]->[071D8AF0-0B68-4AA9-9041-A06B28FC2104] Session:[1168DDB5-5C01-41D7-B411-81FE9A075B81] Timeout Detected 10 s
Aug 23 07:02:43 centos01 sqlservr[1272]: [HADR TRANSPORT] AR[8FA8354D-F40F-44EF-A648-722A0ED4F90F]->[071D8AF0-0B68-4AA9-9041-A06B28FC2104] Session:[1168DDB5-5C01-41D7-B411-81FE9A075B81] CHadrTransportReplica State change from HadrSession_Configuring to HadrSession_Timeout - function [CHadrTransportReplica::TimeoutReplica]
Aug 23 07:02:43 centos01 sqlservr[1272]: [HADR TRANSPORT] AR[8FA8354D-F40F-44EF-A648-722A0ED4F90F]->[071D8AF0-0B68-4AA9-9041-A06B28FC2104] Setting Reconnect Delay to 30 s
1
打开第二台从库的时候,状态又有所变化:

Aug 23 07:18:51 centos02 sqlservr[1307]: CHadrTransportReplica::Reset called from function [CHadrTransportReplica::ReconnectTask], primary = 0, primaryConnector = 1
Aug 23 07:18:51 centos02 sqlservr[1307]: CHadrSession State with session ID 965706DC-2B3D-4E2D-82E0-CAB3ACEC9ED4 change from HadrSessionConfig_WaitingSynAck to HadrSessionConfig_ConfigRequest - function [CHadrSession::Reset]
Aug 23 07:18:51 centos02 sqlservr[1307]: [HADR TRANSPORT] AR[D55252F0-9CBA-4D36-87B2-246248A0C846]->[071D8AF0-0B68-4AA9-9041-A06B28FC2104] Session:[CDF4AEB9-41B8-42C6-B729-28E9378BB4D0] CHadrTransportReplica State change from HadrSession_Timeout to HadrSession_Configuring - function [CHadrTransportReplica::Reset_Deregistered]
Aug 23 07:18:51 centos02 sqlservr[1307]: [HADR TRANSPORT] AR[D55252F0-9CBA-4D36-87B2-246248A0C846]->[071D8AF0-0B68-4AA9-9041-A06B28FC2104], Seesion:[CDF4AEB9-41B8-42C6-B729-28E9378BB4D0] Queue Timeout (10) from [CHadrTransportReplica::Reset_Deregistered]
Aug 23 07:18:51 centos02 sqlservr[1307]: CHadrSession State with session ID CDF4AEB9-41B8-42C6-B729-28E9378BB4D0 change from HadrSessionConfig_ConfigRequest to HadrSessionConfig_WaitingSynAck - function [CHadrSession::GenerateConfigMessage]
Aug 23 07:18:53 centos02 sqlservr[1307]: [HADR TRANSPORT] AR[D55252F0-9CBA-4D36-87B2-246248A0C846]->[071D8AF0-0B68-4AA9-9041-A06B28FC2104] Transport is not in a connected state, unable to send packet
Aug 23 07:18:57 centos02 sqlservr[1307]: [HADR TRANSPORT] AR[D55252F0-9CBA-4D36-87B2-246248A0C846]->[071D8AF0-0B68-4AA9-9041-A06B28FC2104] Transport is not in a connected state, unable to send packet
Aug 23 07:19:01 centos02 sqlservr[1307]: [HADR TRANSPORT] AR[D55252F0-9CBA-4D36-87B2-246248A0C846]->[071D8AF0-0B68-4AA9-9041-A06B28FC2104] Session:[CDF4AEB9-41B8-42C6-B729-28E9378BB4D0] Timeout Detected 10 s
Aug 23 07:19:01 centos02 sqlservr[1307]: [HADR TRANSPORT] AR[D55252F0-9CBA-4D36-87B2-246248A0C846]->[071D8AF0-0B68-4AA9-9041-A06B28FC2104] Session:[CDF4AEB9-41B8-42C6-B729-28E9378BB4D0] CHadrTransportReplica State change from HadrSession_Configuring to HadrSession_Timeout - function [CHadrTransportReplica::TimeoutReplica]
Aug 23 07:19:01 centos02 sqlservr[1307]: [HADR TRANSPORT] AR[D55252F0-9CBA-4D36-87B2-246248A0C846]->[071D8AF0-0B68-4AA9-9041-A06B28FC2104] Setting Reconnect Delay to 9 s
1
Transport is not in a connected state, unable to send packet

这似乎说明,这三台集群节点之间并不能互相通信。 又或者说明作为 Service Broker Endpoint 之间,没有认证的通信授权。

截了个图,经历了各种蹂躏,惨败以及怀疑人生之后最终的模样 :

Linux 上配置 SQL Server Always On Availability Group