summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaulius Sapragonas <pauliussap@gmail.com>2021-03-05 20:15:30 +0200
committerJakub Zelenka <bukka@php.net>2021-03-28 20:53:58 +0100
commiteac1609a847f7cca45c9c14e1b9c4d72cea04fd6 (patch)
tree203b80f304ce36679641e96ef5d8c23745858e4d
parent830d38535178920bfaae6e8e8d93fadcba4a1a7e (diff)
downloadphp-git-eac1609a847f7cca45c9c14e1b9c4d72cea04fd6.tar.gz
Max spawn child processes rate an once
* Add functionality to expect log config options
-rw-r--r--sapi/fpm/fpm/fpm_conf.c10
-rw-r--r--sapi/fpm/fpm/fpm_conf.h1
-rw-r--r--sapi/fpm/fpm/fpm_process_ctl.c2
-rw-r--r--sapi/fpm/fpm/fpm_process_ctl.h2
-rw-r--r--sapi/fpm/tests/set-pm-max-spawn-rate.phpt39
-rw-r--r--sapi/fpm/tests/tester.inc42
-rw-r--r--sapi/fpm/www.conf.in8
7 files changed, 100 insertions, 4 deletions
diff --git a/sapi/fpm/fpm/fpm_conf.c b/sapi/fpm/fpm/fpm_conf.c
index 42f75a475d..72772031e4 100644
--- a/sapi/fpm/fpm/fpm_conf.c
+++ b/sapi/fpm/fpm/fpm_conf.c
@@ -132,6 +132,7 @@ static struct ini_value_parser_s ini_fpm_pool_options[] = {
{ "pm.start_servers", &fpm_conf_set_integer, WPO(pm_start_servers) },
{ "pm.min_spare_servers", &fpm_conf_set_integer, WPO(pm_min_spare_servers) },
{ "pm.max_spare_servers", &fpm_conf_set_integer, WPO(pm_max_spare_servers) },
+ { "pm.max_spawn_rate", &fpm_conf_set_integer, WPO(pm_max_spawn_rate) },
{ "pm.process_idle_timeout", &fpm_conf_set_time, WPO(pm_process_idle_timeout) },
{ "pm.max_requests", &fpm_conf_set_integer, WPO(pm_max_requests) },
{ "pm.status_path", &fpm_conf_set_string, WPO(pm_status_path) },
@@ -610,6 +611,7 @@ static void *fpm_worker_pool_config_alloc() /* {{{ */
memset(wp->config, 0, sizeof(struct fpm_worker_pool_config_s));
wp->config->listen_backlog = FPM_BACKLOG_DEFAULT;
+ wp->config->pm_max_spawn_rate = 32; /* 32 by default */
wp->config->pm_process_idle_timeout = 10; /* 10s by default */
wp->config->process_priority = 64; /* 64 means unset */
wp->config->process_dumpable = 0;
@@ -848,7 +850,7 @@ static int fpm_conf_process_all_pools() /* {{{ */
return -1;
}
- /* pm.start_servers, pm.min_spare_servers, pm.max_spare_servers */
+ /* pm.start_servers, pm.min_spare_servers, pm.max_spare_servers, pm.max_spawn_rate */
if (wp->config->pm == PM_STYLE_DYNAMIC) {
struct fpm_worker_pool_config_s *config = wp->config;
@@ -881,6 +883,11 @@ static int fpm_conf_process_all_pools() /* {{{ */
zlog(ZLOG_ALERT, "[pool %s] pm.start_servers(%d) must not be less than pm.min_spare_servers(%d) and not greater than pm.max_spare_servers(%d)", wp->config->name, config->pm_start_servers, config->pm_min_spare_servers, config->pm_max_spare_servers);
return -1;
}
+
+ if (config->pm_max_spawn_rate < 1) {
+ zlog(ZLOG_ALERT, "[pool %s] pm.max_spawn_rate must be a positive value", wp->config->name);
+ return -1;
+ }
} else if (wp->config->pm == PM_STYLE_ONDEMAND) {
struct fpm_worker_pool_config_s *config = wp->config;
@@ -1718,6 +1725,7 @@ static void fpm_conf_dump() /* {{{ */
zlog(ZLOG_NOTICE, "\tpm.start_servers = %d", wp->config->pm_start_servers);
zlog(ZLOG_NOTICE, "\tpm.min_spare_servers = %d", wp->config->pm_min_spare_servers);
zlog(ZLOG_NOTICE, "\tpm.max_spare_servers = %d", wp->config->pm_max_spare_servers);
+ zlog(ZLOG_NOTICE, "\tpm.max_spawn_rate = %d", wp->config->pm_max_spawn_rate);
zlog(ZLOG_NOTICE, "\tpm.process_idle_timeout = %d", wp->config->pm_process_idle_timeout);
zlog(ZLOG_NOTICE, "\tpm.max_requests = %d", wp->config->pm_max_requests);
zlog(ZLOG_NOTICE, "\tpm.status_path = %s", STR2STR(wp->config->pm_status_path));
diff --git a/sapi/fpm/fpm/fpm_conf.h b/sapi/fpm/fpm/fpm_conf.h
index cd71bb53fd..1d5eabe17c 100644
--- a/sapi/fpm/fpm/fpm_conf.h
+++ b/sapi/fpm/fpm/fpm_conf.h
@@ -70,6 +70,7 @@ struct fpm_worker_pool_config_s {
int pm_start_servers;
int pm_min_spare_servers;
int pm_max_spare_servers;
+ int pm_max_spawn_rate;
int pm_process_idle_timeout;
int pm_max_requests;
char *pm_status_path;
diff --git a/sapi/fpm/fpm/fpm_process_ctl.c b/sapi/fpm/fpm/fpm_process_ctl.c
index a2f0f935e4..d8c0bc30d1 100644
--- a/sapi/fpm/fpm/fpm_process_ctl.c
+++ b/sapi/fpm/fpm/fpm_process_ctl.c
@@ -431,7 +431,7 @@ static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now) /* {{{
zlog(ZLOG_DEBUG, "[pool %s] %d child(ren) have been created dynamically", wp->config->name, children_to_fork);
/* Double the spawn rate for the next iteration */
- if (wp->idle_spawn_rate < FPM_MAX_SPAWN_RATE) {
+ if (wp->idle_spawn_rate < wp->config->pm_max_spawn_rate) {
wp->idle_spawn_rate *= 2;
}
continue;
diff --git a/sapi/fpm/fpm/fpm_process_ctl.h b/sapi/fpm/fpm/fpm_process_ctl.h
index f39a489f61..03dc98e931 100644
--- a/sapi/fpm/fpm/fpm_process_ctl.h
+++ b/sapi/fpm/fpm/fpm_process_ctl.h
@@ -5,8 +5,6 @@
#include "fpm_events.h"
-/* spawn max 32 children at once */
-#define FPM_MAX_SPAWN_RATE (32)
/* 1s (in ms) heartbeat for idle server maintenance */
#define FPM_IDLE_SERVER_MAINTENANCE_HEARTBEAT (1000)
/* a minimum of 130ms heartbeat for pctl */
diff --git a/sapi/fpm/tests/set-pm-max-spawn-rate.phpt b/sapi/fpm/tests/set-pm-max-spawn-rate.phpt
new file mode 100644
index 0000000000..8b5f6b4eb6
--- /dev/null
+++ b/sapi/fpm/tests/set-pm-max-spawn-rate.phpt
@@ -0,0 +1,39 @@
+--TEST--
+FPM: set pm.max_spawn_rate
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+
+require_once "tester.inc";
+
+$cfg = <<<EOT
+[global]
+error_log = {{FILE:LOG}}
+log_level = notice
+[unconfined]
+listen = {{ADDR}}
+pm = dynamic
+pm.max_children = 5
+pm.start_servers = 2
+pm.min_spare_servers = 1
+pm.max_spare_servers = 3
+pm.max_spawn_rate = 64
+EOT;
+
+$tester = new FPM\Tester($cfg);
+$tester->start(['-t', '-t']);
+$tester->expectLogConfigOptions(['pm.max_spawn_rate' => 64]);
+$tester->close();
+
+?>
+Done
+--EXPECT--
+Done
+--CLEAN--
+<?php
+require_once "tester.inc";
+FPM\Tester::clean();
+?>
diff --git a/sapi/fpm/tests/tester.inc b/sapi/fpm/tests/tester.inc
index 7aab2d3aa9..9ce4c1a091 100644
--- a/sapi/fpm/tests/tester.inc
+++ b/sapi/fpm/tests/tester.inc
@@ -1348,6 +1348,48 @@ class Tester
}
/**
+ * Expect log config options
+ *
+ * @param array $options
+ * @return bool
+ */
+ public function expectLogConfigOptions(array $options)
+ {
+ $configOptions = $this->getConfigOptions();
+ foreach ($options as $name => $value) {
+ if (!isset($configOptions[$name])) {
+ return $this->error("Expected config option: {$name} = {$value} but {$name} is not set");
+ }
+ if ($configOptions[$name] != $value) {
+ return $this->error(
+ "Expected config option: {$name} = {$value} but got: {$name} = {$configOptions[$name]}"
+ );
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Get set config options
+ *
+ * @return array
+ */
+ private function getConfigOptions()
+ {
+ $options = [];
+
+ foreach ($this->getLogLines(-1) as $line) {
+ preg_match('/.+NOTICE:\s+(.+)\s=\s(.+)/', $line, $matches);
+ if ($matches) {
+ $options[$matches[1]] = $matches[2];
+ }
+ }
+
+ return $options;
+ }
+
+ /**
* Print content of access log.
*/
public function printAccessLog()
diff --git a/sapi/fpm/www.conf.in b/sapi/fpm/www.conf.in
index 3d5658a65d..ebf1bb8c90 100644
--- a/sapi/fpm/www.conf.in
+++ b/sapi/fpm/www.conf.in
@@ -93,6 +93,8 @@ listen = 127.0.0.1:9000
; state (waiting to process). If the number
; of 'idle' processes is greater than this
; number then some children will be killed.
+; pm.max_spawn_rate - the maximum number of rate to spawn child
+; processes at once.
; ondemand - no children are created at startup. Children will be forked when
; new requests will connect. The following parameter are used:
; pm.max_children - the maximum number of children that
@@ -128,6 +130,12 @@ pm.min_spare_servers = 1
; Note: Mandatory when pm is set to 'dynamic'
pm.max_spare_servers = 3
+; The number of rate to spawn child processes at once.
+; Note: Used only when pm is set to 'dynamic'
+; Note: Mandatory when pm is set to 'dynamic'
+; Default Value: 32
+;pm.max_spawn_rate = 32
+
; The number of seconds after which an idle process will be killed.
; Note: Used only when pm is set to 'ondemand'
; Default Value: 10s