最初在为公司设计SQLServer数据库镜像的时候,首先考虑的是高可用性(三台计算机,一台见证服务器,一台做主数据库,一台做镜像)

在虚拟机环境下部署成功,一切都是那么的完美。 故障转移3秒之内就可以顺利完成。


1.高可用性的实施代码:

主体数据库
  1. /********************************************************
  2. 此脚本在主体服务器执行
  3. ********************************************************/
  4. --镜像只支持完全恢复模式,在备份数据库之前检查恢复的模式
  5. --对要镜像的数据库进行完整备份后,复制到镜像数据库以NORECOVERNY选项进行恢复
  6. USE master;
  7. --DROP MASTER KEY
  8. CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'password';
  9. GO
  10. --为此服务器实例制作一个证书。
  11. --DROP CERTIFICATE HOST_A_cert
  12. CREATE CERTIFICATE HOST_A_cert
  13.   WITH SUBJECT = 'HOST_A certificate',START_DATE  = '01/01/2009';
  14. GO
  15. --使用该证书为服务器实例创建一个镜像端点。
  16. --DROP ENDPOINT Endpoint_Mirroring
  17. CREATE ENDPOINT Endpoint_Mirroring
  18.   STATE = STARTED
  19.   AS TCP (
  20.       LISTENER_PORT=5022
  21.       , LISTENER_IP = ALL
  22.   )
  23.   FOR DATABASE_MIRRORING (
  24.       AUTHENTICATION = CERTIFICATE HOST_A_cert
  25.       , ENCRYPTION = REQUIRED ALGORITHM AES
  26.       , ROLE = PARTNER
  27.   );
  28. GO

  29. --备份 HOST_A 证书,并将其复制到其他机器,将 C:\HOST_A_cert.cer 复制到 HOST_B\HOST_C。
  30. BACKUP CERTIFICATE HOST_A_cert TO FILE = 'e:\HOST_A_cert.cer';
  31. GO
  32. --为入站连接配置 Host_A
  33. --在 HOST_A 上为 HOST_B 创建一个登录名。
  34. USE master;
  35. --DROP LOGIN HOST_B_login
  36. CREATE LOGIN HOST_B_login WITH PASSWORD = 'password';
  37. GO

  38. --创建一个使用该登录名的用户。
  39. --DROP USER HOST_B_user
  40. CREATE USER HOST_B_user FOR LOGIN HOST_B_login;
  41. GO
  42. --使证书与该用户关联。
  43. --DROP CERTIFICATE HOST_B_cert
  44. CREATE CERTIFICATE HOST_B_cert
  45.   AUTHORIZATION HOST_B_user
  46.   FROM FILE = 'e:\HOST_B_cert.cer'
  47. GO

  48. --授予对远程镜像端点的登录名的 CONNECT 权限。
  49. GRANT CONNECT ON ENDPOINT::Endpoint_Mirroring TO [HOST_B_login];
  50. GO

  51. --在 HOST_A 上为 HOST_C 创建一个登录名。
  52. USE master;
  53. --DROP LOGIN HOST_C_login
  54. CREATE LOGIN HOST_C_login WITH PASSWORD = 'password';
  55. GO

  56. --创建一个使用该登录名的用户。
  57. --DROP USER HOST_C_user
  58. CREATE USER HOST_C_user FOR LOGIN HOST_C_login;
  59. GO
  60. --使证书与该用户关联。
  61. --DROP CERTIFICATE HOST_C_cert
  62. CREATE CERTIFICATE HOST_C_cert
  63.   AUTHORIZATION HOST_C_user
  64.   FROM FILE = 'e:\HOST_C_cert.cer'
  65. GO

  66. --授予对远程镜像端点的登录名的 CONNECT 权限。
  67. GRANT CONNECT ON ENDPOINT::Endpoint_Mirroring TO [HOST_C_login];
  68. GO

  69. USE master;
  70. --DROP LOGIN HOST_A_login
  71. CREATE LOGIN HOST_A_login WITH PASSWORD = 'password';
  72. GO
  73. --创建一个使用该登录名的用户。
  74. --DROP USER HOST_A_user
  75. CREATE USER HOST_A_user FOR CERTIFICATE HOST_A_cert;
  76. GO
  77. --授予对远程镜像端点的登录名的 CONNECT 权限。
  78. GRANT CONNECT ON ENDPOINT::Endpoint_Mirroring TO [HOST_A_login];
  79. GO

  80. --必须要在镜像数据库中先设置好伙伴后,才能在主体服务器执行
  81. --在 HOST_A 的主体服务器实例上,将 HOST_B 上的服务器实例设置为伙伴(使其成为初始镜像服务器实例)。
  82. ALTER DATABASE crm
  83.     SET PARTNER = 'TCP://192.168.1.205:5022';
  84. GO

  85. --设置见证服务器
  86. ALTER DATABASE crm SET WITNESS = N'TCP://192.168.1.204:5022';
  87. GO
复制代码
镜像数据库
  1. /***********************************************
  2. 在镜像服务器执行此脚本
  3. ***********************************************/
  4. USE master;
  5. --DROP MASTER KEY
  6. CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'password';
  7. GO
  8. --为 HOST_B 服务器实例制作一个证书。
  9. --DROP CERTIFICATE HOST_B_cert
  10. CREATE CERTIFICATE HOST_B_cert
  11.   WITH SUBJECT = 'HOST_B certificate for database mirroring',START_DATE  = '01/01/2009';
  12. GO
  13. --在 HOST_B 中为服务器实例创建一个镜像端点。
  14. --DROP ENDPOINT Endpoint_Mirroring
  15. CREATE ENDPOINT Endpoint_Mirroring
  16.   STATE = STARTED
  17.   AS TCP (
  18.       LISTENER_PORT=5022
  19.       , LISTENER_IP = ALL
  20.   )
  21.   FOR DATABASE_MIRRORING (
  22.       AUTHENTICATION = CERTIFICATE HOST_B_cert
  23.       , ENCRYPTION = REQUIRED ALGORITHM AES
  24.       , ROLE = PARTNER
  25.   );
  26. GO
  27. --备份 HOST_B 证书,将 C:\HOST_B_cert.cer 复制到 HOST_A\HOST_C。
  28. BACKUP CERTIFICATE HOST_B_cert TO FILE = 'e:\HOST_B_cert.cer';
  29. GO

  30. --为入站连接配置 Host_B
  31. --在 HOST_B 上为 HOST_A 创建一个登录名。
  32. USE master;
  33. --DROP LOGIN HOST_A_login
  34. CREATE LOGIN HOST_A_login WITH PASSWORD = 'password';
  35. GO
  36. --创建一个使用该登录名的用户。
  37. --DROP USER HOST_A_user
  38. CREATE USER HOST_A_user FOR LOGIN HOST_A_login;
  39. GO
  40. --使证书与该用户关联。
  41. --DROP CERTIFICATE HOST_A_cert
  42. CREATE CERTIFICATE HOST_A_cert
  43.   AUTHORIZATION HOST_A_user
  44.   FROM FILE = 'e:\HOST_A_cert.cer'
  45. GO

  46. --授予对远程镜像端点的登录名的 CONNECT 权限。
  47. GRANT CONNECT ON ENDPOINT::Endpoint_Mirroring TO [HOST_A_login];
  48. GO

  49. --在 HOST_B 上为 HOST_C 创建一个登录名。
  50. USE master;
  51. --DROP LOGIN HOST_C_login
  52. CREATE LOGIN HOST_C_login WITH PASSWORD = 'password';
  53. GO

  54. --创建一个使用该登录名的用户。
  55. --DROP USER HOST_C_user
  56. CREATE USER HOST_C_user FOR LOGIN HOST_C_login;
  57. GO
  58. --使证书与该用户关联。
  59. --DROP CERTIFICATE HOST_C_cert
  60. CREATE CERTIFICATE HOST_C_cert
  61.   AUTHORIZATION HOST_C_user
  62.   FROM FILE = 'e:\HOST_C_cert.cer'
  63. GO

  64. --授予对远程镜像端点的登录名的 CONNECT 权限。
  65. GRANT CONNECT ON ENDPOINT::Endpoint_Mirroring TO [HOST_C_login];
  66. GO

  67. --在 HOST_B 上为 HOST_B 创建一个登录名。
  68. USE master;
  69. --DROP LOGIN HOST_B_login
  70. CREATE LOGIN HOST_B_login WITH PASSWORD = 'password';
  71. GO
  72. --创建一个使用该登录名的用户。
  73. --DROP USER HOST_B_user
  74. CREATE USER HOST_B_user FOR CERTIFICATE HOST_B_cert;
  75. GO
  76. --授予对远程镜像端点的登录名的 CONNECT 权限。
  77. GRANT CONNECT ON ENDPOINT::Endpoint_Mirroring TO [HOST_B_login];
  78. GO
  79. --在 HOST_B 的镜像服务器实例上,将 HOST_A 上的服务器实例设置为伙伴(使其成为初始主体服务器实例)。
  80. ALTER DATABASE crm
  81.     SET PARTNER = 'TCP://192.168.1.203:5022';
  82. GO
