-
Notifications
You must be signed in to change notification settings - Fork 369
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ubiquity php-pm High concurrency level benchmark #456
Comments
Ping @marcj I could imagine that degrading performance at higher concurrency lavels might be due to only having a single incoming process for all connections? What really discomforts me again is the unclear slave not responding errors. Do you have any idea how to improve logging to catch those? |
@jcheron regarding your config you should adjust the number of workers with the level of parallelism. Each worker will only handle a single request at a time. Once you have more requests than the workers can handle the requests will start queuing up at the master and worst case time out before handed to the slave. Ppm log output for your test cases would be helpful, too. Also- as far as Ubiquit goes- are you really sure that you‘re not starting an entire application instead of just processing a request in https://github.com/phpMv/ubiquity-php-pm/blob/master/src/PHPPM/Ubiquity.php#L55? |
@andig
When I activate the logging at php-pm server starting, all requests return a status of 200 until we get to the warnings. with -vvv: If I increase the total number of requests to be made, I realize that the problems always occur on the last 10 percent.
Yes, the |
I didn't notice anything wrong on the framework side by enabling all the log and error display possibilities. By removing any reference to the framework in the public function handle(ServerRequestInterface $request): ResponseInterface {
return new \React\Http\Response(200, ['Content-Type'=>'text/plain'], 'Hello World!');
} I still have the same warnings with concurrency 512
|
Do you see any chance of adding logging in the bridge? Does the bridge even receive those stray requests or does the redponse somehow get stuck? |
I added logging in the bridge. But stray requests do not go through there. |
Then the next step would be to find out if the slave even receives the request or if it gets stuck in the master. Could you also find out if the slave ever sees an incoming connection in those cases? |
Until we find a solution to the high concurrency level problem, I will remove the Ubiquity-react (php-pm) benchmark from the TechEmpower results. For now, it's bad publicity for php-pm as much as it is for Ubiquity. |
Hi @jcheron the problems were the same when running 512 php-pm slaves? As I can see in your repo, php-pm is only given 64 slaves, no? |
@acasademont Some of the TechEmpower tests go up to a concurrency level of 16 384 (Plaintext benchmark)... |
@jcheron php-pm behaves exactly the same way as php-fpm, it can only process one request at a time per worker. Therefore, if you use a concurrency level of 512 but you limit the number of workers to 64, you're artificially limiting the number of requests than can be managed concurrently. In an ideal world you're right, the number of workers should equal the number of processors (it's what you do in nginx, for example), but php is not an async language, any IO call would block the whole process. That's why php-pm decided to go for the safer approach of limiting one concurrent request per worker. If you have a min_children directive set in the php-fpm config, the same number should be given to php-pm. We might then encounter other problems (for sure!), but at least we're giving php-pm the minimum number of resources it needs :p |
@acasademont we still have the |
Yes, definitely, we should address that problem too, but I wanted to start with a fair comparison first :p I'll try to replicate the issue and see what I can find 👌 |
@acasademont So for now I'm removing So I tried it with 16, 32, 64 and 128 workers, without seeing any real impact on performance. |
I've looked some more into this. It is definitely a problem in the core:
With 32 concurrent it will almost always work. If it breaks we'll have these messages in the log:
|
More experiments. I've started giving the slaves ids to trace requests across log messages by slave. Running this with only a single worker:
Test dies after only a single request, but only if we chose a high concurrency level! |
/cc @WyriHaximus might I ask you if you've seen something like the comment above before where reactphp might get stuck on high concurrency levels? |
@andig only seen this happen with |
Taking a look at this today, let's see what we can find! |
@acasademont you know where to find me if you do ;) |
Thanks @acasademont. I‘m concentrating on programming an ev charge controller- so many projects, so little time... |
I'm starting from the basics, just a simple "ab -n 2 -c 2 http://127.0.0.1:8080/" First weird thing I saw:
Things that we could definitely improve:
Thoughts? @andig @WyriHaximus On the slaves we could also start a simpler http server without the default reactphp middlewares, knowing that the master has already done the hard work for us. |
In any case, to continue with this, we should not emit that |
I ended up doing some tcpdumps to see why A simple reactphp server: <?php
include __DIR__.'/vendor/autoload.php';
$loop = React\EventLoop\Factory::create();
$server = new React\Http\Server(function (Psr\Http\Message\ServerRequestInterface $request) {
return new React\Http\Response(
200,
array('Content-Type' => 'text/plain'),
"Hello World!\n"
);
});
$socket = new React\Socket\Server(8080, $loop);
$server->listen($socket);
echo "Server running at http://127.0.0.1:8080\n";
$loop->run(); an will yield errors most of the time. For comparison, I created a nodejs server const http = require('http')
const requestHandler = (request, response) => {
response.end('Hello World!')
}
const server = http.createServer(requestHandler)
server.listen(8080, (err) => {
if (err) {
return console.log('something bad happened', err)
}
console.log('Server running at http://127.0.0.1:8080')
}) and dealt with that concurrency level just fine. |
Attaching the tcpdumps capture for both reactphp and node if that might help. |
Tried it also with another benchmark tool written in go called hey (https://github.com/rakyll/hey). Doesn't miserably fail on the first connection reset like AB, but it still does fail quite often compared to the nodejs server (also much slower, but that's another issue I guess :p) |
@acasademont I've also been playing around with https://k6.io/ lately, different approach but might be interesting to check out as well as you can use it as a unit test to make sure everything works as intended during different levels of load. |
@WyriHaximus seems like the problem is a very low TCP backlog value by default on PHP streams (32). php-pm should probably set a specific (and configurable) parameter for that...After increasing it to 128 everything works fine! |
@acasademont awesome! |
See #488 for fix. Confirmation this is solved in HEAD would be great. |
There are other things we could do to improve performance for sure, but at least the test shouldn't miserably fail anymore @jcheron would be great if you could try again! |
Thank you for your work! |
I wouldn't do that as it would really increase latency. If a client connects we can be fairly certain that it should have a valid request? Seems the "client went away" errors were part of #488.
That sounds like an excellent idea. As far as I remember that server didn't exist yet when I refactored PPM. Now it seems like a good idea to move to the streaming server implementation? |
ping @jcheron any news? |
Sorry, @andig , I didn't forget. Json test with 72 workers on an i7-8750H (6 cores, 12 threads): |
It's hard to say from looking at the screenshots as they show different results, but do you notice any difference to the situation before? It seems the number of warnings has reduced but they still exist. Did performance increase in any way at concurrency levels above 30? |
Mmm, in your screenshot i can only see 4 errors after 81k(!!) requests and
the test finished. I’d say this is a pretty noticeable improvement, no? I’m
I missing something?
…On Tue, 14 Jan 2020 at 08:21, andig ***@***.***> wrote:
It's hard to say from looking at the screenshots as they show different
results, but do you notice any difference to the situation before? It seems
the number of warnings has reduced but they still exist. Did performance
increase in any way at concurrency levels above 30?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#456?email_source=notifications&email_token=AAGJNPIU76X5W7NCKZOBIBLQ5VRZJA5CNFSM4HUTANAKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEI3SLTA#issuecomment-574039500>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAGJNPIVZT5NCV4RBTLIXLTQ5VRZJANCNFSM4HUTANAA>
.
|
I think it's better too, there are fewer error messages. But even if the test passes, the results are not satisfactory:
I benchmarked by varying the number of requests, the duration, the concurrency level, |
I find it hard to understand how the heck you can do 57k req/s on a standard php-fpm installation with apache. Is it possible to have the test reproducer? |
I think that HTTP keep alive might be playing an important role here... |
The 57k on my computer is not out of proportion to the runs on TechEmpower. echo \json_encode ( [ 'message' => 'Hello, World!' ] ); For Ubiquity, you can reproduce in :
For php-pm, I use this docker file:
I'll try without the Http keep-alive. |
@jcheron what OS do you use? |
@marcj Ubuntu 16.04.6 LTS |
TechEmpower runs the tests using PHP-FPM, right? How many CPU cores are they using? I doubt that PHP-FPM is able to pull those numbers, even with very simple hello world scripts, since even Apache out of the box isn't able to pull those numbers for serving static files. From my experience even nginx has troubles going to 500k req/s serving static files (which is way easier than using cgi protocol and communicate with a PHP interpreter). It seems those are in-php loop tests where something like the http-kernel/react-http abstraction is called without external http servers like apache/nginx involved, might this be the case? If so, the whole comparison is flawed. |
What unattainable number are you talking about? I don't get it. |
Hi,
I implemented a PHP-PM adapter for Ubiquity framework, which I test the performance on TechEmpower benchmarks.
For the moment, the results are not conclusive (see Ubiquity and Ubiquity-react).
For the Multiple Queries test, which requires a connection to the database and could have benefited php-pm, I have the following results:
Responses per second for multiple queries test (1, 5, 10, 15, 20), concurrency level of 512:
The source code and configuration are available on TechEmpower repository.
The PHP-PM test (currently called Ubiquity-react) uses php-pm as a web server and load balancer.
Dockerfile to build & run is ubiquity-react.dockerfile.
I have the same symptoms as @oozone with Laravel (see #453): poor performance, and warning on some requests:
Script did not return a valid HTTP response. Maybe it has called exit() prematurely?
I also tried to manually test the script with ab:
At concurrency level 5, php-pm is more efficient than php-fpm
PHP-PM
Apache
If I increase the concurrency level, performance degrades for php-pm:
PHP-PM
Apache
TechEmpower multiple query tests are run at 512 concurrency...
At this level, my php-pm use generates warnings.
The results are the same for the other tests (Plaintext or Json).
I wonder if I'm doing something wrong somewhere.
The adjustment of the number of workers does not change much in this context.
The text was updated successfully, but these errors were encountered: