├── README.md └── mysqlchk.mysql /README.md: -------------------------------------------------------------------------------- 1 | # mysqlchk 2 | 3 | Based on ClusterControl's mysqlchk script but built for MySQL Replication. It detects the MySQL replication role on the database node as per below: 4 | 5 | * if master (``read_only = OFF``), 6 | * return 'MySQL master is running.' 7 | 8 | * if slave (``Slave_IO_Running = Yes`` AND ``Slave_SQL_Running = Yes`` AND (``Seconds_Behind_Master = 0`` OR ``Seconds_Behind_Master < SLAVE_LAG_LIMIT``)) 9 | * return 'MySQL slave is running. (slave lag: 0)' 10 | 11 | * else 12 | * return 'MySQL is \*down\*' 13 | 14 | # How to use 15 | 16 | 0) Deploy or add existing MySQL Replication setup into ClusterControl 17 | 18 | 1) Install HAProxy on the your selected node. ClusterControl will install the default mysqlchk that need to be replaced with this one on each of the database node. By default, it's located under ``/usr/local/sbin/mysqlchk`` 19 | 20 | 2) Grab the file from this repo and replace it. 21 | 22 | 3) Update require information (``SLAVE_LAG_LIMIT`` is in seconds): 23 | ```bash 24 | SLAVE_LAG_LIMIT=5 25 | MYSQL_HOST="localhost" 26 | MYSQL_PORT="3306" 27 | MYSQL_USERNAME='root' 28 | MYSQL_PASSWORD='password' 29 | ``` 30 | 4) You are good to go. Now ensure in HAProxy you have 2 listeners (3307 for write, 3308 for read) and use ``option tcp-check`` & ``tcp-check expect`` to distinguish master/slave similar to example below: 31 | ```bash 32 | listen haproxy_192.168.55.110_3307_write 33 | bind *:3307 34 | mode tcp 35 | timeout client 10800s 36 | timeout server 10800s 37 | balance leastconn 38 | option tcp-check 39 | tcp-check expect string MySQL\ master 40 | option allbackups 41 | default-server port 9200 inter 2s downinter 5s rise 3 fall 2 slowstart 60s maxconn 64 maxqueue 128 weight 100 42 | server 192.168.55.111 192.168.55.111:3306 check 43 | server 192.168.55.112 192.168.55.112:3306 check 44 | server 192.168.55.113 192.168.55.113:3306 check 45 | 46 | listen haproxy_192.168.55.110_3308_read 47 | bind *:3308 48 | mode tcp 49 | timeout client 10800s 50 | timeout server 10800s 51 | balance leastconn 52 | option tcp-check 53 | tcp-check expect string is\ running. 54 | option allbackups 55 | default-server port 9200 inter 2s downinter 5s rise 3 fall 2 slowstart 60s maxconn 64 maxqueue 128 weight 100 56 | server 192.168.55.111 192.168.55.111:3306 check 57 | server 192.168.55.112 192.168.55.112:3306 check 58 | server 192.168.55.113 192.168.55.113:3306 check 59 | ``` 60 | -------------------------------------------------------------------------------- /mysqlchk.mysql: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This script checks if a mysql server is healthy running on localhost. It will 4 | # return: 5 | # "HTTP/1.x 200 OK\r" (if mysql is running smoothly) 6 | # - OR - 7 | # "HTTP/1.x 500 Internal Server Error\r" (else) 8 | # 9 | # The purpose of this script is make haproxy capable of monitoring mysql properly 10 | # 11 | 12 | SLAVE_LAG_LIMIT=5 13 | MYSQL_HOST="localhost" 14 | MYSQL_PORT="@MYSQL_PORT@" 15 | MYSQL_USERNAME='@MYSQL_USER@' 16 | MYSQL_PASSWORD='@MYSQL_PASSWORD@' 17 | MYSQL_BIN='@MYSQL_BIN@' 18 | MYSQL_OPTS="-q -A --connect-timeout=10" 19 | TMP_FILE="/dev/shm/mysqlchk.$$.out" 20 | ERR_FILE="/dev/shm/mysqlchk.$$.err" 21 | FORCE_FAIL="/dev/shm/proxyoff" 22 | 23 | preflight_check() 24 | { 25 | for I in "$TMP_FILE" "$ERR_FILE"; do 26 | if [ -f "$I" ]; then 27 | if [ ! -w $I ]; then 28 | echo -e "HTTP/1.1 503 Service Unavailable\r\n" 29 | echo -e "Content-Type: Content-Type: text/plain\r\n" 30 | echo -e "\r\n" 31 | echo -e "Cannot write to $I\r\n" 32 | echo -e "\r\n" 33 | exit 1 34 | fi 35 | fi 36 | done 37 | } 38 | 39 | return_ok() 40 | { 41 | echo -e "HTTP/1.1 200 OK\r\n" 42 | echo -e "Content-Type: text/html\r\n" 43 | echo -e "Content-Length: 43\r\n" 44 | echo -e "\r\n" 45 | if [ $role == "master" ]; then 46 | echo -e "MySQL master is running.\r\n" 47 | elif [ $role == "slave" ]; then 48 | echo -e "MySQL slave is running. (Slave lag: $SLAVE_LAG)\r\n" 49 | else 50 | echo -e "MySQL is running.\r\n" 51 | fi 52 | echo -e "\r\n" 53 | # rm $ERR_FILE $TMP_FILE 54 | exit 0 55 | } 56 | return_fail() 57 | { 58 | echo -e "HTTP/1.1 503 Service Unavailable\r\n" 59 | echo -e "Content-Type: text/html\r\n" 60 | echo -e "Content-Length: 42\r\n" 61 | echo -e "\r\n" 62 | echo -e "MySQL is *down*.\r\n" 63 | echo -e "\r\n" 64 | exit 1 65 | } 66 | 67 | preflight_check 68 | 69 | if [ -f "$FORCE_FAIL" ]; then 70 | echo "$FORCE_FAIL found" > $ERR_FILE 71 | return_fail 72 | fi 73 | 74 | CMDLINE="$MYSQL_BIN $MYSQL_OPTS --host=$MYSQL_HOST --port=$MYSQL_PORT --user=$MYSQL_USERNAME --password=$MYSQL_PASSWORD -e" 75 | SLAVE_IO=$(${CMDLINE} 'SHOW SLAVE STATUS' --vertical 2>/dev/null | grep Slave_IO_Running | tail -1 | awk {'print $2'}) 76 | SLAVE_SQL=$(${CMDLINE} 'SHOW SLAVE STATUS' --vertical 2>/dev/null | grep Slave_SQL_Running | head -1 | awk {'print $2'}) 77 | 78 | if [[ "${SLAVE_IO}" == "Yes" ]] && [[ "${SLAVE_SQL}" == "Yes" ]]; then 79 | role='slave' 80 | SLAVE_LAG=$(${CMDLINE} 'SHOW SLAVE STATUS' --vertical 2>/dev/null | grep Seconds_Behind_Master | tail -1 | awk {'print $2'}) 81 | if [[ $SLAVE_LAG = 0 ]]; then 82 | return_ok 83 | elif [ $SLAVE_LAG -lt $SLAVE_LAG_LIMIT ] ; then 84 | return_ok 85 | fi 86 | else 87 | role='master' 88 | READ_ONLY=$($CMDLINE 'SHOW GLOBAL VARIABLES LIKE "read_only"' --vertical 2>/dev/null | tail -1 | awk {'print $2'}) 89 | [[ "${READ_ONLY}" == "OFF" ]] && return_ok 90 | fi 91 | 92 | return_fail 93 | --------------------------------------------------------------------------------