复制代码
见证服务器
  1. /****************************
  2. 见证服务器执行
  3. *****************************/
  4. --ALTER DATABASE MirrorDB SET PARTNER OFF
  5. USE master;
  6. --DROP MASTER KEY
  7. CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'password';
  8. GO

  9. --为此服务器实例制作一个证书。
  10. --DROP CERTIFICATE HOST_C_cert
  11. CREATE CERTIFICATE HOST_C_cert
  12.   WITH SUBJECT = 'HOST_C certificate',START_DATE  = '01/01/2009';
  13. GO

  14. --使用该证书为服务器实例创建一个镜像端点。
  15. --DROP ENDPOINT Endpoint_Mirroring
  16. CREATE ENDPOINT Endpoint_Mirroring
  17.   STATE = STARTED
  18.   AS TCP (
  19.       LISTENER_PORT=5022
  20.       , LISTENER_IP = ALL
  21.   )
  22.   FOR DATABASE_MIRRORING (
  23.       AUTHENTICATION = CERTIFICATE HOST_C_cert
  24.       , ENCRYPTION = REQUIRED ALGORITHM AES
  25.       , ROLE = WITNESS
  26.   );
  27. GO


  28. --备份 HOST_C 证书,并将其复制到其他系统,即 HOST_B\HOST_A。
  29. BACKUP CERTIFICATE HOST_C_cert TO FILE = 'e:\HOST_C_cert.cer';
  30. GO

  31. --为入站连接配置 Host_C
  32. --在 HOST_C 上为 HOST_B 创建一个登录名。
  33. USE master;
  34. --DROP LOGIN HOST_B_login
  35. CREATE LOGIN HOST_B_login WITH PASSWORD = 'password';
  36. GO

  37. --创建一个使用该登录名的用户。
  38. --DROP USER HOST_B_user
  39. CREATE USER HOST_B_user FOR LOGIN HOST_B_login;
  40. GO
  41. --使证书与该用户关联。
  42. --DROP CERTIFICATE HOST_B_cert
  43. CREATE CERTIFICATE HOST_B_cert
  44.   AUTHORIZATION HOST_B_user
  45.   FROM FILE = 'e:\HOST_B_cert.cer'
  46. GO

  47. --授予对远程镜像端点的登录名的 CONNECT 权限。
  48. GRANT CONNECT ON ENDPOINT::Endpoint_Mirroring TO [HOST_B_login];
  49. GO

  50. --在 HOST_C 上为 HOST_A 创建一个登录名。
  51. USE master;
  52. --DROP LOGIN HOST_A_login
  53. CREATE LOGIN HOST_A_login WITH PASSWORD = 'password';
  54. GO
  55. --创建一个使用该登录名的用户。
  56. --DROP USER HOST_A_user
  57. CREATE USER HOST_A_user FOR LOGIN HOST_A_login;
  58. GO
  59. --使证书与该用户关联。
  60. --DROP CERTIFICATE HOST_A_cert
  61. CREATE CERTIFICATE HOST_A_cert
  62.   AUTHORIZATION HOST_A_user
  63.   FROM FILE = 'e:\HOST_A_cert.cer'
  64. GO

  65. --授予对远程镜像端点的登录名的 CONNECT 权限。
  66. GRANT CONNECT ON ENDPOINT::Endpoint_Mirroring TO [HOST_A_login];
  67. GO

  68. --在 HOST_C 上为 HOST_C 创建一个登录名。
  69. USE master;
  70. --DROP LOGIN HOST_C_login
  71. CREATE LOGIN HOST_C_login WITH PASSWORD = 'password';
  72. GO
  73. --创建一个使用该登录名的用户。
  74. --DROP USER HOST_C_user
  75. CREATE USER HOST_C_user FOR CERTIFICATE HOST_C_cert;
  76. GO
