Linux 上配置 SQL Server Always On Availability Group

dbLenis發表於2018-08-29

SQL Server Always On Availability Group 配置

步驟:

  1. 配置三臺 Linux 叢集節點
  2. 建立 Availability Group
  3. 配置 Cluster Resource Manager, 比如 Pacemaker
  4. 在叢集中新增 Availability Groups

詳細解說

1. 配置三臺 Linux 叢集節點

  • 在叢集中的三臺伺服器之間可以互相通訊
  • 安裝 SQL Server

在 Linux 上,往叢集管理器中新增叢集資源時,一定是先建立叢集資源,接著將新建的資源加入到叢集中去。

所以建立 SQL Server Always On Availability Groups 也一樣,先建立 AG, 完了之後新增到叢集管理器( Cluster Manager )中去。

三臺節點之間可以相互通訊,該如何瞭解?

使用 ssh 可以相互無障礙地登入

  1. 設定每臺計算機的機器名
  2. 加入同一個域
  3. 配置 RSA 使得無密碼 ssh 登入

1 設定每臺計算機的機器名

vi /etc/hostname

分別設定為 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

把以上的配置指令碼放入各自伺服器的 /etc/hosts 中去,不需要配置域即可互相識別。

安裝 SQL Server 已有介紹,不展開了

2. 啟動 AlwaysOn Availability Group 特性

/opt/mssql/bin/mssql-conf set hadr.hadrenabled 1
systemctl restart mssql-server

可以檢查伺服器是否啟用了 hadr :

select serverproperty('HadrManagerStatus')

適用於: 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

在每一臺節點例項上都開啟 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.'

create master key 是 T-SQL 命令,不能直接在 shell 裡面執行!

新建證照:

create certificate dbm_certificate with subject='dbm'
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.')

現在有了公鑰,私鑰和證照,則需要保證所有的叢集節點都有私鑰和證照,如果沒有則複製私鑰和證照到相同目錄下,以便之後的安裝證照。

所以配置 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/

把這兩個檔案的許可權賦給執行 ms sql server 服務的賬戶 mssql:

chown mssql:mssql dbm_certificate.*

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.')

在所有的從庫都執行上述的指令碼,來建立證照。

其中會遇到一點小麻煩:

Msg 15208, Level 16, State 6, Server centos02, Line 1
The certificate, asymmetric keyor private key file is not valid or does not exist; or you do not have permissions for it.

mssql 是用來執行 sql server on linux 的賬戶,因此他需要被賦予可以訪問證照和私鑰檔案的許可權。

chown mssql:mssql dbm_certificate.*

證照是從主庫上“移栽”過去的,那麼從庫是否也需要搭建自己的證照,“移栽”給主庫使用呢?

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

開啟 防火牆對 endpoint 對應的埠的支援。

    firewall-cmd --zone=public --add-port=5022/tcp --permanent
    firewall-cmd --reload

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 ;

我們在這裡指定了 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 ;

理論上所有 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 ;

新增 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]

驗證同步情況:

select db_name(database_id)  as 'database'
    ,   synchronization_state_desc
from sys.dm_hadr_database_replica_states ;

到這裡,資料庫只是同步了名字,但資料表等還沒有徹底完成節點之間的同步。

8. Pacemaker 的安裝

在配置完畢 AG 的時候,一定要配置 Pacemaker.

以下六個步驟除了 pcs 第5步,其他都需要在叢集中的每臺節點上執行。

詳細構建與解說可以檢視【參考文章】。

1. 大致需要安裝 2個軟體和 1 個工具:

  • Pacemaker
  • Corosync
  • Pcsd

預設情況下,這三個軟體都在自帶的 repository 庫中配置好了,只要執行安裝即可:

yum install -y pacemaker,corosync,pcs

pcsd 是 pacemaker 的客戶端命令執行程式,任何的功能都需要 pcsd 來啟動和設定,pacemaker 是服務程式。當 pcsd, pacemaker 都配置好之後,使用命令 pcs 就可以用來和 pacemaker 互動了。所以 pcs 才是真正執行叢集管理的程式軟體,只要在其中一臺節點上執行 pcs, 命令即將被送到各個節點去執行。

從安裝的日誌分析, corosync 會在安裝 pacemaker 的時候一起安裝,因此不需要特別去單獨安裝。pcs 是需要獨立安裝的。

MSDN 文件中規定,還需要安裝額外的兩個程式:

yum install -y fence-agents-all resource-agents

但 fency-agents-all 沒有找到安裝包,而 resource-agents 卻已經安裝完畢了。

2. 開啟防火牆埠

firewall-cmd --permanent --add-service=high-availability
firewall-cmd --reload

如果沒有 high availability 的配置,也可以指定埠:

TCP:ports 2224,3121,21064

UDP:port 5405

3. 設定使用者密碼

這個使用者非常重要,他是建立叢集的賬戶,有了他的存在,叢集才能執行起來,和 sql server 安裝使用者要區分開來,實際上這兩個使用者需要分開建。

passwd hacluster

為了方便這裡的使用者密碼和 sa 密碼一致!

  1. 開啟叢集的重啟回線設定

當節點失效了,修復後需要重新回到叢集,這叫做回線。此功能需要設定:

systemctl enable pcsd 
systemctl start pcsd
systemctl enable pacemaker

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

配置授權的程式執行過長,而且中間經常有錯誤,比如失聯,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

換成 root.

###### 小結下叢集的主要步驟:

pcs 的程式只要在其中一臺執行即可

5.1 開啟 pcs 程式:

systemctl enable pcsd
systemctl start pcsd
systemctl enable pacemaker

** 每臺節點都需要執行

