huang-yi/shadowfax

在 Swoole 上运行 Laravel。

v2.10.5 2022-01-15 16:35 UTC

README

英文 | 中文

Shadowfax

Shadowfax 是一个可以在 Swoole 上运行 Laravel 应用的包。

安装

您可以使用 Composer 将 Shadowfax 安装到您的项目中

composer require huang-yi/shadowfax

如果您使用的是 Lumen,您需要手动在 bootstrap/app.php 中注册服务提供者

$app->register(HuangYi\Shadowfax\ShadowfaxServiceProvider::class);

安装 Shadowfax 后,使用 shadowfax:publish Artisan 命令发布其配置文件

php artisan shadowfax:publish

配置

主要的配置文件是 shadowfax.yml。此文件名由 shadowfax:publish Artisan 命令添加到 .gitignore 文件中。

  1. 基本配置
  • name: 进程名称。
  • type: 服务器类型,支持: httpwebsocket
  • host: 服务器主机。
  • port: 服务器端口。
  • mode: 服务器模式,支持: processbase
  • access_log: 指示是否打印请求信息。
  • app_pool_capacity: 设置应用池的容量。只有在启用协程时才有效。
  • framework_bootstrapper: 设置 Laravel 启动文件。如果您更改了 Laravel 的目录结构,则应修改此值。
  1. 服务器配置:

本节定义了 Swoole\Server 配置。有关更多信息,请参阅 官方文档

  1. 抽象配置

此选项允许您在 Laravel IoC 容器中设置一组抽象。这些抽象将在每次请求后重新绑定。

  1. 控制器配置

此选项允许您在路由后清除控制器实例。

controllers:
  - App\Http\Controllers\FooController
  - App\Http\Controllers\BarController
  1. 清洁器配置

此选项允许您注册自定义清洁器。这些清洁器将在每次请求后运行。

cleaners:
  - app/Cleaners/
  - CustomNamespace/FooCleaner
  1. 数据库连接池配置:

此选项允许您配置数据库连接池。您可以在其中添加多个键值对。键名是您的 database.connections 中的连接名称,键值是连接池容量。例如。

db_pools:
  mysql: 3
  mysql2: 5
  1. Redis 连接池配置:

此选项允许您配置 Redis 连接池。您可以在其中添加多个键值对。键名是您的 database.redis 中的连接名称,键值是连接池容量。例如。

redis_pools:
  default: 3
  1. 控制器服务器配置:

本节定义了控制器服务器配置。控制器服务器允许您停止或重新加载您的 Shadowfax。

命令

Shadowfax 提供了一个 shadowfax 命令来管理您的服务器进程。此命令基于 Symfony 控制台组件,因此您可以运行 php shadowfax list 获取更多信息。

您可以通过运行 php shadowfax start 命令来启动 Shadowfax 服务器。使用 --watch|-w 选项可以在监视模式下运行您的 Shadowfax。在监视模式下,当项目下的文件更改时,进程将自动重新加载。

在使用 --watch|-w 选项之前,您必须安装 fswatch

php shadowfax reload 允许您重新加载 Shadowfax 进程。

php shadowfax stop 允许您停止 Shadowfax 服务器。

数据库连接池

在使用数据库连接池之前,您必须启用Swoole协程并配置hook_flags

server:
  enable_coroutine: true
  hook_flags: SWOOLE_HOOK_ALL

然后,将您的连接添加到db_pools选项中,并指定池容量

db_pools:
  mysql: 3
  mysql2: 5

Redis连接池

与数据库连接池不同的是,Redis连接池是在redis_pools选项下配置的。

redis_pools:
  default: 3

WebSocket服务器

Shadowfax还允许您构建自己的WebSocket服务器。

首先,您需要将配置项type的值更改为websocket。然后创建一个实现了HuangYi\Shadowfax\Contracts\WebSocket\Handler接口的处理类

namespace App\WebSocket;

use Illuminate\Http\Request;
use HuangYi\Shadowfax\Contracts\WebSocket\Connection;
use HuangYi\Shadowfax\Contracts\WebSocket\Handler;
use HuangYi\Shadowfax\Contracts\WebSocket\Message;

class EchoServer implements Handler
{
    /**
     * Handler for open event.
     *
     * @param  \HuangYi\Shadowfax\Contracts\WebSocket\Connection  $connection
     * @param  \Illuminate\Http\Request  $request
     * @return mixed
     */
    public function onOpen(Connection $connection, Request $request)
    {
        $connection->send('connected');
    }

    /**
     * Handler for message event.
     *
     * @param  \HuangYi\Shadowfax\Contracts\WebSocket\Connection  $connection
     * @param  \HuangYi\Shadowfax\Contracts\WebSocket\Message  $message
     * @return mixed
     */
    public function onMessage(Connection $connection, Message $message)
    {
        $connection->send($message->getData());
    }

    /**
     * Handler for close event.
     *
     * @param  \HuangYi\Shadowfax\Contracts\WebSocket\Connection  $connection
     * @return mixed
     */
    public function onClose(Connection $connection)
    {
        $connection->send('closed');
    }
}

并将此处理程序绑定到您的路由文件中的uri

use App\WebSocket\EchoServer;
use HuangYi\Shadowfax\Facades\WebSocket;

WebSocket::listen('/echo', new EchoServer);

现在,您可以通过命令php shadowfax start启动WebSocket服务器。

Nginx配置

在生产环境中,您可以使用Nginx作为反向代理。

# Uncomment this if you are running a websocket server.
# map $http_upgrade $connection_upgrade {
#     default upgrade;
#     '' close;
# }

server {
    listen 80;
    server_name example.com;
    root /example.com/public;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.html index.htm index.php;

    charset utf-8;

    location = /index.php {
        try_files /nonexistent_file @shadowfax;
    }

    location / {
        try_files $uri $uri/ @shadowfax;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 @shadowfax;

    location @shadowfax {
        set $suffix "";

        if ($uri = /index.php) {
            set $suffix ?$query_string;
        }

        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # Uncomment this if you are running a websocket server.
        # proxy_set_header Upgrade $http_upgrade;
        # proxy_set_header Connection $connection_upgrade;

        proxy_pass http://127.0.0.1:1215$suffix;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

您需要将Shadowfax的IP地址添加到App\Http\Middleware\TrustProxies中间件。

Supervisor配置

如果您想使用Supervisor来管理您的Shadowfax进程,以下配置文件应该足够了

[program:shadowfax]
process_name=%(program_name)s
directory=/path/to/project
command=php shadowfax start
autostart=true
autorestart=true
user=www
redirect_stderr=true
stdout_logfile=/path/to/project/storage/logs/supervisor.log

基准测试

使用wrk运行测试。

环境1

  • 硬件:1个CPU,4个核心,16GB内存
  • MacOS 10.15.3
  • PHP 7.3.12(包含opcache)
  • Swoole 4.4.13
  • Laravel 7(不包含session中间件)
  • Shadowfax 2.0.0(包含20个工作进程)
wrk -t4 -c200 http://127.0.0.1:1215/

结果

Running 10s test @ http://127.0.0.1:1215/
  4 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    26.44ms   31.44ms 212.73ms   84.28%
    Req/Sec     3.13k   839.99     6.07k    65.75%
  124418 requests in 10.01s, 312.06MB read
  Socket errors: connect 0, read 54, write 0, timeout 0
Requests/sec:  12430.20
Transfer/sec:     31.18MB

环境2

  • 硬件:2个CPU,2个核心,4GB内存
  • CentOS 7.5.1804
  • PHP 7.3.16(包含opcache)
  • Swoole 4.4.17
  • Laravel 7(不包含session中间件)
  • Shadowfax 2.0.0(包含10个工作进程)
wrk -c100 http://127.0.0.1:1215/

结果

Running 10s test @ http://127.0.0.1:1215/
  2 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    25.06ms   12.11ms  85.92ms   60.94%
    Req/Sec     4.02k    41.46     4.08k    79.79%
  40321 requests in 10.08s, 101.13MB read
Requests/sec:   4001.76
Transfer/sec:     10.04MB

测试

composer test

许可证

Shadowfax是开源软件,根据MIT许可证授权。