您的位置:首页 > 运维架构 > Linux

Availability Group On Linux 搭建后记

2020-05-02 12:13 886 查看
create availability group [InvestorAG]
    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 [InvestorAG]
        grant create any database ;

使用这份脚本来搭建 Availability Group 的时候,会爆出如下的错误:

消息 35237,级别 16,状态 1,第 1 行
None of the specified replicas for availability group InvestorAG maps to the instance of SQL Server to which you are connected. Reenter the command, specifying this server instance to host one of the replicas. This replica will be the initial primary replica.

使用如下命令即可:

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

新建表以及装载数据

create table dbo.DimTime(TimeID bigint, DayX int, FinMonth int, FinYear Int, FinDate datetime) 
GO 

Insert into DimTime(TimeID,DayX,FinMonth,FinYear,FinDate) values(1,1,1,2018,'2018-01-01')
go 

SELECT * FROM DimTime 

GO

如果 SQL Server 再聪明一点,这一步已经足够让其他的副本也启动起来了, 但遗憾的是,我去检查 192.168.1.11 和 192.168.1.12 什么都没有发生。
因为我并没有给新建的 Availability Group 添加同步的数据库 Investor, 只是AG 的名字用了 InvestorAG, 并没有同时指定数据库。

通过检查新建的 hadr session 和内建的 AlwaysOn_health session, 倒是有点收获:

-- 新建一个 all-in 的 session 

CREATE EVENT SESSION [All_AlwaysOn] ON SERVER 
ADD EVENT sqlserver.alwayson_ddl_executed,
ADD EVENT sqlserver.availability_group_lease_expired(
    ACTION(package0.last_error,sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.context_info,sqlserver.database_name,sqlserver.is_system,sqlserver.nt_username,sqlserver.server_instance_name,sqlserver.session_nt_username,sqlserver.session_server_principal_name,sqlserver.sql_text,sqlserver.username)),
ADD EVENT sqlserver.availability_replica_automatic_failover_validation(
    ACTION(package0.last_error,sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.context_info,sqlserver.database_name,sqlserver.is_system,sqlserver.nt_username,sqlserver.server_instance_name,sqlserver.session_nt_username,sqlserver.session_server_principal_name,sqlserver.sql_text,sqlserver.username)),
ADD EVENT sqlserver.availability_replica_database_fault_reporting(
    ACTION(package0.last_error,sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.context_info,sqlserver.database_name,sqlserver.is_system,sqlserver.nt_username,sqlserver.server_instance_name,sqlserver.session_nt_username,sqlserver.session_server_principal_name,sqlserver.sql_text,sqlserver.username)),
ADD EVENT sqlserver.availability_replica_manager_state_change(
    ACTION(package0.last_error,sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.context_info,sqlserver.database_name,sqlserver.is_system,sqlserver.nt_username,sqlserver.server_instance_name,sqlserver.session_nt_username,sqlserver.session_server_principal_name,sqlserver.sql_text,sqlserver.username)),
ADD EVENT sqlserver.availability_replica_state(
    ACTION(package0.last_error,sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.context_info,sqlserver.database_name,sqlserver.is_system,sqlserver.nt_username,sqlserver.server_instance_name,sqlserver.session_nt_username,sqlserver.session_server_principal_name,sqlserver.sql_text,sqlserver.username)),
ADD EVENT sqlserver.availability_replica_state_change(
    ACTION(package0.last_error,sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.context_info,sqlserver.database_name,sqlserver.is_system,sqlserver.nt_username,sqlserver.server_instance_name,sqlserver.session_nt_username,sqlserver.session_server_principal_name,sqlserver.sql_text,sqlserver.username)),
ADD EVENT sqlserver.hadr_ddl_failover_execution_state(
    ACTION(package0.last_error,sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.context_info,sqlserver.database_name,sqlserver.is_system,sqlserver.nt_username,sqlserver.server_instance_name,sqlserver.session_nt_username,sqlserver.session_server_principal_name,sqlserver.sql_text,sqlserver.username)),
ADD EVENT sqlserver.hadr_read_only_route_preconditions(
    ACTION(package0.last_error,sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.context_info,sqlserver.database_name,sqlserver.is_system,sqlserver.nt_username,sqlserver.server_instance_name,sqlserver.session_nt_username,sqlserver.session_server_principal_name,sqlserver.sql_text,sqlserver.username)),
ADD EVENT sqlserver.hadr_undo_of_redo_log_scan(
    ACTION(package0.last_error,sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.context_info,sqlserver.database_name,sqlserver.is_system,sqlserver.nt_username,sqlserver.server_instance_name,sqlserver.session_nt_username,sqlserver.session_server_principal_name,sqlserver.sql_text,sqlserver.username))
ADD TARGET package0.event_file(SET filename=N'All_AlwaysOn')
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)
GO
-- 内建的 AlwaysOn_health session 

