AsyncPool: Apply a cooldown to workers to cut down unnecessary GC lag spikes

Since 3.2 there have been some runtime performance issues related to garbage collection and dynamic AsyncWorker booting. This is partly because of GC being dumb about shutting down what it thinks are "unused" workers. A worker which has been idle for a single tick is considered the same as a worker which has been idle for hours. The result of this is that on active servers, workers would get shut down and then immediately restarted because of something like chunk sending. Since booting an async worker is frightfully expensive, this causes lag spikes, which is obviously bad.

This commit changes the GC mechanism to only shutdown workers which have not been used for the last 5 minutes.
This commit is contained in:
Dylan K. Taylor 2019-01-03 15:06:53 +00:00
parent 658786f2f6
commit 6bd1491b8b

View File

@ -56,6 +56,8 @@ class AsyncPool{
private $workers = [];
/** @var int[] */
private $workerUsage = [];
/** @var int[] */
private $workerLastUsed = [];
/** @var \Closure[] */
private $workerStartHooks = [];
@ -167,6 +169,7 @@ class AsyncPool{
$this->getWorker($worker)->stack($task);
$this->workerUsage[$worker]++;
$this->taskWorkers[$task->getTaskId()] = $worker;
$this->workerLastUsed[$worker] = time();
}
/**
@ -322,10 +325,11 @@ class AsyncPool{
public function shutdownUnusedWorkers() : int{
$ret = 0;
$time = time();
foreach($this->workerUsage as $i => $usage){
if($usage === 0){
if($usage === 0 and (!isset($this->workerLastUsed[$i]) or $this->workerLastUsed[$i] + 300 < $time)){
$this->workers[$i]->quit();
unset($this->workers[$i], $this->workerUsage[$i]);
unset($this->workers[$i], $this->workerUsage[$i], $this->workerLastUsed[$i]);
$ret++;
}
}
@ -343,5 +347,6 @@ class AsyncPool{
$worker->quit();
}
$this->workers = [];
$this->workerLastUsed = [];
}
}