0

Prerequisites

Cluster server

I have a server that runs a number of virtual "cluster nodes". Basically, each one of them is a public, very minimal HTTP server, that has two functions:

127.0.0.1:XXXXn/ping
127.0.0.1:XXXXn/api/arg/arg/arg

Both of those functions return a 200OK header followed by HTML. ping is used to test if the node is busy or not. If node n is busy, the connection will just time out (because the node is busy handling another request). However, if the node is responsive and available, ping will return

PING=NODE.FREE

Calling server

I want to write a PHP program that can be loaded on any webserver to expose a better interface for the API. The following code is from an older API version that only had one node per IP, thus the code was quite simple:

<?php
    error_reporting(0);
    ini_set('display_errors', 0);
    echo file_get_contents("http://127.0.0.1:XXXX9/".$_REQUEST['script']."/".$_REQUEST['query']."/".$_REQUEST['sort']."/".$_REQUEST['num']);
?>

This was, of course, called like

http://server.org/api.php?script=api&query=... (etc.)

and would return results from node #9 (hence XXXX9). There are 10 nodes populating one server, so 10 servers from :XXXX0 to :XXXX9.

The Goal

I want to implement PHP (i.e. webserver-side-) load balancing. Basically, when called, the PHP program should loop through all nodes until one node does successfully return PING=NODE.FREE in less than a specified amount of time.

Since I use file_get_contents, I read up on ways to set a timeout for this. As it turns out, there are quite a few ways, for example using the stream context, or a curl option (instead of file_...). The problem I think I am facing is that each of the options (presented in these answers here and here) is only affecting either the connection or the read.

What I want to check for is, if in the given time (say 1000ms per node), the node connects and returns the message. Then, and only then, the code should proceed to call the API at this node using the above syntax. Of course, if there is no node avail. atm., it should loop until one is free.

Now, what is the best and safest way to set and check for this timeout? If possible, I'd like to avoid fsock, because this is disabled for most managed webservers.

Community
  • 1
  • 1
turbo
  • 1,233
  • 14
  • 36

1 Answers1

0

Solved, using the stream context method:

<?php
error_reporting(0);
ini_set('display_errors', 0);

$streamContext = stream_context_create(array('http'=>
    array(
        'method' => 'GET',
        'timeout' => 1, // timeout in seconds (varies +- 1 sec or so)
    )
));

$iFreeNode = -1;

while (true) {
    for ($i = 0; $i <= 9; $i++) {

        $bNodeAvailable = @file_get_contents('http://127.0.0.1:XXXX'.$i.'/ping', false, $streamContext);

        if ($bNodeAvailable === false) {
            //echo "Node ".$i." busy.<br>";
        } else {
            if ($bNodeAvailable = "PING=NODE.FREE") {
                //echo "Node ".$i." available.<br>";
                $iFreeNode = $i;
                break;
            } else {
                //echo "Node ".$i." busy.<br>";
            }
        }
    }
    if ($iFreeNode > -1) { break; }
}
echo file_get_contents("http://127.0.0.1:XXXX".$iFreeNode."/".$_REQUEST['script']."/".$_REQUEST['query']."/".$_REQUEST['sort']."/".$_REQUEST['num']);
?>
turbo
  • 1,233
  • 14
  • 36