hollodotme/fast-cgi-proxy

用于将同步和异步请求分发到多个 php-fpm 套接字/池的代理。

v0.2.0 2019-06-10 20:23 UTC

This package is auto-updated.

Last update: 2024-09-11 14:47:17 UTC


README

CircleCI Latest Stable Version Total Downloads codecov

FastCGI 代理

描述

将同步和异步请求分发到多个 fastCGI 服务器的代理。

安装

composer require hollodotme/fast-cgi-proxy

使用方法

请求分发

代理可以通过以下方式将请求分发到多个 fastCGI 服务器:

  1. 随机
  2. 轮询

随机分发

要设置随机分发,请使用以下示例代码:

<?php declare(strict_types=1);

namespace YourVendor\YourProject;

use hollodotme\FastCGI\Proxy;
use hollodotme\FastCGI\Collections\Random;
use hollodotme\FastCGI\SocketConnections\NetworkSocket;
use hollodotme\FastCGI\SocketConnections\UnixDomainSocket;

$random = Random::fromConnections(
    new NetworkSocket( '127.0.0.1', 9000 ),
    new NetworkSocket( '10.100.10.42', 9000 ),
    new UnixDomainSocket( '/var/run/php7.3-fpm.sock' )	
);

$proxy = new Proxy( $random );

现在发送请求时,代理将随机选择一个 fastCGI 服务器来处理请求。

轮询分发

要设置轮询分发,请使用以下示例代码:

<?php declare(strict_types=1);

namespace YourVendor\YourProject;

use hollodotme\FastCGI\Proxy;
use hollodotme\FastCGI\Collections\RoundRobin;
use hollodotme\FastCGI\SocketConnections\NetworkSocket;
use hollodotme\FastCGI\SocketConnections\UnixDomainSocket;

$roundRobin = RoundRobin::fromConnections(
    new NetworkSocket( '127.0.0.1', 9000 ),
    new NetworkSocket( '10.100.10.42', 9000 ),
    new UnixDomainSocket( '/var/run/php7.3-fpm.sock' )	
);

$proxy = new Proxy( $roundRobin );

代理将按照它们被添加到 RoundRobin 实例的相同顺序将您的请求发送到下一个 fastCGI 服务器。在本例中,它将发送到

  1. 127.0.0.1:9001
  2. 10.100.10.42:9001,
  3. /var/run/php7.1-fpm.sock
  4. 127.0.0.1:9001(从头开始)
  5. 等等...

发送请求

Proxy 类具有与底层 Client 类相同的用于发送同步和异步请求以及检索响应(响应式)的方法。因此,请参阅 hollodotme/fast-cgi-client 的文档以获取更多信息。

以下是一个可用方法的简要列表

  • $proxy->sendRequest(ProvidesRequestData $request) : ProvidesResponseData
    发送一个同步请求并返回响应。(阻塞)

  • $proxy->sendAsyncRequest(ProvidesRequestData $request) : int
    发送一个异步请求并返回请求 ID。(非阻塞)

  • $proxy->readResponse(int $requestId, ?int $timeoutMs = null) : ProvidesResponseData
    读取并返回先前获得的请求 ID 的响应。
    (阻塞直到读取响应或读取超时)

  • $proxy->readResponses(?int $timeoutMs = null, int ...$requestIds) : \Generator|ProvidesResponseData[]
    按给定请求 ID 的顺序读取并产生先前获得的请求 ID 的响应。
    (阻塞直到读取所有响应或读取超时)

  • $proxy->readReadyResponses(?int $timeoutMs = null) : \Generator|ProvidesResponseData[]
    读取并产生所有已完成请求的响应。
    (非阻塞,适用于循环中)

  • $proxy->waitForResponse(int $requestId, ?int $timeoutMs = null) : void
    等待先前获得的请求 ID 的响应并调用请求的响应回调。
    (阻塞直到读取响应或读取超时)

  • $proxy->waitForResponses(?int $timeoutMs = null) : void
    等待先前获得的请求 ID 的响应并按完成请求的顺序调用相应的响应回调。
    (阻塞直到读取所有响应或读取超时)

  • $proxy->hasResponse(int $requestId) : bool
    返回给定的请求 ID 是否有响应。(非阻塞)

  • $proxy->handleResponse(int $requestId, ?int $timeoutMs = null) : void
    调用已完成请求的相应响应回调。
    (如果请求 ID 有响应,在调用此方法之前必须进行检查,请参阅 $proxy->hasResponse(int $requestId))。

  • $proxy->hasUnhandledResponses() : bool
    如果有未处理的响应,则返回 TRUE,否则返回 FALSE。

  • $proxy->getRequestIdsHavingResponse() : array
    返回所有有响应的请求 ID。(非阻塞)

  • $proxy->handleResponses(?int $timeoutMs = null, int ...$requestIds) : void
    按给定请求 ID 的顺序调用已完成请求的相应响应回调。
    (如果请求 ID 有响应,在调用此方法之前必须进行检查,请参阅 $proxy->hasResponse(int $requestId)$proxy->getRequestIdsHavingResponse() : array。)

  • $proxy->handleReadyResponses(?int $timeoutMs = null) : void
    按照完成请求的顺序调用相应的响应回调。
    (非阻塞,简写为 $proxy->handleResponses($timeoutMs, int ...$proxy->getRequestIdsHavingResponse()))

集群请求

此功能自库的 v0.2.0 版本以来可用。

为了在众多快速CGI服务器上处理单个请求,引入了 ClusterProxy 类。因此,为了将请求分发到配置的快速CGI服务器之一,集群代理将向所有配置的快速CGI服务器发送相同的请求,并允许您读取/处理它们的响应(响应式)。

根据集群请求的概念,请求与响应之间始终存在一对一或多对多的关系。这就是为什么 ClusterProxy 类不提供基于请求ID的同步请求和单个响应读取。

要设置集群代理,请使用以下示例代码

<?php declare(strict_types=1);

namespace YourVendor\YourProject;

use hollodotme\FastCGI\ClusterProxy;
use hollodotme\FastCGI\Collections\Cluster;
use hollodotme\FastCGI\SocketConnections\NetworkSocket;
use hollodotme\FastCGI\SocketConnections\UnixDomainSocket;

$cluster = Cluster::fromConnections(
    new NetworkSocket( '127.0.0.1', 9000 ),
    new NetworkSocket( '10.100.10.42', 9000 ),
    new UnixDomainSocket( '/var/run/php7.3-fpm.sock' )	
);

$clusterProxy = new ClusterProxy( $cluster );

在集群代理类中,以下方法集用于发送请求和处理响应

  • $clusterProxy->sendAsyncRequest(ProvidesRequestData $request) : void
    向集群中的所有连接发送异步请求。 (非阻塞)

  • $clusterProxy->readReadyResponses(?int $timeoutMs = null) : \Generator|ProvidesResponseData[]
    读取并产生所有已完成请求的响应。
    (非阻塞,适用于循环中)

  • $clusterProxy->waitForResponses(?int $timeoutMs = null) : void
    等待先前获得的请求 ID 的响应并按完成请求的顺序调用相应的响应回调。
    (阻塞直到读取所有响应或读取超时)

  • $clusterProxy->hasUnhandledResponses() : bool
    如果有未处理的响应,则返回 TRUE,否则返回 FALSE。

  • $clusterProxy->handleReadyResponses(?int $timeoutMs = null) : void
    按照完成请求的顺序调用相应的响应回调。
    (非阻塞,意在结合 $clusterProxy->hasUnhandledResponses() 在循环中使用)

集群状态

此功能自库的 v0.2.0 版本以来可用。

为了检索集群中所有快速CGI服务器的状态,引入了 ClusterProxy#getStatus() 方法。

目前此方法仅支持PHP-FPM的状态响应实现,但可以通过实现接口 hollodotme\FastCGI\Interfaces\ProvidesServerStatus 容易地扩展到其他快速CGI服务器。

<?php declare(strict_types=1);

namespace hollodotme\FastCGI\Interfaces;

interface ProvidesServerStatus
{
	/**
     * Returns the original response object for the status request provided by hollodotme/fast-cgi-client
     * @see https://github.com/hollodotme/fast-cgi-client/blob/2.x-stable/src/Responses/Response.php
     * 
     * @return ProvidesResponseData
     */
	public function getResponse() : ProvidesResponseData;

    /**
     * Returns the connection object used for the status request 
     * in order to identify the server that produced the status response
     * 
     * @return ConfiguresSocketConnection
     */
	public function getConnection() : ConfiguresSocketConnection;

    /**
     * Returns any data structure representing the status information of the server 
     * @return mixed
     */
	public function getStatus();

    /**
     * Returns a list of any data structure representing current processes running on the server 
     * @return array 
     */
	public function getProcesses() : array;
}

集群状态示例

以下代码读取了库的 docker-compose 设置 中所有3个php-fpm容器的状态。

请注意:如果服务器配置中没有启用状态端点(PHP-FPM的 pm.status_path),则 ClusterProxy#getStatus() 方法将抛出 RuntimeException

examples/cluster_status.php

<?php declare(strict_types=1);

namespace hollodotme\FastCGI\Examples;

use hollodotme\FastCGI\ClusterProxy;
use hollodotme\FastCGI\Collections\Cluster;
use hollodotme\FastCGI\Responses\PhpFpmStatusResponse;
use hollodotme\FastCGI\SocketConnections\NetworkSocket;

require_once __DIR__ . '/../vendor/autoload.php';

$cluster = Cluster::fromConnections(
	new NetworkSocket( 'php71', 9001 ),
	new NetworkSocket( 'php72', 9001 ),
	new NetworkSocket( 'php73', 9001 )
);

$clusterProxy = new ClusterProxy( $cluster );

$statusResponses = $clusterProxy->getStatus( '/status?full' );
# If you do not want the list processes, use the following line to get the status only
# $statusResponses = $clusterProxy->getStatus( '/status' );

/** @var PhpFpmStatusResponse $statusResponse */
foreach ( $statusResponses as $statusResponse )
{
	$connection = $statusResponse->getConnection();
	$status     = $statusResponse->getStatus();
	$processes  = $statusResponse->getProcesses();
	$response   = $statusResponse->getResponse();

	echo '[ SERVER: ', $connection->getSocketAddress(), " ]\n";

	echo '- Pool name: ', $status->getPoolName(), "\n";
	echo '- Process manager: ', $status->getProcessManager(), "\n";
	echo '- Started at: ', $status->getStartTime()->format( 'c' ), "\n";
	echo '- Seconds since start: ', $status->getStartSince(), "\n";
	echo '- Number of accepted connections: ', $status->getAcceptedConnections(), "\n";
	echo '- Current listen queue: ', $status->getListenQueue(), "\n";
	echo '- Listen queue maximum: ', $status->getMaxListenQueue(), "\n";
	echo '- Listen queue length: ', $status->getListenQueueLength(), "\n";
	echo '- Number of idle processes: ', $status->getIdleProcesses(), "\n";
	echo '- Number of active processes: ', $status->getActiveProcesses(), "\n";
	echo '- Number of total processes: ', $status->getTotalProcesses(), "\n";
	echo '- Number of active processes maximum: ', $status->getMaxActiveProcesses(), "\n";
	echo '- Times max children reached: ', $status->getMaxChildrenReached(), "\n";
	echo '- Number of slow requests: ', $status->getSlowRequests(), "\n";

	echo "\nPrinting processes:\n\n";

	foreach ( $processes as $index => $process )
	{
		echo '- [ PROCESS #', ($index + 1), " ]\n";
		echo '  * PID: ', $process->getPid(), "\n";
		echo '  * State: ', $process->getState(), "\n";
		echo '  * Started at: ', $process->getStartTime()->format( 'c' ), "\n";
		echo '  * Seconds since start: ', $process->getStartSince(), "\n";
		echo '  * Number of requests processed: ', $process->getRequests(), "\n";
		echo '  * Last request duration: ', $process->getRequestDuration(), "\n";
		echo '  * Last request method: ', $process->getRequestMethod(), "\n";
		echo '  * Last request URI: ', $process->getRequestUri(), "\n";
		echo '  * Last content length: ', $process->getContentLength(), "\n";
		echo '  * Last user: ', $process->getUser(), "\n";
		echo '  * Last script: ', $process->getScript(), "\n";
		echo '  * CPU usage of last request: ', $process->getLastRequestCpu(), "\n";
		echo '  * Memory usage of last request: ', $process->getLastRequestMemory(), "\n";

		echo "\n\n---\n\n";
	}

	echo 'Processing duration: ', $response->getDuration(), " seconds\n\n";
}

此脚本产生的输出示例

[ SERVER: tcp://php71:9001 ]
- Pool name: network
- Process manager: dynamic
- Started at: 2019-06-10T14:56:45+00:00
- Seconds since start: 18094
- Number of accepted connections: 81
- Current listen queue: 0
- Listen queue maximum: 0
- Listen queue length: 128
- Number of idle processes: 1
- Number of active processes: 1
- Number of total processes: 2
- Number of active processes maximum: 2
- Times max children reached: 0
- Number of slow requests: 0

Printing processes:

- [ PROCESS #1 ]
  * PID: 8
  * State: Idle
  * Started at: 2019-06-10T14:56:45+00:00
  * Seconds since start: 18094
  * Number of requests processed: 40
  * Last request duration: 190
  * Last request method: -
  * Last request URI: -
  * Last content length: 0
  * Last user: -
  * Last script: -
  * CPU usage of last request: 0
  * Memory usage of last request: 2097152


---

- [ PROCESS #2 ]
  * PID: 9
  * State: Running
  * Started at: 2019-06-10T14:56:45+00:00
  * Seconds since start: 18094
  * Number of requests processed: 41
  * Last request duration: 190
  * Last request method: GET
  * Last request URI: /status?full
  * Last content length: 0
  * Last user: -
  * Last script: -
  * CPU usage of last request: 0
  * Memory usage of last request: 0


---

Processing duration: 0.0137939453125 seconds

[ SERVER: tcp://php72:9001 ]
- Pool name: network
- Process manager: dynamic
- Started at: 2019-06-10T14:56:46+00:00
- Seconds since start: 18093
- Number of accepted connections: 75
- Current listen queue: 0
- Listen queue maximum: 0
- Listen queue length: 128
- Number of idle processes: 1
- Number of active processes: 1
- Number of total processes: 2
- Number of active processes maximum: 2
- Times max children reached: 0
- Number of slow requests: 0

Printing processes:

- [ PROCESS #1 ]
  * PID: 10
  * State: Idle
  * Started at: 2019-06-10T14:56:46+00:00
  * Seconds since start: 18093
  * Number of requests processed: 38
  * Last request duration: 217
  * Last request method: -
  * Last request URI: -
  * Last content length: 0
  * Last user: -
  * Last script: -
  * CPU usage of last request: 0
  * Memory usage of last request: 2097152


---

- [ PROCESS #2 ]
  * PID: 11
  * State: Running
  * Started at: 2019-06-10T14:56:46+00:00
  * Seconds since start: 18093
  * Number of requests processed: 37
  * Last request duration: 177
  * Last request method: GET
  * Last request URI: /status?full
  * Last content length: 0
  * Last user: -
  * Last script: -
  * CPU usage of last request: 0
  * Memory usage of last request: 0


---

Processing duration: 0.027499914169312 seconds

[ SERVER: tcp://php73:9001 ]
- Pool name: network
- Process manager: dynamic
- Started at: 2019-06-10T14:56:45+00:00
- Seconds since start: 18094
- Number of accepted connections: 1706
- Current listen queue: 0
- Listen queue maximum: 1
- Listen queue length: 128
- Number of idle processes: 2
- Number of active processes: 1
- Number of total processes: 3
- Number of active processes maximum: 23
- Times max children reached: 0
- Number of slow requests: 0

Printing processes:

- [ PROCESS #1 ]
  * PID: 331
  * State: Idle
  * Started at: 2019-06-10T17:00:25+00:00
  * Seconds since start: 10674
  * Number of requests processed: 383
  * Last request duration: 185
  * Last request method: -
  * Last request URI: -
  * Last content length: 0
  * Last user: -
  * Last script: -
  * CPU usage of last request: 0
  * Memory usage of last request: 2097152


---

- [ PROCESS #2 ]
  * PID: 497
  * State: Running
  * Started at: 2019-06-10T17:31:02+00:00
  * Seconds since start: 8837
  * Number of requests processed: 59
  * Last request duration: 244
  * Last request method: GET
  * Last request URI: /status?full
  * Last content length: 0
  * Last user: -
  * Last script: -
  * CPU usage of last request: 0
  * Memory usage of last request: 0


---

- [ PROCESS #3 ]
  * PID: 315
  * State: Idle
  * Started at: 2019-06-10T16:42:27+00:00
  * Seconds since start: 11752
  * Number of requests processed: 433
  * Last request duration: 230
  * Last request method: -
  * Last request URI: -
  * Last content length: 0
  * Last user: -
  * Last script: -
  * CPU usage of last request: 0
  * Memory usage of last request: 2097152


---

Processing duration: 0.029183149337769 seconds

贡献

欢迎贡献,并将获得全面认可。请参阅 贡献指南 了解详情。