Edit report at https://bugs.php.net/bug.php?id=74178&edit=1
ID: 74178
User updated by: alex at alex-at dot ru
Reported by: alex at alex-at dot ru
Summary: Suggestion/Idea: Stateful / Application Script
Status: Open
Type: Feature/Change Request
Package: FPM related
PHP Version: Next Major Version
Block user comment: N
Private report: N
New Comment:
1000/1.1 is obviously about 909 requests per second per core. With more cores it should be more of
course, but not linearly. And again: it heavily depends on application itself.
In our case, final content is quite small, and will never saturate even 100Mbps. It's using
~50% CPU time in FPM process, and most of that time is taken by script initialization. We need to
reconnect to memcached, to MySQL, open some files for second level cache and pre-connect to ZeroMQ
for case of cache miss (connection and socket start is asynchronous, but takes time). In a case of
both levels cache miss we sometimes need to wait a bit of time for ZeroMQ data to arrive from
publisher. This ZeroMQ magic could be autonomously happening in background if script was running in
'appserver' mode, making latency of cache misses negligible.
Previous Comments:
------------------------------------------------------------------------
[2017-02-27 19:30:50] spam2 at rhsoft dot net
> Man. 1.1 to 3.5 ms response time is good, but not
> any news. It's only 300 to 900 requests per second
check your math!
on a i7 from 2011 it's 1200 request per seconds, on our current hardware it's 4500
requests per second with small contents and with larger contents it saturates easily the gigabit
network and PHP is for sure not the bottenleck
------------------------------------------------------------------------
[2017-02-27 19:22:04] alex at alex-at dot ru
>>> because when you need a app-server than just use a app-server and don't abuse PHP
The whole point of this feature request is that PHP can easily be evolved to utilize best of both
worlds.
Reloading less state is obviously good, but manageability and extensibility of PHP code is obviously
good as well. So when choosing between PHP/niche appserver, it's not an easy choice.
The appserver choice also requires a whole second stack, meaning more developer time and skills are
needed.
>>> that said from a happy user which has generate times between 1.1 and 3.5 ms
Man. 1.1 to 3.5 ms response time is good, but not any news. It's only 300 to 900 requests per
second. Also, what's good in our case can be not attainable for larger applications with larger
state.
I.e. we have a real world running PHP application that handles ~1000 requests per second per 8 cores
as well (2 to 3 requests per second from 300-500 simultaneous 'realtime' clients),
connecting to MySQL and ZeroMQ and keeping a lot of state in multilevel cache.
It really could benefit a lot from appserver strategy... if there was one. Reducing cache complexity
and cutting off all complex state caching code on the way.
------------------------------------------------------------------------
[2017-02-27 19:06:06] spam2 at rhsoft dot net
> So why just not bring common 'appserver' paradigm to PHP?
because when you need a app-server than just use a app-server and don't abuse PHP
if "initialization of all database/cache/etc. connections and classes takes age" the just
seek the bloat in your application - that said from a happy user which has generate times between
1.1 and 3.5 ms including connect to database, load templates, load cached contents just because our
code is designed to have a small footprint and oads things on demand but nothing unneeded
NO don't introduce all sort of bugs and race-conditions by trying to make something out of PHP
which is not PHP - a with little exceptions "shared-nothing" architecture
------------------------------------------------------------------------
[2017-02-27 19:00:41] alex at alex-at dot ru
Elaborating further (of course don't know if the idea is viable as a whole, but nevertheless).
max_execution_time may (should) be counted anew for each request. Something like
max_stateful_execution_time should control total execution time, but only inside run_as_stateful()
code, not at any moment, to make sure last request is complete.
run_as_stateful() never exits but may also be extended with optional $eventHandler and
$eventInterval. If no requests come under $eventInterval microseconds, $eventHandler callback may be
called to process i.e. external ZeroMQ or other events periodically, updating internal state.
From scripts developer perspective, applications handling a lot of state and serving lots of clients
would benefit a lot from lack of 1) code reloading, 2) PHP engine initialization, 3) internal class
reinitialization. Some messaging queues like ZeroMQ can also be used to synchronize state between
running stateful scripts, reducing need to reload any state even further. Also similar mechanisms
can potentially be used for i.e. websocket handling in parallel with handling requests.
------------------------------------------------------------------------
[2017-02-27 18:34:41] alex at alex-at dot ru
Description:
------------
Many current PHP scripts suffer from necessity of (re)initializing lots of state from startup to
real serving. Even using Opcache/Memcached/whatever, initialization of all database/cache/etc.
connections and classes takes ages.
So why just not bring common 'appserver' paradigm to PHP?
Basically, it all boils to implementation of a single function: run_as_stateful($callback, $timeout
= null) or something like that.
What should it do: it should clean up all volatile request and session variables, and make server
know script is ready to accept new request to it. Everything else related to process should remain
intact: variables, classes, objects, database/cache connections, open files, other resources,
whatever.
When a new request to the same script comes, and there is some stateful script process idling,
request gets scheduled to one of these processes. Request variables get filled (session ones do not,
until new session_start call in PHP code), and $callback gets executed. Basically, that's all.
This will allow $callback to skip all the unnecessary initialization, getting through only to
request-based serving.
Once $callback executes, it can either "exit", causing script process to terminate, or
just "return", causing script to wait for a new request, or call run_as_stateful() anew,
refreshing $timeout. Any error of course causes script process to terminate.
$timeout here is a timeout for script process to be waiting for requests (idling) in total (each
period counts, or may be refreshed within $callback), after which process terminates.
If there are no running stateful script processes at the moment of request, request is scheduled to
normal PHP execution strategy, without any changes required.
File change detection can be optionally either ignored or delegated to opcache with its change
detection strategy, and terminate all idling stateful script processes / set terminate flag to all
running stateful script processes so they terminate at next idle loop.
The idea/suggestion is mainly intended for FPM I think, because it has process control and can be
extended with any tunables needed, like maximum lifetime of a stateful script, maximum count of
stateful scripts running (total and per script), list of scripts that are allowed to run as
stateful, etc.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=74178&edit=1