php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #78825 stream_socket_client works slower than expect
Submitted: 2019-11-17 12:28 UTC Modified: 2020-01-18 17:50 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: vibbow at hotmail dot com Assigned:
Status: Verified Package: Performance problem
PHP Version: 7.4.1 OS: Windows Server 2019
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2019-11-17 12:28 UTC] vibbow at hotmail dot com
Description:
------------
In my test script, I use two method to create a tcp connection (to another pc in LAN), one is socket_connect, another is stream_socket_client.

Since those two code snips doing the same thing, they should have same time cost.

But on Windows platform, stream_socket_client are must slower than except.

socket_create are using less 1ms in average,
stream_socket_client are using around 10ms in average.

Can be reproduced from PHP 7.1 to 7.3

Can be reproduced on Windows 2019 & Windows 10 1909.



Test script:
---------------
<?php

$begin = microtime(true);
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, '192.168.163.110', 6379);
$end = microtime(true);
echo ($end - $begin) * 1000 . PHP_EOL;


$begin = microtime(true);
$fp = stream_socket_client("tcp://192.168.163.110:6379");
$end = microtime(true);
echo ($end - $begin) * 1000 . PHP_EOL;

Expected result:
----------------
socket_create & stream_socket_client should use similier time cost

Actual result:
--------------
D:\Websites>php test.php
1.1060237884521
10.412216186523

stream_socket_client use 10 times time than socket_create

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-11-17 12:33 UTC] vibbow at hotmail dot com
This issue can be reproduced on Windows platform only, on Linux everything works fine.

This issue may also affect php extension who used php_stream API, like phpredis.
 [2019-11-17 13:40 UTC] cmb@php.net
-Status: Open +Status: Feedback -Package: Sockets related +Package: Performance problem -Assigned To: +Assigned To: cmb
 [2019-11-17 13:40 UTC] cmb@php.net
I can't reproduce this; I get something like:

0.83518028259277
0.43416023254395

Similar if I use hrtime() for measuring the performance.

Which exact PHP version do you use?
 [2019-11-17 13:44 UTC] vibbow at hotmail dot com
I can get this reproduced on:

Windows 10 1909 x64

PHP 7.3.11 x64 nts
PHP 7.3.1 x64 nts
PHP 7.2.9 x64 nts
PHP 5.6.9 x64 nts

If stream_socket_client connect to a local interface ip address, then everything works fine.

It can only reproduced by connect to another PC on same network.
 [2019-11-17 13:48 UTC] vibbow at hotmail dot com
It can also be reproduced on Windows Server 2019
 [2019-11-17 22:42 UTC] cmb@php.net
-Status: Feedback +Status: Open
 [2019-11-18 12:35 UTC] cmb@php.net
Hmm, I cannot reproduce this when connecting to another machine on
the same network, where one runs Windows 10 1903 and the other
Windows 10 1909 (tested both directions).  Tested with PHP 7.3.11
x64 NTS.
 [2019-11-18 15:22 UTC] vibbow at hotmail dot com
That'e weird, I can consistent reproduce this issue.


I'll try to replicate my environment on a cloud server and try again.
 [2019-11-18 19:26 UTC] vibbow at hotmail dot com
I tried to reproduce this issue on 4 different environment, 3 environment can reproduce this issue, 1 environemtn can't reproduce this issue.

First I enhanced the test script a little bit, so I can see the overall trend.
https://gist.github.com/vibbow/8909ffc9990023129562e8971fe30f7d

This script will return four number at end of test:
1000 | 0 | 239 | 761
1st and 2nd number are latency below & above 5ms when using socket_create
3rd and 4th number are latnecy below & avobe 5ms when using stream_socket_client

Next is my four enviroment and test results:

 - First environment:
Two Physical Machine
Machine One
    Running Windows 10 1909 x64 ´╝łAgent A)
Machine Two
    Running Windows Server 2019 with Hyper-V enabled (Agent B)
    Running Ubuntu Server 19.10 as Hyper-V Guest (Agent C)

Result:
Agent A -> Agent C
    992 | 8 | 157 | 843
Agent B -> Agent C
    1000 | 0 | 106 | 894
Agent B -> Agent A
    994 | 6 | 53 | 947


- Second environment:
One Physical Machine
Machine One:
    Running VMware ESXi 6.7
    Running Windows Server 2019 as ESXi Guest (Agent A)
    Running Ubuntu Server 18.04 as ESXi Guest (Agent B)

Result:
Agent A -> Agent B
    1000 | 0 | 239 | 761