5.2 授權節點

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

更建議換成:

pcs cluster auth centos00 centos01 centos02

5.3 設定叢集屬性: 叢集名,節點名

pcs cluster setup --name crmcluster centos00 centos1 centos02
[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

5.4 開啟叢集服務

pcs cluster start 
pcs cluster enable 

6 安裝 sql server resource agent

yum install mssql-server-ha

7. 配置 fencing(STONITH)

fencing 的作用是讓失效的節點回線,一旦節點故障離線了,fencing 會引導節點重新回到叢集。

STONITH: shoot the other node in the head

常規情況,fencing 特性是必須要在叢集的節點中啟動的。但如果處於測試的目的,可以不啟動。可以嘗試著去啟動它,對於以後部署聖餐環境,是有好處的,相當於一次生產環境中部署的演練。在本文中為了方便快捷的部署,先將其關閉。

fencing 可以從兩方面進行叢集資源的控制,一是節點本身,二是節點上提供的資源,比如硬碟,SQL 服務等。

針對節點本身一級的控制:

pcs property set stonith-enabled=false

問題:

1 叢集管理器(Cluster Manager)為什麼不能整合 fencing 的功能?

2 叢集資源與叢集管理器之間的互動,依靠什麼來介面?

3 fencing 的實現

8 叢集“心跳”的設定

“心跳”(Heart Beat)的概念,在這裡是指叢集節點之間互相通訊,檢查健康狀態和叢集屬性變更的機制。通過設定叢集屬性 cluster-recheck-interval 來確定“心跳” 的時間間隔。

一旦叢集中的某一個節點下線(不能互相通訊),叢集管理器可以嘗試著在一段時間(failure-timeout)後去重啟這臺節點。如果在這段時間內節點又有反應(能與叢集互相通訊)了,那麼在接收到這個回線的訊號之後,就取消重啟先前標記為下線的節點。

pcs property set cluster-recheck-interval=2min

不建議把 cluster-recheck-interval 設定的過短,比如 60s; 一般 failure-timeout 可以設定的短一些,60s, 而 cluster-recheck-interval 要設定的比 failure-timeout 長一些。

pcs resource update [crmag] meta failure-timeout=60s

9 為 Pacemaker 設定 SQL Server Login 賬戶

use master 
go 

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

GO

在每一臺叢集例項上都執行上面的命令。

[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

在每一臺叢集節點上執行上述指令碼

10 建立 AG (Availability Groups)叢集資源

pcs resource create crmag_cluster ocf:mssql:ag ag_name=crmag meta failure-timeout=30master notify=true

11 建立虛擬 IP 地址

pcs resource create virtualip ocf:heartbeat:IPaddr2 ip=192.168.1.15

與我們的 SQL Server 例項所在節點的網段一致。

12 Add colocation constraint

pcs constraint colocation add virtualip crmag_cluster-master INFINITY with-rsc-role=master

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>

而正確的寫法卻是:

pcs constraint colocation add virtualip crmag_cluster-master INFINITY with-rsc-role=Master

大小寫敏感!

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)

注意點:

叢集資源管理器:

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 也能實現的

參考文章:

  1. MSDN 文件: https://docs.microsoft.com/en-us/sql/linux/sql-server-linux-setup?view=sql-server-2017
  2. 雲和恩墨張樂奕的文章:https://blog.csdn.net/enmotech/article/details/80267170
  3. https://docs.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker?view=sql-server-2017
  4. SQL Server 映象下載: https://packages.microsoft.com/
  5. 介紹在 Centos 上安裝 SQL Server 的文章: https://www.rootusers.com/how-to-install-microsoft-sql-server-on-linux/
  6. 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
  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
  8. 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.

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 identitySqlConnectionString connectionOptionsSqlCredential credentialObject providerInfoString newPasswordSecureString newSecurePasswordBoolean redirectedUserInstanceSqlConnectionString userConnectionOptionsSessionData reconnectSessionDataDbConnectionPool poolString accessTokenBoolean applyTransientFaultHandlingSqlAuthenticationProviderManager sqlAuthProviderManager)
在 System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions optionsDbConnectionPoolKey poolKeyObject poolGroupProviderInfoDbConnectionPool poolDbConnection owningConnectionDbConnectionOptions userOptions)
在 System.Data.ProviderBase.DbConnectionFactory.CreateNonPooledConnection(DbConnection owningConnectionDbConnectionPoolGroup poolGroupDbConnectionOptions userOptions)
在 System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnectionTaskCompletionSource`1 retryDbConnectionOptions userOptionsDbConnectionInternal oldConnectionDbConnectionInternalconnection)
在 System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnectionDbConnectionFactory connectionFactoryTaskCompletionSource`1 retryDbConnectionOptions userOptions)
在 System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnectionDbConnectionFactory connectionFactoryTaskCompletionSource`1 retryDbConnectionOptions 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 ciIServerType server)
在 Microsoft.SqlServer.Management.UI.ConnectionDlg.Connector.ConnectionThreadUser()

但也有可能是 SSMS 17 是比較新的版本,因此不是很穩定,第二次連線就連上了。

  1. 主庫伺服器啟動後,接著啟動從庫的伺服器,傳輸訊息失敗
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 (10from [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

開啟第二臺從庫的時候,狀態又有所變化:

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 (10from [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

Transport is not in a connected state, unable to send packet

這似乎說明,這三臺叢集節點之間並不能互相通訊。 又或者說明作為 Service Broker Endpoint 之間,沒有認證的通訊授權。

截了個圖,經歷了各種蹂躪,慘敗以及懷疑人生之後最終的模樣 :

這裡寫圖片描述

相關文章