Comparing communication speed between different machines in PHP

For a project we needed some sort of inter-server communication. Due to performance critical tasks like Click Tracking we decided that we need to investigate first the most reliable and fastest way to communicate.

1. Using Sockets

I created a Test Socket Server using more or less the demo script under http://de.php.net/sockets . This Server just takes what he receives and send it back. What is not implemented is multi threading and optimization - but it should be enough to get some reasonable results.

The Test Server looks like this…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
do {
 
 if (FALSE === ($buf = socket_read ($msgsock, 2048))) {
 
 	echo "socket_read() fehlgeschlagen: Grund: ";
 
 	echo socket_strerror ($ret) . "n";
 
 	break 2;
 
 }	if (!$buf = trim ($buf)) {
 
 	continue;
 
 }
 
if ($buf == 'quit') {
 
 	break;
 
 }
 
if ($buf == 'shutdown') {
 
 	socket_close ($msgsock);
 
 	break 2;
 
 }
 
$buf .= "n";
 
 socket_write ($msgsock, $buf, strlen ($buf));
 
} while (true);
 
 socket_close ($msgsock);
 
} while (true);

Now we need to create some client. In our case we keep the connection open so we could avoid opening and closing sockets. The client for testing looks like this:

1
2
3
4
5
$sh = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
 
if (! socket_connect( $sh, '192.168.20.33', 10000) )
 
die( 'Could not bind to Socket!'.PHP_EOL);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$dStart = microtime( true);
 
for( $iIdx = 0; $iIdx < $iMaxCyles; $iIdx++) {
 
 $aClient[$iIdx] = $iIdx;
 
 $aData = array( 'iIdx' => $iIdx );	// call
 
 $aRes = Comm_Socket( $sh, $aData);
 
 $sResult = $aRes['iIdx'];
 
$aServer[$iIdx] = $sResult;
 
}
 
$dDuration = microtime( true) - $dStart;
 
echo( $iMaxCyles." calls total: $dDuration sec. ".PHP_EOL);
 
echo( "Average:  ".$dDuration/$iMaxCyles." sec. per call ".PHP_EOL.PHP_EOL);
 
$aLost = array_diff( $aClient, $aServer);
 
if( count( $aLost)) {
 
 echo( "lost call/differences:".PHP_EOL);
 
 print_r( array_diff( $aClient, $aServer));
 
}

where as function Comm_Socket looks quite simple:

1
2
3
4
5
6
7
8
9
10
11
function Comm_Socket( $Socket, $mPostData)
 
{
 
 $sMessage = serialize( $mPostData);	socket_write( $Socket, $sMessage, strlen( $sMessage));
 
 $sRet = socket_read( $Socket,512,PHP_NORMAL_READ);
 
return unserialize( $sRet);
 
}

The results look like this:

1000 calls total: 0.473767995834 sec.
Average: 0.000473767995834 sec. per call

2. Using http via file_get_contents

Now let’s modify our testscript a bit and change our server so, that he takes any POST parameter and echo’s it.
This is easy to do - and our Client Function looks now like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function Comm_File_Get_Contents( $sUri, $mPostData)
 
{
 
 $fTimeout = 20;	$sHttpPostQuery =  http_build_query ( $mPostData );
 
$aStreamContextOpts = array(
 
 'http'=>array(
 
 'method'  => 'POST',
 
 'header'  => 'Content-type: application/x-www-form-urlencoded',
 
 'content' => $sHttpPostQuery
 
 )
 
);
 
$oContext = stream_context_create ( $aStreamContextOpts );
 
// inject a request read timeout
 
$aAddOpts = array(
 
'http' => array('timeout' => (float) $fTimeout )
 
);
 
stream_context_set_option( $oContext, $aAddOpts );
 
$sResponse = file_get_contents ( urldecode($sUri), false, $oContext );
 
return $sResponse;
 
}

Ok the results are quite interesting:

1000 calls total: 4.02230811119 sec.
Average: 0.00402230811119 sec. per call

Nearly 10 times slower compared to our Socket communication. For sure - by using lighttpd and tweaking the system we could improve performance - but still it’s a lot slower.

Also interesting are the results when we call the server not by IP but by URI - then the results look a lot worse:

1000 calls total: 156.423214912 sec.
Average: 0.156423214912 sec. per call

This is probably because our nslookup is quite slow ( we run Microsoft Small Business Server ) but still - the differences are dramatically.

Actually I could sum up now - but for the records I will try also the cURL way.

3. Using http via cURL

For using cURL we have to modify our client function a bit - the server can be left untouched.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
function Comm_cUrl( $sUri, $mPostData)
 
{
 
$mOptions = array( 'host' => $sUri,
 
'port' => 80,
 
'method' => 'POST',
 
'timeout' => 3,
 
'params' => $mPostData);$ch = curl_init();
 
curl_setopt( $ch, CURLOPT_URL, $sUri );
 
curl_setopt( $ch, CURLOPT_HEADER, 0 );
 
curl_setopt( $ch, CURLOPT_USERAGENT, @$_SERVER['HTTP_USER_AGENT'] );
 
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1 );
 
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
 
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 );
 
if (  'POST' == $mOptions['method'] ) {
 
curl_setopt( $ch, CURLOPT_POST, 1 );
 
$sPostString = "";
 
foreach( $mOptions['params'] as $key => $value ) {
 
$sPostString .= "$key=" . utf8_encode( $value ) . "&";
 
}
 
$sPostString = substr( $sPostString, 0, -1 );
 
curl_setopt( $ch, CURLOPT_POSTFIELDS, $sPostString );
 
}
 
$mData = curl_exec( $ch );
 
curl_close( $ch );
 
return $mData;
 
}

Using IP we get these results:

1000 calls total: 3.17922592163 sec.
Average: 0.00317922592163 sec. per call

Interesting - a bit faster then with file_get_contents.

Finally let’s also try an URI and we get:

1000 calls total: 4.69447493553 sec.
Average: 0.00469447493553 sec. per call

So - cURL obivously caches the nslookup what leads to much better results.

4. Conclusion

More or less we got what we expected. Taking into account that multi threaded socket communication is a real beast and can cause a lot of trouble my personal opinion is that http will work fine for us. There is a lot of potential of speeding things up - so the difference is tolerable for us. This might be different for you ;)

Results:
Time    Avg      Typeof
0.47    0.00047	 Socket
4.02    0.00402	 file_get_contents
156.42  0.15642  file_get_contents by uri
3.17    0.00317  curl
4.69    0.00469  curl by uri

Comments

2 Responses to “Comparing communication speed between different machines in PHP”

  1. Usergroup Thüringen » Blog Archive » PHP Communications Comparison on August 21st, 2007 12:06 pm

    [...] Comparing communication speed between different machines in PHP [...]

  2. robert on June 13th, 2008 2:53 pm

    oh thanks.. everything i looked for :)

Leave a Reply