复制代码
可能有朋友们会比较有疑惑,你一下搞两个数据库出来,他们的ip地址都不一样,到时候数据库切换过去了,我的数据库的连接字符串可如何是好?难道还得在代码中去控制是连接哪个数据库吗?

其实这个问题是这样的,使用ADO.NET或者SQL Native Client能够自动连接到故障转移后的伙伴,连接字符串如下所示:

C


DataSource= A;这个就是我们常用的主数据库的ip地址,Failover Partner=B;这个填写的就是镜像数据库的ip地址,一旦出现了连接错误,ado.net会在超时以后自动去连接镜像数据库。


2.高级别保护模式

在昨天晚上加班做实施的时候,才发现我的设计已经被修改了,由于以前的项目有java写的也有c#写的,全自动的故障转移不能够实现 。换句话说,由于老项目中的历史遗留问题,以及特殊模块的耦合性过高,无法解耦,只能在高级别保护模式或高性能模式中选择一种了。那么这两者有什么区别呢?


简单一点来说,区别就在与事务安全模式上跟应用场景上。

高级别保护模式采用的是同步镜像, SAFETY FULL。应用场景:通常在局域网中或对数据要求比较高的场景中。

高性能保护模式采用的是异步镜像, SAFETY OFF。应用场景:通常在广域网或对数据要求不太高,丢失几条数据是允许的,但是必须保证它不中断服务。

在微软的SQLServer2005的课程上是这么说的。如果是高级别保护模式的话,主、从数据库只要有一台不能正常保证服务,数据库就不能够对外进行服务了,我在开始的时候就没有打算采用这种模式,因为部门经理说了,丢失一两条数据是可以接受的,况且我们公司是做运营的,按照起先微软的课程的理论,高级别保护模式是不太适合我们公司的应用场景的,万一有一台数据库出问题了,整个服务就被中断,这是不能让人接受的。再说了,公司对数据要求不太苛刻,两台服务器都有内网线连接,由于内网传输速度非常的快,即使采用高性能模式,一般来说也是不会丢失数据的。于是我打算采用高性能模式来做数据库的镜像。由于公司服务器没有域环境,所以我就采用了证书验证来做SQLServer镜像。

意外收获:


两台服务器全部都安装了SQLServer2008,在设置事务安全模式的时候,才发现SQLServer2008不支持异步模式。提示大概如下:此SQLServer版本不支持修改事务安全模式,alter database失败。 我当时汗都出来了,忙活了一晚上,到最后居然是这个结果。


由于是服务器维护时间,我大胆的把镜像服务器停止了,结果却让我大吃一惊,主数据库依旧可以正常工作,正常对外提供服务。也就是说,起先微软的课程讲的知识是错误的,两台数据库做镜像,不管是哪台数据库出了问题,另外的一台数据库都可以保证正常对外提供服务。于是我反复试验反复切换了一下,结果依然是这样。


由于高级别保护模式与高性能模式代码差不太多,只是在事务安全模式的设置上有些小区别,前面已经提到,这里就不再多解释了。实施的代码如下:


主体服务器
  1. USE  master;
  2. CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'password';
  3. CREATE CERTIFICATE HOST_A_cert WITH SUBJECT = 'HOST_A certificate' ,
  4. START_DATE = '01/01/2009';


  5. CREATE  ENDPOINT Endpoint_Mirroring
  6. STATE = STARTED
  7. AS
  8. TCP ( LISTENER_PORT=5022 , LISTENER_IP = ALL )
  9. FOR
  10. DATABASE_MIRRORING
  11. ( AUTHENTICATION = CERTIFICATE HOST_A_cert , ENCRYPTION = REQUIRED ALGORITHM AES , ROLE = ALL );


  12. BACKUP  CERTIFICATE HOST_A_cert TO  FILE  =  'e:\HOST_A_cert.cer';


  13. CREATE  LOGIN HOST_B_login WITH  PASSWORD  =  'password';
  14. CREATE USER HOST_B_user FOR LOGIN HOST_B_login;
  15. CREATE CERTIFICATE HOST_B_cert AUTHORIZATION HOST_B_user FROM FILE = 'e:\HOST_B_cert.cer';
  16. GRANT CONNECT ON ENDPOINT::Endpoint_Mirroring TO [HOST_B_login];


  17. ALTER  DATABASE crm SET  PARTNER  =  'TCP://10.10.10.8:5022';
复制代码
镜像数据库
  1. USE  master;
  2. CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'password';
  3. CREATE CERTIFICATE HOST_B_cert WITH SUBJECT = 'HOST_B certificate',
  4. START_DATE = '01/01/2009';


  5. CREATE  ENDPOINT Endpoint_Mirroring
  6. STATE = STARTED
  7. AS
  8. TCP ( LISTENER_PORT=5022 , LISTENER_IP = ALL )
  9. FOR
  10. DATABASE_MIRRORING
  11. ( AUTHENTICATION = CERTIFICATE HOST_B_cert , ENCRYPTION = REQUIRED ALGORITHM AES , ROLE = ALL );


  12. BACKUP  CERTIFICATE HOST_B_cert TO  FILE  =  'e:\HOST_B_cert.cer';


  13. CREATE  LOGIN HOST_A_login WITH  PASSWORD  = 'password';
  14. CREATE USER HOST_A_user FOR LOGIN HOST_A_login;
  15. CREATE CERTIFICATE HOST_A_cert AUTHORIZATION HOST_A_user FROM FILE = 'e:\HOST_A_cert.cer';
  16. GRANT CONNECT ON ENDPOINT::Endpoint_Mirroring TO [HOST_A_login];


  17. ALTER  DATABASE crm SET  PARTNER  =  'TCP://10.10.10.6:5022';
复制代码
可能有朋友会比较奇怪,你这里也没有使用ALTER DATABASE crm SET SAFETY FULL; 按理应该是高性能模式才对呀?


其实这个问题是这样的,我的这个SQLServer2008默认已经是将事务安全模式设置为full了,即使是手动设置也一样,并且我实施的时候SQLServer2008不支持将


事务安全模式设置为OFF。

OK,一切都设置好了,那么就可以模拟服务器真的down机时候的操作了,后续的工作我也把代码做了总结,具体代码如下:

手动故障转移代码
  1. --主备互换
  2. --主机执行:

  3. ALTER DATABASE crm SET PARTNER FAILOVER

  4. --主服务器Down掉,备机紧急启动并且开始服务
  5. ALTER DATABASE crm SET PARTNER FORCE_SERVICE_ALLOW_DATA_LOSS
复制代码
原来的主服务器恢复,可以继续工作,需要重新设定镜像
  1. --备机执行:
  2. USE master
  3. ALTER DATABASE crm SET PARTNER RESUME  --恢复镜像

  4. ALTER DATABASE crm SET PARTNER FAILOVER; --切换主备
复制代码
3.监视数据库镜像


SQLServer提供了一些视图,可以供查询镜像的各种状态,到时候可以根据这个做一个监视,一旦发生故障转移群集,发邮件给系统管理员,好让系统管理员及时的知道数据库服务器发生了什么问题,即使的做故障分析、排查。有关这方面资料,MSDN上已经提供太多资料了。感兴趣的朋友可以去查这方面的资料。


在文章的最后提出一个有争议的问题:SQLServer(2008)高级别保护模式,只要有一台数据库能够保证正常运行,就可以正常对外提供服务。我的实验结果是这样的,这的确跟以往的理论知识有些出入。


还等什么,赶快搭环境动手实验一下吧,体验一下SQLServer镜像带来的快感。



文/深山老林
赞助商广告:

TOP