HAProxy is able to load balance MySQL wonderfully. The main issue is how to make sure that the backend MySQL server to forward the request to is up and running (I mean not just to establish a connection to port 3306, I mean something more “complete”, that performs a little operation against the MySQL server).
It is possible to make haproxy check the status of a mysql server using a small shell script managed through the xinetd daemon.
What this script basically does is performs a basic operation against the mysql database then returns http status 200 if the operation was successful or http status 500 if it there was any error (i.e. mysql was not available).
Script
The script looks like this:
#!/bin/bash # # This script checks if a mysql server is healthy running on localhost. It will # return: # # "HTTP/1.x 200 OKr" (if mysql is running smoothly) # # - OR - # # "HTTP/1.x 500 Internal Server Errorr" (else) # # The purpose of this script is make haproxy capable of monitoring mysql properly # # Author: Unai Rodriguez # # It is recommended that a low-privileged-mysql user is created to be used by # this script. Something like this: # # mysql> GRANT SELECT on mysql.* TO 'mysqlchkusr'@'localhost' # -> IDENTIFIED BY '257retfg2uysg218' WITH GRANT OPTION; # mysql> flush privileges; MYSQL_HOST="localhost" MYSQL_PORT="3306" MYSQL_USERNAME="mysqlchkusr" MYSQL_PASSWORD="secret" TMP_FILE="/tmp/mysqlchk.out" ERR_FILE="/tmp/mysqlchk.err" # # We perform a simple query that should return a few results :-p # /usr/bin/mysql --host=$MYSQL_HOST --port=$MYSQL_PORT --user=$MYSQL_USERNAME --password=$MYSQL_PASSWORD -e"show databases;" > $TMP_FILE 2> $ERR_FILE # # Check the output. If it is not empty then everything is fine and we return # something. Else, we just do not return anything. # if [ "$(/bin/cat $TMP_FILE)" != "" ] then # mysql is fine, return http 200 /bin/echo -e "HTTP/1.1 200 OKrn" /bin/echo -e "Content-Type: Content-Type: text/plainrn" /bin/echo -e "rn" /bin/echo -e "MySQL is running.rn" /bin/echo -e "rn" else # mysql is fine, return http 503 /bin/echo -e "HTTP/1.1 503 Service Unavailablern" /bin/echo -e "Content-Type: Content-Type: text/plainrn" /bin/echo -e "rn" /bin/echo -e "MySQL is *down*.rn" /bin/echo -e "rn" fi
Steps on the MySQL server
First, you should create the script somewhere, and assign proper permissions:
chown nobody /opt//mysqlchk chmod 744 /opt//mysqlchk
Then, set permissions into the mysql server:
mysql> GRANT SELECT on mysql.* TO 'mysqlchkusr'@'localhost' -> IDENTIFIED BY 'secret' WITH GRANT OPTION; mysql> flush privileges; mysql> exit
Test:
/opt/mysqlchk HTTP/1.x 200 OK
Now, configure xinetd by adding this line at the bottom of /etc/services:
mysqlchk 9200/tcp # mysqlchk
Then add this file /etc/xinetd.d/mysqlchk:
# default: on # description: mysqlchk service mysqlchk { flags = REUSE socket_type = stream port = 9200 wait = no user = nobody server = /opt/mysqlchk log_on_failure += USERID disable = no only_from = 0.0.0.0/0 # recommended to put the IPs that need # to connect exclusively (security purposes) per_source = UNLIMITED # Recently added (May 20, 2010) # Prevents the system from complaining # about having too many connections open from # the same IP. More info: # http://www.linuxfocus.org/English/November2000/article175.shtml }
Restart xinetd (you can watch for issues on /var/log/syslog):
/etc/init.d/xinetd stop /etc/init.d/xinetd start
Test:
telnet localhost 9200 Trying 127.0.0.1... Connected to localhost.localdomain. Escape character is '^]'. HTTP/1.1 200 OK Content-Type: Content-Type: text/plain MySQL is running. Connection closed by foreign host.
Steps on the HAProxy server
Now, in order to make haproxy check the status of the mysql service through the xinetd-managed-script, we should add something similar to this on the haproxy.cfg file:
listen MySQL 10.135.2.67:3306 mode tcp option httpchk server 10.135.2.69:3306 10.135.2.69:3306 check port 9200 inter 12000 rise 3 fall 3 source 10.135.2.67
What is important?
- option httpchk.- tells haproxy to check for full http response (i.e. http headers: 2xx OK or 5xx ERROR)
- check port XXXX.- tells haproxy to check the status of the service by sending an http request on that port
Comments
0 responses to “Having HAProxy check mysql status through a xinetd script”
[…] modified the mysqlchk_status.sh script found at SysBible with my […]
One thing which is not mentionned here, is that you will need to open your firewall accordingly.
In this case, protocol TCP on port 9200.
Otherwise, it works perfectly!
That is correct Gael, thank you for pointing it out.
Thanks for this! The only thing I found I needed to change was:
server = /opt/mysql-xinetd-monitor/mysqlchk
changed to
server = /opt/mysqlchk
[…] requests to the non-working slave. For this I referenced a tutorial written by Unai Rodriquez – Having HAProxy check mysql status through a xinetd script Essentially, you just create a xinetd service that listens on port 9200 and returns an HTTP status […]
Dear John,
Thank you so much for the feedback! I have just updated the doc.
Thanks, it helps a lot.
How does the replication works? For instance I make an Insert and the haproxy sends the request for 1 server. How does it propagates to the other mysqlServer?
MySQL’s replication will take care of inserting that same data into the other server(s). More info: http://dev.mysql.com/doc/refman/5.0/en/replication.html
news source…
[…]Sysbible » Blog Archive » Having HAProxy check mysql status through a xinetd script[…]…
SCRiPTzMAFiA.ORG…
[…]Sysbible » Blog Archive » Having HAProxy check mysql status through a xinetd script[…]…