CREATE EVENT SESSION [AlwaysOn_health] ON SERVER 
ADD EVENT sqlserver.alwayson_ddl_executed,
ADD EVENT sqlserver.availability_group_lease_expired,
ADD EVENT sqlserver.availability_replica_automatic_failover_validation,
ADD EVENT sqlserver.availability_replica_manager_state_change,
ADD EVENT sqlserver.availability_replica_state,
ADD EVENT sqlserver.availability_replica_state_change,
ADD EVENT sqlserver.error_reported(
    WHERE ([error_number]=(9691) OR [error_number]=(35204) OR [error_number]=(9693) OR [error_number]=(26024) OR [error_number]=(28047) OR [error_number]=(26023) OR [error_number]=(9692) OR [error_number]=(28034) OR [error_number]=(28036) OR [error_number]=(28048) OR [error_number]=(28080) OR [error_number]=(28091) OR [error_number]=(26022) OR [error_number]=(9642) OR [error_number]=(35201) OR [error_number]=(35202) OR [error_number]=(35206) OR [error_number]=(35207) OR [error_number]=(26069) OR [error_number]=(26070) OR [error_number]>(41047) AND [error_number]<(41056) OR [error_number]=(41142) OR [error_number]=(41144) OR [error_number]=(1480) OR [error_number]=(823) OR [error_number]=(824) OR [error_number]=(829) OR [error_number]=(35264) OR [error_number]=(35265) OR [error_number]=(41188) OR [error_number]=(41189))),
ADD EVENT sqlserver.hadr_db_partner_set_sync_state,
ADD EVENT sqlserver.lock_redo_blocked
ADD TARGET package0.event_file(SET filename=N'AlwaysOn_health.xel',max_file_size=(5),max_rollover_files=(4))
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)
GO

定义中唯一的区别就是 sqlserver.error_reported 事件,在 AlwaysOn_health 定义中添加了这份事件,而在 All_AlwaysOn 自定义中却没有。导致的结局是 AlwaysOn_health 提供了一些蛛丝马迹可供调查:

message A connection timeout has occurred while attempting to establish a connection to availability replica 'centos01' with id [D42B7002-C59F-47A3-9E39-7980F399AC91]. Either a networking or firewall issue exists, or the endpoint address provided for the replica is not the database mirroring endpoint of the host server instance.

通过执行命令:

select * from sys.dm_hadr_availability_replica_states

发现 D42B7002-C59F-47A3-9E39-7980F399AC91 在结果集中是脱线的,disconnected.

登录 centos01 ,执行下列命令:

select * from sys.dm_hadr_availability_replica_states
select * from sys.dm_hadr_availability_replica_cluster_states
select * from sys.dm_hadr_availability_replica_cluster_nodes
select * from sys.dm_hadr_availability_group_states

可知,centos01 上没有添加到 InvestorAG 中来的 replica, group 和 replica 唯一确定了参与 Availability Group 的成员,即 group_id 与 replica_id 是组合唯一键。

在每台从库上执行下面命令:

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

ALTER AVAILABILITY GROUP [InvestorAG]
    Grant Create Any Database ;

在 AlwaysOn_health 会话中,找到如下错误:

message A connection for availability group 'InvestorAG' from availability replica 'centos01' with id [D42B7002-C59F-47A3-9E39-7980F399AC91] to 'centos00' with id [F7830D02-7E2E-4494-82FD-D1CC700CA108] has been successfully established. This is an informational message only. No user action is required.

但这个错误显然是让人高兴的。因为再次去主库上查询状态时,centos01 从库已经上线了。

但此时 Investor 数据库还没有完全上线,即从库 centos01 还没有接收到主库同步过来的 Investor 数据库。因为我还没有把数据库 Investor 加入到 InvestorAG 中来。

需在 master 为当前数据库的情况下,执行添加 AG 数据库的操作,否则有这么个错误:

消息 35208,级别 16,状态 241,第 32 行
Availability-group DDL operations are permitted only when you are using the master database. Run the USE MASTER command, and retry your availability-group DDL command.

use master 
go 

alter availability group InvestorAG
    add database investor

看上去很简单, 我认为此时数据库已经同步到每台从库上了,且每台从库也都有建立这个库了,但是并不能访问

消息
The target database, 'investor', 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.

似乎在这里我忘记了这么一个概念:高可用架构保障的就是当前集群中只有一台服务器在提供者某一种服务,而当前配置的 Availability Group 架构是三台实时同步的服务器,提供了某一个数据库的7*24不发生故障,持续提供服务的功能。如果需要某一台副本数据库可供访问,那么配置两台实时同步,另一台只读,这样便可提供读写分离的服务。

所以还是要思考两个问题:

1 在高可用的集群中,衍生出一台来做读写分离,另外两台提供高可用服务

2 实现高可用的故障转移,即主库失效则自动切换到从库,以提供持续服务

第一个问题,在配置的时候,只要选择可供只读访问:

create availability group sap
    with (db_failover=on,cluster_type=external)
    for replica on 
        N'centos00'
        with (
            endpoint_url = N'tcp://192.168.1.10:5022',
            availability_mode=synchronous_commit,
            failover_mode=external,
            seeding_mode=automatic

            ),
         N'centos01'
        with (
            endpoint_url = N'tcp://192.168.1.11:5022',
            availability_mode=synchronous_commit,
            failover_mode=external,
            seeding_mode=automatic,
            secondary_role ( 
            allow_connections = read_only
            )
            ),
         N'centos02'
        with (
            endpoint_url = N'tcp://192.168.1.12:5022',
            availability_mode=synchronous_commit,
            failover_mode=external,
            seeding_mode=automatic,
            secondary_role ( 
            allow_connections = read_only
            )
            );

当下最重要的话题,先配置三台实时同步的高可用集群,实现自动化故障转移。

有两篇外文,值得参考:

https://blog.dbi-services.com/introducing-alwayson-availability-groups-on-linux/

https://blog.dbi-services.com/introducing-high-availability-with-sql-server-on-linux/

在之前第一遍尝试搭建 Availability Groups 过程中,启动切换故障的主库不成功,要分析原因,就要做一些测试点:

[root@centos00 log]# pcs status
Cluster name: crmcluster
Stack: corosync
Current DC: centos00 (version 1.1.18-11.el7_5.3-2b07d5c5a9) - partition WITHOUT quorum
Last updated: Sun Aug 26 15:26:43 2018
Last change: Tue Aug 21 23:33:46 2018 by root via cibadmin on centos00

3 nodes configured
4 resources configured

Online: [ centos00 ]
OFFLINE: [ centos01 centos02 ]

Full list of resources:

 Master/Slave Set: crmag_cluster-master [crmag_cluster]
     Stopped: [ centos00 centos01 centos02 ]
 virtualip    (ocf::heartbeat:IPaddr2):   Stopped

Daemon Status:
  corosync: active/enabled
  pacemaker: active/enabled
  pcsd: active/enabled

通过 pcs status 命令看到部分原因了: Master/Slave set 和 virtualip 都停止了。

[root@centos02 ~]# pcs status
Cluster name: crmcluster
Stack: corosync
Current DC: centos00 (version 1.1.18-11.el7_5.3-2b07d5c5a9) - partition with quorum
Last updated: Wed Aug 29 06:15:23 2018
Last change: Wed Aug 29 06:15:01 2018 via centos02 on centos00

3 nodes configured
4 resources configured

Online: [ centos00 centos01 centos02 ]

Full list of resources:

 Master/Slave Set: crmag_cluster-master [crmag_cluster]
     Masters: [ centos01 ]
     Slaves: [ centos00 centos02 ]
 virtualip    (ocf::heartbeat:IPaddr2):   Started centos01

Daemon Status:
  corosync: active/enabled
  pacemaker: active/enabled
  pcsd: active/enabled

在每一台服务器上开启集群服务,即可启动整个集群。

pcs cluster start
pcs cluster enable

有趣的是,误打误撞开启了本该是从库的服务器为集群之首(master), 结果访问 virtual ip (192.168.1.15) 的时候,连上的是 192.168.1.11,并不能打开可读可写的 Investor 数据库,该数据库才是我们加入 availability group,保障高可用的目标。

此时我们在 192.168.1.15 的实例上面新建一个数据库,可以看到该数据库在 192.168.1.12 上也同时建立了。

关闭 centos02 的集群,再新建一个数据库,看看如何:

pcs cluster stop

新建的数据库,并不能同步到 192.168.1.12 的实例中了。
但却无意中,将原本一直连接不同的 crm 数据库给同步起来了。

这样的话,要测试是否自动切换就能简单了,直接断掉 192.168.1.11 (现在是 cluster mater ).

[root@centos01 ~]# pcs cluster stop
Error: Stopping the node will cause a loss of the quorum, use --force to override
[root@centos02 ~]# pcs status
Cluster name: crmcluster
Stack: corosync
Current DC: centos00 (version 1.1.18-11.el7_5.3-2b07d5c5a9) - partition with quorum
Last updated: Wed Aug 29 07:11:01 2018
Last change: Tue Aug 21 23:33:46 2018 by root via cibadmin on centos00

3 nodes configured
4 resources configured

Online: [ centos00 centos02 ]
OFFLINE: [ centos01 ]

Full list of resources:

 Master/Slave Set: crmag_cluster-master [crmag_cluster]
     Masters: [ centos00 ]
     Slaves: [ centos02 ]
     Stopped: [ centos01 ]
 virtualip    (ocf::heartbeat:IPaddr2):   Started centos00

Daemon Status:
  corosync: active/enabled
  pacemaker: active/enabled
  pcsd: active/enabled

自动切换实现了

所有的连接如果指向的是 192.168.1.15 那么背后的 sql server instance 自动切换,都是没有影响的。借用《子弹飞》里刘嘉玲的那句话,“我只想当县长夫人,至于县长是谁,那并不重要!”。

dbLenis 博客专家 原创文章 319获赞 295访问量 53万+ 关注 他的留言板
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: