利用NetScaler和自行编写的健康检查脚本,完美解决多台MySQL Slave数据库的负载均衡
view plaincopy to clipboardprint?
1. #!/usr/bin/perl -w
2. ################################################################
3. ##
4. ## MySQL Slave Server Monitoring Script V1.1 for NetScaler 8.x
5. ## Written by Zhang Yan (blog.s135.com) on
6. ##
7. ################################################################
8. ## This is a netscaler supplied script.
9.
10. ## This script is used to do MySQL slave server monitoring
11. ## using KAS feature.
12. ## The mandatory arguments are:
13. ## 1. Database to which the user is going to connect
14. ## 2. User name
15. ## The optional arguments are:
16. ## 1. password: This is the password that will be used to
17. ## login into the server. If no password is
18. ## given a blank password is used.
19. ## 2. SQL query
20. ## Example:
21. ## set monitor ... -scriptArgs "database=test;user=user1;password=password;
22. ## query=show slave status"
23.
24.
25. use strict;
26. use DBI;
27. use Netscaler::KAS;
28.
29. ## This function is a handler for performing MYSQL probe in KAS mode
30. sub mysql_probe
31. {
32. ## There must be at least 3 arguments to this function.
33. ## 1. First argument is the IP that has to be probed.
34. ## 2. Second argument is the port to connect to.
35. ## 3. Arguments to be used during probing.
36. if(scalar(@_) < 3)
37. {
38. return (1,"Arguments not given");
39. }
40.
41. ## Parse the argument given, to get database,user name,password,SQL query.
42. ## If parsing fails, it is monitoring probe failure.
43. $_[2]=~/database=([^;]+);user=([^;]+)(;password=([^;]+))?(;query=([^;]+))?/
44. or return (1,"Invalid argument format");
45.
46. (my $database,my $username,my $password,my $sql_query)=($1,$2,$4,$6);
47.
48. ## If no password is given, try blank password
49. if(!defined($password))
50. {
51. $password="";
52. }
53.
54. ## Try to connect to the server
55. my $db_handle = DBI->connect("dbi:mysql:database=$database:host=$_[0]:$_[1]",$username,$password)
56. or return (1,"Connection to database failed - $!");
57.
58. ## Check MySQL Slave Server
59. my $slave_info = $db_handle->prepare("show slave status");
60. $slave_info->execute()
61. or return (1,"Execution of SQL query failed");
62. my $slave_ref = $slave_info->fetchrow_hashref()
63. or return (1,"Fetchrow of SQL query failed");
64.
65. my $threads_info = $db_handle->prepare("show global status like 'Threads_running'");
66. $threads_info->execute()
67. or return (1,"Execution of SQL query failed");
68. my $threads_ref = $threads_info->fetchrow_hashref()
69. or return (1,"Fetchrow of SQL query failed");
70.
71. if (exists $slave_ref->{Slave_SQL_Running} and $slave_ref->{Slave_SQL_Running} eq 'No')
72. {
73. $db_handle->disconnect();
74. return (1,"Slave IO thread has stopped");
75. }
76. elsif (exists $slave_ref->{Slave_IO_Running} and $slave_ref->{Slave_IO_Running} eq 'No')
77. {
78. $db_handle->disconnect();
79. return (1,"Slave IO thread has stopped");
80. }
81. elsif (exists $slave_ref->{Last_Error} and $slave_ref->{Last_Error} ne '')
82. {
83. $db_handle->disconnect();
84. return (1,"Has some error information");
85. }
86. elsif (exists $slave_ref->{Seconds_Behind_Master} and $slave_ref->{Seconds_Behind_Master} > 600)
87. {
88. $db_handle->disconnect();
89. return (1,"The seconds behind master more than 600");
90. }
91. elsif (exists $threads_ref->{Value} and $threads_ref->{Value} > 200)
92. {
93. $db_handle->disconnect();
94. return (1,"The number of threads that are not sleeping more than 200");
95. }
96. else
97. {
98. ## If no query is given then it is probe success , else try executing the query
99. if(!defined($sql_query))
100. {
101. $db_handle->disconnect();
102. return 0;
103. }
104.
105. ## Problem during query execution, report failure
106. my $statement = $db_handle->prepare($sql_query)
107. or return (1,"Preparation of SQL query failed");
108.
109. $statement->execute()
110. or return (1,"Execution of SQL query failed");
111. }
112.
113. ## Probe Succeeded.
114. $db_handle->disconnect();
115.
116. return 0;
117. }
118.
119. ## Register MS SQL probe handler, to the KAS module.
120. probe(&mysql_probe);
脚本压缩包下载:
下载文件 (已下载 83 次)
健康检查脚本写完了,现在开始配置NetScaler 8.0:
1、使用SecureCRT等SSH客户端工具登录到NetScaler,然后执行以下命令:
shell
cd /nsconfig/monitors/
vi nsmysql-slave.pl
将“nsmysql-slave.pl”的源代码粘贴到其中,然后保存退出,再执行以下命令:
chmod +x nsmysql-slave.pl
2、检查一下从NetScaler上是否能够连接MySQL Slave数据库:
mysql -u 用户名 -p -h 192.168.1.31 -P 3306
Enter password:(在此输入MySQL登录密码)
ERROR 1251: Client does not support authentication protocol requested by server; consider upgrading MySQL client
如果你的MySQL Slave服务器版本高于4.0,就会出现以上错误。这是因为MySQL 4.1及其以上版本的密码验证算法与MySQL 4.0及其以下版本不同,而NetScaler 8.0上的MySQL客户端默认版本为4.0.25,因此,4.0.25版本的MySQL客户端连接4.1、5.X、6.X版本的MySQL服务器就会出错。
解决办法1:升级NetScaler 8.0上的MySQL客户端,但最好不要这么做,因为NetScaler与底层的FreeBSD系统和应用软件嵌入很密切的,不要轻易替换成非官方版本,以免导致不兼容、不稳定等情况。
解决方法2:在各台MySQL Slave服务器上新建一个名为“netscaler”的超级管理员帐号,将密码改为使用旧加密算法进行加密的密码。如果从安全考虑,可将以下语句中的%换成NetScaler的Subnet IP。
Server version: 5.1.24-rc MySQL Community Server (GPL)
Type 'help;' or 'h' for help. Type 'c' to clear the buffer.
mysql>
GRANT ALL PRIVILEGES ON *.* TO 'netscaler'@'%' IDENTIFIED BY OLD_PASSWORD('12345678');
FLUSH PRIVILEGES;
3、各台MySQL Slave数据库必须添加允许NetScaler的Subnet IP访问的帐号,因为在同一网段,不能开启源IP支持,MySQL服务器上看到的将是NetScaler的Subnet IP:
例如:【Web服务器(192.168.1.21)】──→【NetScaler VIP(192.168.1.5)】- - - →【NetScaler Subnet IP(192.168.1.2)】──→【MySQL Slave服务器(192.168.1.31)】
MySQL Slave服务器看到的是IP地址是192.168.1.2,就需要添加NetScaler的Subnet IP访问的帐号('apache'@'192.168.1.2'):
Server version: 5.1.24-rc MySQL Community Server (GPL)
Type 'help;' or 'h' for help. Type 'c' to clear the buffer.
mysql>
GRANT ALL PRIVILEGES ON *.* TO 'apache'@'192.168.1.2' IDENTIFIED BY '12345678';
FLUSH PRIVILEGES;
4、从Web管理界面登录NetScaler 8.0,进入Configuration页面(需要安装Java Runtime Environment,版本在JRE 1.4.x+以上):
5、点击【Load Balancing】──【Monitors】栏的“add”按钮,添加一个名为“mysql_slave”的MySQL健康检查:
①、Interval:正常情况下,10秒钟检查一次;
②、Response Timeout:每次检查的超时时间为8秒,必须小于Interval;
③、Down Time:宕机状态下,每5秒钟检查一次;
④、Retries:重试5次后仍然检查失败,标记服务器为宕机;
⑤、Type:选择MySQL;
⑥、Script Name:点击其后的“Browse...”按钮,选择我编写的MySQL Slave健康检查脚本“nsmysql-slave.pl”;
⑦、Dispatcher IP和Dispatcher Port必须填“127.0.0.1”和“3013”,不要改变;
⑧、User Name输入刚才创建的帐号“netscaler“,password输入创建帐号时设定的“12345678”。
6、点击【Load Balancing】──【Service Groups】栏的“add”按钮,添加一个名为“pool_mysql”的MySQL服务器池:
①、添加真实MySQL Slave服务器到“pool_mysql”服务器池,协议选择TCP:
②、健康检查方式选择第5步中创建的“mysql_slave”:
7、点击【Load Balancing】──【Virtual Servers】栏的“add”按钮,添加一个名为“vs_mysql_slave”的VIP(虚拟IP):
①、添加“pool_mysql”服务器池到名为“vs_mysql_slave”的VIP(192.168.1.5:3306),协议选择TCP:
②、负载均衡方式选择Least Connection(最小连接数):
8、Web服务器要访问MySQL Slave,只需访问NetScaler的VIP──192.168.1.5的3306端口即可。至此,已经完美解决多台MySQL Slave数据库的负载均衡问题。
[文章作者:张宴本文版本:v1.1 最后修改:2008.07.17 转载请注明出自:http://blog.s135.com]