mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-19 05:12:41 +01:00
Allow persistent connections to be configured per database host
Summary: Ref T11044. Fixes T11672. In T11672, persistent connections seem to work fine, but they can require `max_connections` and other settings to be raised. Since most users don't need them, make them an advanced option. Test Plan: Configured persistent connections, loaded some pages, observed persistent connections get used. Reviewers: chad Reviewed By: chad Maniphest Tasks: T11044, T11672 Differential Revision: https://secure.phabricator.com/D16913
This commit is contained in:
parent
256d14c7ea
commit
8c89fc38fc
5 changed files with 79 additions and 19 deletions
|
@ -31,6 +31,13 @@ with a single master first. Even if you choose not to deploy replication, you
|
||||||
should review and understand how replication works before you partition. For
|
should review and understand how replication works before you partition. For
|
||||||
details, see @{Cluster:Databases}.
|
details, see @{Cluster:Databases}.
|
||||||
|
|
||||||
|
Databases also support some advanced configuration options. Briefly:
|
||||||
|
|
||||||
|
- `persistent`: Allows use of persistent connections, reducing pressure on
|
||||||
|
outbound ports.
|
||||||
|
|
||||||
|
See "Advanced Configuration", below, for additional discussion.
|
||||||
|
|
||||||
|
|
||||||
What Partitioning Does
|
What Partitioning Does
|
||||||
======================
|
======================
|
||||||
|
@ -145,7 +152,7 @@ Launching a new Partition
|
||||||
To add a new partition, follow these steps:
|
To add a new partition, follow these steps:
|
||||||
|
|
||||||
- Set up the new database host or hosts.
|
- Set up the new database host or hosts.
|
||||||
- Add the new database to `cluster.database`, but keep its "partition"
|
- Add the new database to `cluster.databases`, but keep its "partition"
|
||||||
configuration empty (just an empty list). If this is the first time you
|
configuration empty (just an empty list). If this is the first time you
|
||||||
are partitioning, you will need to configure your existing master as the
|
are partitioning, you will need to configure your existing master as the
|
||||||
new "default". This will let Phabricator interact with it, but won't send
|
new "default". This will let Phabricator interact with it, but won't send
|
||||||
|
@ -196,6 +203,37 @@ meaningful differences in runtime behavior if two applications are on the same
|
||||||
physical host or different physical hosts.
|
physical host or different physical hosts.
|
||||||
|
|
||||||
|
|
||||||
|
Advanced Configuration
|
||||||
|
======================
|
||||||
|
|
||||||
|
Separate from partitioning, some advanced configuration is supported. These
|
||||||
|
options must be set on database specifications in `cluster.databases`. You can
|
||||||
|
configure them without actually building a cluster by defining a cluster with
|
||||||
|
only one master.
|
||||||
|
|
||||||
|
`persistent` //(bool)// Enables persistent connections. Defaults to off.
|
||||||
|
|
||||||
|
With persitent connections enabled, Phabricator will keep a pool of database
|
||||||
|
connections open between web requests and reuse them when serving subsequent
|
||||||
|
requests.
|
||||||
|
|
||||||
|
The primary benefit of using persistent connections is that it will greatly
|
||||||
|
reduce pressure on how quickly outbound TCP ports are opened and closed. After
|
||||||
|
a TCP port closes, it normally can't be used again for about 60 seconds, so
|
||||||
|
rapidly cycling ports can cause resource exuastion. If you're seeing failures
|
||||||
|
because requests are unable to bind to an outbound port, enabling this option
|
||||||
|
is likely to fix the issue. This option may also slightly increase performance.
|
||||||
|
|
||||||
|
The cost of using persistent connections is that you may need to raise the
|
||||||
|
MySQL `max_connections` setting: although Phabricator will make far fewer
|
||||||
|
connections, the connections it does make will be longer-lived. Raising this
|
||||||
|
setting will increase MySQL memory requirements and may run into other limits,
|
||||||
|
like `open_files_limit`, which may also need to be raised.
|
||||||
|
|
||||||
|
Persistent connections are enabled per-database. If you always want to use
|
||||||
|
them, set the flag on each configured database in `cluster.databases`.
|
||||||
|
|
||||||
|
|
||||||
Next Steps
|
Next Steps
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ final class PhabricatorClusterDatabasesConfigOptionType
|
||||||
'disabled' => 'optional bool',
|
'disabled' => 'optional bool',
|
||||||
'master' => 'optional string',
|
'master' => 'optional string',
|
||||||
'partition' => 'optional list<string>',
|
'partition' => 'optional list<string>',
|
||||||
|
'persistent' => 'optional bool',
|
||||||
));
|
));
|
||||||
} catch (Exception $ex) {
|
} catch (Exception $ex) {
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
|
|
|
@ -40,6 +40,7 @@ final class PhabricatorDatabaseRef
|
||||||
private $applicationMap = array();
|
private $applicationMap = array();
|
||||||
private $masterRef;
|
private $masterRef;
|
||||||
private $replicaRefs = array();
|
private $replicaRefs = array();
|
||||||
|
private $usePersistentConnections;
|
||||||
|
|
||||||
public function setHost($host) {
|
public function setHost($host) {
|
||||||
$this->host = $host;
|
$this->host = $host;
|
||||||
|
@ -171,6 +172,15 @@ final class PhabricatorDatabaseRef
|
||||||
return $this->isDefaultPartition;
|
return $this->isDefaultPartition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setUsePersistentConnections($use_persistent_connections) {
|
||||||
|
$this->usePersistentConnections = $use_persistent_connections;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUsePersistentConnections() {
|
||||||
|
return $this->usePersistentConnections;
|
||||||
|
}
|
||||||
|
|
||||||
public function setApplicationMap(array $application_map) {
|
public function setApplicationMap(array $application_map) {
|
||||||
$this->applicationMap = $application_map;
|
$this->applicationMap = $application_map;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -582,7 +592,8 @@ final class PhabricatorDatabaseRef
|
||||||
->setPort($default_port)
|
->setPort($default_port)
|
||||||
->setIsIndividual(true)
|
->setIsIndividual(true)
|
||||||
->setIsMaster(true)
|
->setIsMaster(true)
|
||||||
->setIsDefaultPartition(true);
|
->setIsDefaultPartition(true)
|
||||||
|
->setUsePersistentConnections(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getAllReplicaDatabaseRefs() {
|
public static function getAllReplicaDatabaseRefs() {
|
||||||
|
@ -672,9 +683,31 @@ final class PhabricatorDatabaseRef
|
||||||
'database' => null,
|
'database' => null,
|
||||||
'retries' => $default_retries,
|
'retries' => $default_retries,
|
||||||
'timeout' => $default_timeout,
|
'timeout' => $default_timeout,
|
||||||
|
'persistent' => $this->getUsePersistentConnections(),
|
||||||
);
|
);
|
||||||
|
|
||||||
return self::newRawConnection($spec);
|
$is_cli = (php_sapi_name() == 'cli');
|
||||||
|
|
||||||
|
$use_persistent = false;
|
||||||
|
if (!empty($spec['persistent']) && !$is_cli) {
|
||||||
|
$use_persistent = true;
|
||||||
|
}
|
||||||
|
unset($spec['persistent']);
|
||||||
|
|
||||||
|
$connection = self::newRawConnection($spec);
|
||||||
|
|
||||||
|
// If configured, use persistent connections. See T11672 for details.
|
||||||
|
if ($use_persistent) {
|
||||||
|
$connection->setPersistent($use_persistent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unless this is a script running from the CLI, prevent any query from
|
||||||
|
// running for more than 30 seconds. See T10849 for details.
|
||||||
|
if (!$is_cli) {
|
||||||
|
$connection->setQueryTimeout(30);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function newRawConnection(array $options) {
|
public static function newRawConnection(array $options) {
|
||||||
|
|
|
@ -58,13 +58,16 @@ final class PhabricatorDatabaseRefParser
|
||||||
$role = $server['role'];
|
$role = $server['role'];
|
||||||
$is_master = ($role == 'master');
|
$is_master = ($role == 'master');
|
||||||
|
|
||||||
|
$use_persistent = (bool)idx($server, 'persistent', false);
|
||||||
|
|
||||||
$ref = id(new PhabricatorDatabaseRef())
|
$ref = id(new PhabricatorDatabaseRef())
|
||||||
->setHost($host)
|
->setHost($host)
|
||||||
->setPort($port)
|
->setPort($port)
|
||||||
->setUser($user)
|
->setUser($user)
|
||||||
->setPass($pass)
|
->setPass($pass)
|
||||||
->setDisabled($disabled)
|
->setDisabled($disabled)
|
||||||
->setIsMaster($is_master);
|
->setIsMaster($is_master)
|
||||||
|
->setUsePersistentConnections($use_persistent);
|
||||||
|
|
||||||
if ($is_master) {
|
if ($is_master) {
|
||||||
$master_count++;
|
$master_count++;
|
||||||
|
|
|
@ -73,21 +73,6 @@ abstract class PhabricatorLiskDAO extends LiskDAO {
|
||||||
$connection->setReadOnly(true);
|
$connection->setReadOnly(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unless this is a script running from the CLI:
|
|
||||||
// - (T10849) Prevent any query from running for more than 30 seconds.
|
|
||||||
// - (T11672) Use persistent connections.
|
|
||||||
if (php_sapi_name() != 'cli') {
|
|
||||||
|
|
||||||
// TODO: For now, disable this until after T11044: it's better at high
|
|
||||||
// load, but causes us to use slightly more connections at low load and
|
|
||||||
// is pushing users over limits like MySQL "max_connections".
|
|
||||||
$use_persistent = false;
|
|
||||||
|
|
||||||
$connection
|
|
||||||
->setQueryTimeout(30)
|
|
||||||
->setPersistent($use_persistent);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $connection;
|
return $connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue