第2层/aphplication

PHP应用服务器

dev-master 2018-09-26 17:11 UTC

This package is auto-updated.

Last update: 2024-09-14 02:43:11 UTC


README

PHP本质上是慢的,因为每个请求都要做所有的事情

通常当你运行一个PHP脚本时,以下事情会发生

Without an app server

每个请求上唯一不同的步骤是最后一步。所有启动应用的非平凡工作都在每个请求上完成。每次查看页面时,都会加载类,实例化框架,连接数据库,配置库。所有这些艰苦的工作都是在每个请求上完成的。每次访问页面时,都会加载所有配置文件并实例化类。

Aphplication试图通过改变PHP处理请求的本质来解决此问题。

如果我们能在步骤5时对PHP脚本进行快照,在所有启动工作完成后并准备好处理单个请求?这就是Aphplication的工作方式

Without an app server

通过使用Aphplication,通常在每个请求上运行的代码只运行一次,然后监听连接。你可以有效地跳入运行中的PHP脚本的任何部分。

结果是,每个请求只执行它需要的任务。这为Laravel提供了2400%的性能提升

Aphplication

Aphplication是一个PHP应用服务器。它的工作方式与Node.js类似,你的应用始终在运行,当有人连接时,他们连接到活动应用。这允许你在请求之间保持状态,并避免在每个请求上存在的很多启动代码。

Aphplication项目有两个部分

  1. 服务器。它包含所有的代码,即使在没有人访问页面时也会持续运行。

  2. 客户端。它是浏览器和运行中的应用之间的中间件。当有人连接到client.php时,PHP脚本运行,与服务器通信,请求服务器进行一些处理,然后返回结果。服务器继续运行,但客户端脚本停止。

要求

Aphplication使用内部消息队列。这比其他类似工具使用的套接字快得多。您必须在php.ini中取消注释extension=sysvmsg.so

Aphplication需要一个启用了sysvmsg.so扩展的Linux服务器。这个扩展在大多数Linux默认安装中默认存在。

用法

  1. 通过创建一个实现Aphplication\Aphplication接口的类来创建你的服务器

  2. 将此类的实例传递给Aphplication\Server();

  3. 将其保存为文件,例如server.php

//This class is executed once and keeps running in the background
class MyApplication implements \Aphplication\Aphplication {
	// State that is maintained across reuqests. This is not serialised, it is kept-as is so can be
	// Database connections, complex object graphs, etc
	// Note: Each worker thread has a copy of this state by default
	private $num = 0;

	// The accept method is executed on each request. Because this instance is already running, the superglobals are passed from the client

	//The return value is a string which is to be sent back to the client.
	//Note: For better comatibility any header() calls are also sent back to the client
	public function accept(): string {
		// The only code that is run on each request.
		$this->num++;
		return $this->num;
	}
}

$server = new \Aphplication\Server(new MyApplication());
$server->start();

现在服务器将运行,并且单个MyApplication实例将在服务器上的PHP进程中持续运行。每次客户端连接时,都会调用服务器的accept方法,并可以执行页面的特定处理。

这允许你做类似这样的事情

//This class is executed once and keeps running in the background
class MyApplication implements \Aphplication\Aphplication {
	private $frameworkEntryPoint;

	public function __construct() {
		// Instantiate the framework and store it in memory. This only happens once and is kept active on the server
		$db = new PDO('...');
		$this->frameworkEntryPoint = new MyFramework($db);
	}

	// The accept method is executed on each request. Because this instance is already running, the superglobals are passed from the client

	//The return value is a string which is to be sent back to the client.
	//Note: For better comatibility any header() calls are also sent back to the client
	public function accept(): string {
		// Each time a client requests, route the request as normal
		return $this->frameworkEntryPoint->route($_SERVER['REQUEST_URI']);
	}
}

$server = new \Aphplication\Server(new MyApplication());
$server->start();

通过这样做,所有的框架类只加载一次。这甚至比opcaching更好,因为不仅文件只解析一次,启动代码也只执行一次。

  1. 在命令行上启动应用程序

假设你的服务器存储在server.php中,启动应用服务器

php server.php
  1. 从启动服务器的同一目录运行CLI客户端脚本(服务器和客户端必须从相同的当前工作目录启动)

现在从客户端连接到服务器。

require '../Aphplication/Client.php';
$client = new \Aphplication\Client();
echo $client->connect();

要使用Web服务器作为客户端,只需创建PHP脚本

require '../Aphplication/Client.php';
$client = new \Aphplication\Client();
echo $client->connect();

关闭服务器

要关闭服务器,请在命令行中使用相同的脚本和停止命令

php server stop

Web服务器示例

首先创建一个Web服务器,server.php。它不需要在public_html目录中,也不需要在任何可访问的Web目录中。

require 'vendor/autoload.php';
class MyApplication implements \Aphplication\Aphplication {
	//Application state. This will be kept in memory when the application is closed
	//This can even be MySQL connections and other resources

	private $num;

	public function accept(): string {
		$this->num++;

		//return the response to send back to the browser, e.g. some HTML code
		return $this->num;
	}

}


//Now create an instance of the server
$server = new \Aphplication\Server(new MyApplication());

//Check argv to allow starting and stopping the server
if (isset($argv[1]) && $argv[1] == 'stop') $server->shutdown();
else $server->start();

服务器编写完成后,使用以下命令启动它:

php server.php

这将启动一个内存中的PHP进程并开始等待请求。要停止服务器,您可以调用php server.php stop

现在服务器正在运行,请在public_htmlhttpdocs文件夹中创建一个client.php,确保它在Web可访问的位置。

client.php应只包含以下代码

require '../Aphplication/Client.php';
$client = new \Aphplication\Client();
echo $client->connect();

(根据需要调整Aphplication/Client.php的路径)。您可以使用composer的自动加载器,但这不是一个好主意,因为composer的自动加载对加载单个文件来说是一个显著的负担。仅使用require包含提供的客户端代码将获得更好的性能。

提供的客户端代码连接到服务器,将当前请求的get/post等数据发送给它,并返回响应。这个PHP文件在每次请求时都会运行,所以尽量保持它轻量级!

现在,如果您在浏览器中访问client.php,您将看到服务器返回的输出。在这种情况下,它将显示一个计数器,因为每次服务器被连接时,$num变量都会增加一。

现在该做什么呢?

您的服务器可以执行任何普通PHP脚本可以执行的任务。一旦服务器上处理了require语句,该文件就会被要求,直到服务器重新启动才再次要求!

开发

这确实使得开发变得困难,因为每次都需要重新启动服务器。未来的版本将有一个开发模式,它实际上不会启动服务器,但允许您像普通PHP脚本一样运行客户端(每次都会加载所有内容)。

性能

Aphplication可以比标准PHP脚本快1000%。当您运行Laravel、Wordpress或Zend项目时,PHP解释器会被执行并执行大量工作:加载所有所需的.php文件,连接到数据库,最后处理您的请求。使用Aphplication,所有这些启动代码只会在服务器启动时执行一次。当有人连接时,他们连接到的已经完成了所有启动工作的运行中的应用程序,服务器然后将请求处理完毕并交给客户端。

您可以将应用程序服务器想象成MySQL,它始终在运行并等待处理请求。当请求被提出时,它执行一些处理并返回结果。与传统的PHP脚本不同,它会继续运行以准备处理下一个请求。

这使Aphplication在性能上比传统的加载所有所需文件和建立所有必要连接的方法有了巨大的提升。

多线程

Aphplication是支持多线程的。它可以启动您想要的任意数量的进程。这应该是CPU核心(或虚拟核心)数量的3倍。这是因为PHP脚本经常暂停(例如,等待MySQL返回数据)。

您可以通过以下方式设置线程数:

$server->setThreads($number);

$server->start()之前