分类
PHP

laravel 使用workerman提供http服务

  • 背景

公司项目使用的是laravel框架,开发完后压测一直不过,期间开启过opcache扩展加速(不属于本篇内容,不在此赘述),后决定采用workerman或swoole加速laravel应用,本篇以workerman为例。

首先大家应该知道laravel每次收到请求都会把框架核心代码加载一遍,使用workerman提升性能的关键是把框架核心代码缓存起来,这样就不需要每次重新加载了,以此来提升性能(swoole同理)

  • composer安装workerman
#更改composer源
composer config -g repo.packagist composer https://packagist.phpcomposer.com
#下载workerman包
composer require workerman/workerman
  • 创建启动命令
  1. 生成 WorkermanCommand 文件
php artisan make:command WorkermanCommand

    执行以上命令行会在 app/Console/Commands/ 目录下生成 WorkermanCommand.php 文件,对文件做如下修改。

<?php

namespace App\Console\Commands;

use Workerman\Worker;
use Illuminate\Console\Command;

class WorkermanCommand extends Command
{
    private $server;
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'wk {action}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Start a Workerman server.';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        global $argv;
        $arg = $this->argument('action');
        $argv[1] = $argv[2];
        $argv[2] = isset($argv[3]) ? "-{$argv[3]}" : '';
        switch ($arg) {
            case 'start':
                $this->start();
                break;
            case 'stop':
                break;
            case 'restart':
                break;
            case 'reload':
                break;
            case 'status':
                break;
            case 'connections':
                break;
        }
    }

    private function start()
    {
        // 创建一个Worker监听20002端口,不使用任何应用层协议
        $this->server = new Worker("http://0.0.0.0:1234");
        // 启动4个进程对外提供服务
        $this->server->count = 4;
        $handler = \App::make('handlers\WorkermanHandler');
        // 连接时回调
        $this->server->onConnect = [$handler, 'onConnect'];
        // 收到客户端信息时回调
        $this->server->onMessage = [$handler, 'onMessage'];
        // 进程启动后的回调
        $this->server->onWorkerStart = [$handler, 'onWorkerStart'];
        // 断开时触发的回调
        $this->server->onClose = [$handler, 'onClose'];
        // 运行worker
        Worker::runAll();
    }
}

在这个自定义命令还引用了其他的类文件,如

$handler = \App::make('handlers\WorkermanHandler');

所以,需要创建一个 WorkermanHandler.php 的文件来处理对应的操作

2、创建 WorkermanHandler.php

创建 app/handlers/WorkermanHandler.php

<?php

namespace handlers;


class WorkermanHandler
{
    public function onWorkerStart($worker)
    {
        //加载index文件的内容
        require __DIR__ . '/../../vendor/autoload.php';
        require_once __DIR__ . '/../../bootstrap/app.php';
    }

    // 处理客户端连接
    public function onConnect($connection)
    {
        echo "new connection from ip " . $connection->getRemoteIp() . "\n";
    }

    // 处理客户端消息
    public function onMessage($connection, $data)
    {
        // 向客户端发送hello $data
        //server信息
        if (isset($data->server)) {
            foreach ($data->server as $k => $v) {
                $_SERVER[strtoupper($k)] = $v;
            }
        }

        //header头信息
        if (isset($data->header)) {
            foreach ($data->header as $k => $v) {
                $_SERVER[strtoupper($k)] = $v;
            }
        }

        //get请求
        if (isset($data->get)) {
            foreach ($data->get as $k => $v) {
                $_GET[$k] = $v;
            }
        }

        //post请求
        if (isset($data->post)) {
            foreach ($data->post as $k => $v) {
                $_POST[$k] = $v;
            }
        }

        //文件请求
        if (isset($data->files)) {
            foreach ($data->files as $k => $v) {
                $_FILES[$k] = $v;
            }
        }

        //cookies请求
        if (isset($data->cookie)) {
            foreach ($data->cookie as $k => $v) {
                $_COOKIE[$k] = $v;
            }
        }

        ob_start();//启用缓存区

        //加载laravel请求核心模块
        $kernel = app()->make(\Illuminate\Contracts\Http\Kernel::class);
        $laravelResponse = $kernel->handle(
            $request = \Illuminate\Http\Request::capture()
        );
        $laravelResponse->send();
        $kernel->terminate($request, $laravelResponse);

        $res = ob_get_contents();//获取缓存区的内容
        ob_end_clean();//清除缓存区

        //输出缓存区域的内容
        $connection->send($res);
    }

    // 处理客户端断开
    public function onClose($connection)
    {
        echo "connection closed from ip {$connection->getRemoteIp()}\n";
    }
}

3.使用composer自动加载

        "classmap": [
            "app/Handlers"
        ],

执行

composer dump-autoload -o

至此基本配置写完了,下边试试启动一下

php artisan wk start
----------------------------------------- WORKERMAN -----------------------------------------
Workerman version:3.5.19          PHP version:7.2.11
------------------------------------------ WORKERS ------------------------------------------
proto   user            worker          listen                 processes    status
tcp     xuce            none            http://0.0.0.0:1234    4             [OK]
---------------------------------------------------------------------------------------------

说明启动成功了!!!

发表评论

电子邮件地址不会被公开。 必填项已用*标注