最初在为公司设计sqlserver数据库镜像的时候,首先考虑的是高可用性(三台计算机,一台见证服务器,一台做主数据库,一台做镜像) 在虚拟机环境下部署成功,一切都是那么的完美。 故障转移3秒之内就可以顺利完成。 1.高可用性的实施代码: 主体数据库 /* ***
最初在为公司设计sqlserver数据库镜像的时候,首先考虑的是高可用性(三台计算机,一台见证服务器,一台做主数据库,一台做镜像)
在虚拟机环境下部署成功,一切都是那么的完美。 故障转移3秒之内就可以顺利完成。
1.高可用性的实施代码:
主体数据库
/********************************************************
此脚本在主体服务器执行
********************************************************/
--镜像只支持完全恢复模式,在备份数据库之前检查恢复的模式
--对要镜像的数据库进行完整备份后,复制到镜像数据库以norecoverny选项进行恢复
use master;
--drop master key
create master key encryption by password = 'password';
go
--为此服务器实例制作一个证书。
--drop certificate host_a_cert
create certificate host_a_cert
with subject = 'host_a certificate',start_date = '01/01/2009';
go
--使用该证书为服务器实例创建一个镜像端点。
--drop endpoint endpoint_mirroring
create endpoint endpoint_mirroring
state = started
as tcp (
listener_port=5022
, listener_ip = all
)
for database_mirroring (
authentication = certificate host_a_cert
, encryption = required algorithm aes
, role = partner
);
go
--备份 host_a 证书,并将其复制到其他机器,将 c:\host_a_cert.cer 复制到 host_b\host_c。
backup certificate host_a_cert to file = 'e:\host_a_cert.cer';
go
--为入站连接配置 host_a
--在 host_a 上为 host_b 创建一个登录名。
use master;
--drop login host_b_login
create login host_b_login with password = 'password';
go
--创建一个使用该登录名的用户。
--drop user host_b_user
create user host_b_user for login host_b_login;
go
--使证书与该用户关联。
--drop certificate host_b_cert
create certificate host_b_cert
authorization host_b_user
from file = 'e:\host_b_cert.cer'
go
--授予对远程镜像端点的登录名的 connect 权限。
grant connect on endpoint::endpoint_mirroring to [host_b_login];
go
--在 host_a 上为 host_c 创建一个登录名。
use master;
--drop login host_c_login
create login host_c_login with password = 'password';
go
--创建一个使用该登录名的用户。
--drop user host_c_user
create user host_c_user for login host_c_login;
go
--使证书与该用户关联。
--drop certificate host_c_cert
create certificate host_c_cert
authorization host_c_user
from file = 'e:\host_c_cert.cer'
go
--授予对远程镜像端点的登录名的 connect 权限。
grant connect on endpoint::endpoint_mirroring to [host_c_login];
go
use master;
--drop login host_a_login
create login host_a_login with password = 'password';
go
--创建一个使用该登录名的用户。
--drop user host_a_user
create user host_a_user for certificate host_a_cert;
go
--授予对远程镜像端点的登录名的 connect 权限。
grant connect on endpoint::endpoint_mirroring to [host_a_login];
go
--必须要在镜像数据库中先设置好伙伴后,才能在主体服务器执行
--在 host_a 的主体服务器实例上,将 host_b 上的服务器实例设置为伙伴(使其成为初始镜像服务器实例)。
alter database crm
set partner = 'tcp://192.168.1.205:5022';
go
--设置见证服务器
alter database crm set witness = n'tcp://192.168.1.204:5022';
go
镜像数据库
/***********************************************
在镜像服务器执行此脚本
***********************************************/
use master;
--drop master key
create master key encryption by password = 'password';
go
--为 host_b 服务器实例制作一个证书。
--drop certificate host_b_cert
create certificate host_b_cert
with subject = 'host_b certificate for database mirroring',start_date = '01/01/2009';
go
--在 host_b 中为服务器实例创建一个镜像端点。
--drop endpoint endpoint_mirroring
create endpoint endpoint_mirroring
state = started
as tcp (
listener_port=5022
, listener_ip = all
)
for database_mirroring (
authentication = certificate host_b_cert
, encryption = required algorithm aes
, role = partner
);
go
--备份 host_b 证书,将 c:\host_b_cert.cer 复制到 host_a\host_c。
backup certificate host_b_cert to file = 'e:\host_b_cert.cer';
go
--为入站连接配置 host_b
--在 host_b 上为 host_a 创建一个登录名。
use master;
--drop login host_a_login
create login host_a_login with password = 'password';
go
--创建一个使用该登录名的用户。
--drop user host_a_user
create user host_a_user for login host_a_login;
go
--使证书与该用户关联。
--drop certificate host_a_cert
create certificate host_a_cert
authorization host_a_user
from file = 'e:\host_a_cert.cer'
go
--授予对远程镜像端点的登录名的 connect 权限。
grant connect on endpoint::endpoint_mirroring to [host_a_login];
go
--在 host_b 上为 host_c 创建一个登录名。
use master;
--drop login host_c_login
create login host_c_login with password = 'password';
go
--创建一个使用该登录名的用户。
--drop user host_c_user
create user host_c_user for login host_c_login;
go
--使证书与该用户关联。
--drop certificate host_c_cert
create certificate host_c_cert
authorization host_c_user
from file = 'e:\host_c_cert.cer'
go
--授予对远程镜像端点的登录名的 connect 权限。
grant connect on endpoint::endpoint_mirroring to [host_c_login];
go
--在 host_b 上为 host_b 创建一个登录名。
use master;
--drop login host_b_login
create login host_b_login with password = 'password';
go
--创建一个使用该登录名的用户。
--drop user host_b_user
create user host_b_user for certificate host_b_cert;
go
--授予对远程镜像端点的登录名的 connect 权限。
grant connect on endpoint::endpoint_mirroring to [host_b_login];
go
--在 host_b 的镜像服务器实例上,将 host_a 上的服务器实例设置为伙伴(使其成为初始主体服务器实例)。
alter database crm
set partner = 'tcp://192.168.1.203:5022';
go
见证服务器
/****************************
见证服务器执行
*****************************/
--alter database mirrordb set partner off
use master;
--drop master key
create master key encryption by password = 'password';
go
--为此服务器实例制作一个证书。
--drop certificate host_c_cert
create certificate host_c_cert
with subject = 'host_c certificate',start_date = '01/01/2009';
go
--使用该证书为服务器实例创建一个镜像端点。
--drop endpoint endpoint_mirroring
create endpoint endpoint_mirroring
state = started
as tcp (
listener_port=5022
, listener_ip = all
)
for database_mirroring (
authentication = certificate host_c_cert
, encryption = required algorithm aes
, role = witness
);
go
--备份 host_c 证书,并将其复制到其他系统,即 host_b\host_a。
backup certificate host_c_cert to file = 'e:\host_c_cert.cer';
go
--为入站连接配置 host_c
--在 host_c 上为 host_b 创建一个登录名。
use master;
--drop login host_b_login
create login host_b_login with password = 'password';
go
--创建一个使用该登录名的用户。
--drop user host_b_user
create user host_b_user for login host_b_login;
go
--使证书与该用户关联。
--drop certificate host_b_cert
create certificate host_b_cert
authorization host_b_user
from file = 'e:\host_b_cert.cer'
go
--授予对远程镜像端点的登录名的 connect 权限。
grant connect on endpoint::endpoint_mirroring to [host_b_login];
go
--在 host_c 上为 host_a 创建一个登录名。
use master;
--drop login host_a_login
create login host_a_login with password = 'password';
go
--创建一个使用该登录名的用户。
--drop user host_a_user
create user host_a_user for login host_a_login;
go
--使证书与该用户关联。
--drop certificate host_a_cert
create certificate host_a_cert
authorization host_a_user
from file = 'e:\host_a_cert.cer'
go
--授予对远程镜像端点的登录名的 connect 权限。
grant connect on endpoint::endpoint_mirroring to [host_a_login];
go
--在 host_c 上为 host_c 创建一个登录名。
use master;
--drop login host_c_login
create login host_c_login with password = 'password';
go
--创建一个使用该登录名的用户。
--drop user host_c_user
create user host_c_user for certificate host_c_cert;
go
可能有朋友们会比较有疑惑,你一下搞两个数据库出来,他们的ip地址都不一样,到时候数据库切换过去了,我的数据库的连接字符串可如何是好?难道还得在代码中去控制是连接哪个数据库吗?
其实这个问题是这样的,使用ado.net或者sql native client能够自动连接到故障转移后的伙伴,连接字符串如下所示:
connectionstring=datasource= a;failover partner=b;initial catalog=adventureworks;integrated security=true;
datasource= a;这个就是我们常用的主数据库的ip地址,failover partner=b;这个填写的就是镜像数据库的ip地址,一旦出现了连接错误,ado.net会在超时以后自动去连接镜像数据库。
2.高级别保护模式
在昨天晚上加班做实施的时候,才发现我的设计已经被修改了,由于以前的项目有java写的也有c#写的,全自动的故障转移不能够实现 。换句话说,由于老项目中的历史遗留问题,以及特殊模块的耦合性过高,无法解耦,只能在高级别保护模式或高性能模式中选择一种了。那么这两者有什么区别呢?
简单一点来说,区别就在与事务安全模式上跟应用场景上。
高级别保护模式采用的是同步镜像, safety full。应用场景:通常在局域网中或对数据要求比较高的场景中。
高性能保护模式采用的是异步镜像, safety off。应用场景:通常在广域网或对数据要求不太高,丢失几条数据是允许的,但是必须保证它不中断服务。
在微软的sqlserver2005的课程上是这么说的。如果是高级别保护模式的话,主、从数据库只要有一台不能正常保证服务,数据库就不能够对外进行服务了,我在开始的时候就没有打算采用这种模式,因为部门经理说了,丢失一两条数据是可以接受的,况且我们公司是做运营的,按照起先微软的课程的理论,高级别保护模式是不太适合我们公司的应用场景的,万一有一台数据库出问题了,整个服务就被中断,这是不能让人接受的。再说了,公司对数据要求不太苛刻,两台服务器都有内网线连接,由于内网传输速度非常的快,即使采用高性能模式,一般来说也是不会丢失数据的。于是我打算采用高性能模式来做数据库的镜像。由于公司服务器没有域环境,所以我就采用了证书验证来做sqlserver镜像。
意外收获:
两台服务器全部都安装了sqlserver2008,在设置事务安全模式的时候,才发现sqlserver2008不支持异步模式。提示大概如下:此sqlserver版本不支持修改事务安全模式,alter database失败。 我当时汗都出来了,忙活了一晚上,到最后居然是这个结果。
由于是服务器维护时间,我大胆的把镜像服务器停止了,结果却让我大吃一惊,主数据库依旧可以正常工作,正常对外提供服务。也就是说,起先微软的课程讲的知识是错误的,两台数据库做镜像,不管是哪台数据库出了问题,另外的一台数据库都可以保证正常对外提供服务。于是我反复试验反复切换了一下,结果依然是这样。
由于高级别保护模式与高性能模式代码差不太多,只是在事务安全模式的设置上有些小区别,前面已经提到,这里就不再多解释了。实施的代码如下:
主体服务器
use master;
create master key encryption by password = 'password';
create certificate host_a_cert with subject = 'host_a certificate' ,
start_date = '01/01/2009';
create endpoint endpoint_mirroring
state = started
as
tcp ( listener_port=5022 , listener_ip = all )
for
database_mirroring
( authentication = certificate host_a_cert , encryption = required algorithm aes , role = all );
backup certificate host_a_cert to file = 'e:\host_a_cert.cer';
create login host_b_login with password = 'password';
create user host_b_user for login host_b_login;
create certificate host_b_cert authorization host_b_user from file = 'e:\host_b_cert.cer';
grant connect on endpoint::endpoint_mirroring to [host_b_login];
alter database crm set partner = 'tcp://10.10.10.8:5022';
镜像数据库
use master;
create master key encryption by password = 'password';
create certificate host_b_cert with subject = 'host_b certificate',
start_date = '01/01/2009';
create endpoint endpoint_mirroring
state = started
as
tcp ( listener_port=5022 , listener_ip = all )
for
database_mirroring
( authentication = certificate host_b_cert , encryption = required algorithm aes , role = all );
backup certificate host_b_cert to file = 'e:\host_b_cert.cer';
create login host_a_login with password = 'password';
create user host_a_user for login host_a_login;
create certificate host_a_cert authorization host_a_user from file = 'e:\host_a_cert.cer';
grant connect on endpoint::endpoint_mirroring to [host_a_login];
alter database crm set partner = 'tcp://10.10.10.6:5022';
可能有朋友会比较奇怪,你这里也没有使用alter database crm set safety full; 按理应该是高性能模式才对呀?
其实这个问题是这样的,我的这个sqlserver2008默认已经是将事务安全模式设置为full了,即使是手动设置也一样,并且我实施的时候sqlserver2008不支持将事务安全模式设置为off。
ok,一切都设置好了,那么就可以模拟服务器真的down机时候的操作了,后续的工作我也把代码做了总结,具体代码如下:
手动故障转移代码
--主备互换
--主机执行:
alter database crm set partner failover
--主服务器down掉,备机紧急启动并且开始服务
alter database crm set partner force_service_allow_data_loss
原来的主服务器恢复,可以继续工作,需要重新设定镜像
--备机执行:
use master
alter database crm set partner resume --恢复镜像
alter database crm set partner failover; --切换主备
3.监视数据库镜像
sqlserver提供了一些视图,可以供查询镜像的各种状态,到时候可以根据这个做一个监视,一旦发生故障转移群集,发邮件给系统管理员,好让系统管理员及时的知道数据库服务器发生了什么问题,即使的做故障分析、排查。有关这方面资料,msdn上已经提供太多资料了。感兴趣的朋友可以去查这方面的资料。
在文章的最后提出一个有争议的问题:sqlserver(2008)高级别保护模式,只要有一台数据库能够保证正常运行,就可以正常对外提供服务。我的实验结果是这样的,这的确跟以往的理论知识有些出入。
还等什么,赶快搭环境动手实验一下吧,体验一下sqlserver镜像带来的快感。 希望有兴趣的朋友们一起学习探讨。