- Third environment:
One Physical Machine
Machine One:
    Running Windows 10 LTSC 2019 with Hyper-V Enabled (Agent A)
    Running Ubuntu Server 18.04 as Hyper-V Guest (Agent B)

Result:
Agent A -> Agent B
    1000 | 0 | 23 | 977


- Fourth environment:
Two VIRTUAL machine (on vultr.com)
VM1: Windows Server 2019 (Agent A)
VM2: Ubuntu Server 19.04 (Agent B)

Result:
Agent A -> Agent B
    999 | 1 | 1000 | 0
 [2019-11-18 19:41 UTC] vibbow at hotmail dot com
I'm using minimum PHP config to reproduce this issue:

By copy php.ini-production config file with add following two lines:

extension_dir = ".\ext\"
extension = sockets
 [2019-11-18 19:51 UTC] vibbow at hotmail dot com
I'll try to run this test on two physical machine without any virtualization installed.
 [2019-11-18 23:03 UTC] vibbow at hotmail dot com
I can get this reproduced on my laptop without any virtualization software installed, so it's not virtualizaiton software related issue.

Still try to figure out what's the key point to affect this.
 [2019-12-23 12:02 UTC] vibbow at hotmail dot com
Just tried this on a clean install PC.

Dell Optiplex 3060, with windows 10 1909 x64
Only PHP and VC runtime, no other software

Still can get this reproduced.

https://gist.github.com/vibbow/8909ffc9990023129562e8971fe30f7d
 [2019-12-23 12:21 UTC] cmb@php.net
Thanks for the update!  So far I suspect Windows 10 1909 causing
the issue.  Will have to check with that version.
 [2019-12-23 12:24 UTC] vibbow at hotmail dot com
My server environment is Windows server 2019 (same build number as windows 10 1809) and still can get this reproduced.

So this issue is not strict to windows 10 1909
 [2020-01-02 12:34 UTC] cmb@php.net
-Status: Assigned +Status: Verified -Assigned To: cmb +Assigned To:
 [2020-01-02 12:34 UTC] cmb@php.net
In the meantime (for whatever reason) I have been able to
reproduce a noticeable performance difference.

The relevant difference between socket_connect() and the
respective part of stream_socket_client() appears to be that the
latter switches the socket to non-blocking mode before
connect()[1], and then poll()s to wait for the connection to be
established.  Since there is no poll() on Windows, an emulation[2]
is used, which might explain the performance difference.  However,
if I enforce using the poll emulation on Linux, that's only
marginally slower.  If I skip setting the socket non-blocking,
performance is very close to socket_connect(), but doing so would
ignore configured timeouts, and as such is not an option.

Another noteworthy difference is that Windows explicitly calls
shutdown() and poll() before closesocket() is called[3].

This issue certainly deserves further investigation, but doesn't
appear of high priority, so I'm unassigning myself for now.  Maybe
someone else has some time to look into this?

[1] <https://github.com/php/php-src/blob/php-7.3.13/main/network.c#L306>
[2] <https://github.com/php/php-src/blob/php-7.3.13/main/network.c#L1197>
[3] <https://github.com/php/php-src/blob/php-7.3.13/main/streams/xp_socket.c#L201-L212>
 [2020-01-02 12:39 UTC] vibbow at hotmail dot com
This bug also effect some pecl extension whom use stream_socket_client to create connection.

The one I know is redis extension.
 [2020-01-02 16:32 UTC] cmb@php.net
If this performance issue affects PECL/redis, I suggest that you
file that as issue there; at least the maintainers would become
aware of that, and maybe one of them would have a look at the
issue in the PHP stream layer.
 [2020-01-09 13:58 UTC] vibbow at hotmail dot com
I think I found a workaround for this issue:

https://www.fixwindowserrors.biz/blog/disable-nagle-algorithm-in-windows-10

Add TcpAckFrequency and TCPNoDelay to registry (to disable TCP_NODELAY) did solve the problem.


So this issue is related to TCP_NODELAY feature.
 [2020-01-09 14:43 UTC] vibbow at hotmail dot com
Above registry modify only take effect on some of my PC, not all of them.

There must be something else affect this.
 [2020-01-18 17:50 UTC] vibbow at hotmail dot com
-Summary: stream_socket_client works slower than except +Summary: stream_socket_client works slower than expect -PHP Version: 7.3.11 +PHP Version: 7.4.1
 [2020-01-18 17:50 UTC] vibbow at hotmail dot com
Can still be reproduced in PHP 7.4.1
 
PHP Copyright © 2001-2020 The PHP Group
All rights reserved.
Last updated: Sat Jul 11 22:01:24 2020 UTC