Health checking is the ability to probe a server to ensure the service is up and running. This is one of the root features of any load-balancer.
One can probe servers and services at a different layer of the OSI model:
ARP check (not available in HAProxy)
ICMP (ping) check (not available in HAProxy)
TCP (handshake) check
Application (HTTP, MySql, SMTP, POP, etc…) check
The most representative of the application status of the check is, the best.
This means that the best way to check a service is to “speak” the protocol itself. Unfortunately, it is impossible to write one check per protocol, there are too many protocols and some of them are proprietary and/or binary. That’s why HAProxy 1.5 now embeds a new health checking method called “tcp-check“. It is a very simple and basic “send/expect” probing method where HAProxy can send arbitrary strings and match string or regex comparisons on server responses. Many send and expect can be executed in a row to determine the status of a server.
I’ve already explained how to check Redis server and how to balance traffic only to the Redis master server of a cluster.
Today’s article introduces a binary protocol widely deployed: FastCGI used by php-fpm.
FastCGI Binary Ping/Pong Health Check
FastCGI is a binary protocol. It means data on the network are not readable by humans, like HTTP or SMTP. Php-fpm relies on this protocol to treat PHP code. It is common to use HAProxy to load-balance many php-fpm servers for resiliency and scalability.
Php-Fpm configuration
Enable a dedicated url to probe and setup the response in your php-fpm configuration:
ping.path = /ping
ping.response = pong
HAProxy Health Checking for Php-Fpm
Add the following tcp-check sequence in your php-fpm backend to probe the /ping url and ensure the server answers a “pong“.
The comment at the end of the line describes the php-cgi protocol fields.
option tcp-check
# FCGI_BEGIN_REQUEST
tcp-check send-binary 01 # version
tcp-check send-binary 01 # FCGI_BEGIN_REQUEST
tcp-check send-binary 0001 # request id
tcp-check send-binary 0008 # content length
tcp-check send-binary 00 # padding length
tcp-check send-binary 00 #
tcp-check send-binary 0001 # FCGI responder
tcp-check send-binary 0000 # flags
tcp-check send-binary 0000 #
tcp-check send-binary 0000 #
# FCGI_PARAMS
tcp-check send-binary 01 # version
tcp-check send-binary 04 # FCGI_PARAMS
tcp-check send-binary 0001 # request id
tcp-check send-binary 0045 # content length
tcp-check send-binary 03 # padding length: padding for content % 8 = 0
tcp-check send-binary 00 #
tcp-check send-binary 0e03524551554553545f4d4554484f44474554 # REQUEST_METHOD = GET
tcp-check send-binary 0b055343524950545f4e414d452f70696e67 # SCRIPT_NAME = /ping
tcp-check send-binary 0f055343524950545f46494c454e414d452f70696e67 # SCRIPT_FILENAME = /ping
tcp-check send-binary 040455534552524F4F54 # USER = ROOT
tcp-check send-binary 000000 # padding
# FCGI_PARAMS
tcp-check send-binary 01 # version
tcp-check send-binary 04 # FCGI_PARAMS
tcp-check send-binary 0001 # request id
tcp-check send-binary 0000 # content length
tcp-check send-binary 00 # padding length: padding for content % 8 = 0
tcp-check send-binary 00 #
tcp-check expect binary 706f6e67 # pong
Note that the whole send string could be written on a single line.
Any protocol?
If someday, you have to do the same type of configuration on a protocol nobody knows, simply capture network traffic of a “hello” sequence using tcpdump.
Then send the TCP payload captured using the tcp-check send command and configure the appropriate expectations.
And it will work!
Subscribe to our blog. Get the latest release updates, tutorials, and deep-dives from HAProxy experts.