guanhui07 / blog

把博客迁移到这了
https://guanhui07.github.io/blog/
98 stars 31 forks source link

使用workerman加速任意项目 #818

Open guanhui07 opened 1 year ago

guanhui07 commented 1 year ago

项目地址 https://github.com/joanhey/AdapterMan

看源码原理: 第一、禁止 php 自带函数的同时编写新的函数。 第二、提供新的启动入口使用workerman,同时把框架的核心加载代码,稍作修 改。这样就完美的接替了 php-fpm 。代码常驻内存,性 能提升还是肉眼可见的。当然这个里面的替换思路还是很有意思的。 第三、装上 event扩展 ,性能提升一个量级 , I/O 通知机制有效地安排基于 I/O、时间和信号的事件, epoll linux内核支持 io多路复用

https://pecl.php.net/package/event event扩展安装 此处忽略

php.ini 通过 disable_functions 禁用一些函数

disable_functions =header,header_remove,http_response_code,
setcookie,session_create_id,session_id,session_name,
session_save_path,session_status,session_start,
session_write_close,session_regenerate_id,set_time_limit

start.php 启动文件


<?php

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

use Adapterman\Adapterman;
use Workerman\Worker;

Adapterman::init();

$http_worker                = new Worker('http://0.0.0.0:8080');
$http_worker->count         = 8;
$http_worker->name          = 'AdapterMan';

$http_worker->onWorkerStart = static function () {
    //init();
    require __DIR__.'/start.php';
};

$http_worker->onMessage = static function ($connection, $request) {

    $connection->send(run());
};

Worker::runAll();

AdapterMan 源码 https://github.com/joanhey/AdapterMan/blob/master/src/AdapterFunctions.php#L10


<?php

use Workerman\Protocols\Http;

/**
 * Send a raw HTTP header
 * 
 * @link https://php.net/manual/en/function.header.php
 */
function header(string $content, bool $replace = true, ?int $http_response_code = null): void
{
    Http::header($content, $replace, $http_response_code);
}

/**
 * Remove previously set headers
 *
 * @param string $name  The header name to be removed. This parameter is case-insensitive.
 * @return void
 * 
 * @link https://php.net/manual/en/function.header-remove.php
 */
function header_remove(string $name): void
{
    Http::headerRemove($name);  //TODO fix case-insensitive
}

/**
 * Get or Set the HTTP response code
 *
 * @param integer $code [optional] The optional response_code will set the response code.
 * @return integer      The current response code. By default the return value is int(200).
 * 
 * @link https://www.php.net/manual/en/function.http-response-code.php
 */
function http_response_code(int $code = null): int
{ // int|bool
    return Http::responseCode($code); // Fix to return actual status when void
}

/**
 * Send a cookie
 *
 * @param string $name
 * @param string $value
 * @param integer $expires
 * @param string $path
 * @param string $domain
 * @param boolean $secure
 * @param boolean $httponly
 * @return boolean
 * 
 * @link https://php.net/manual/en/function.setcookie.php
 */
function setcookie(string $name, string $value = '', int $expires = 0, string $path = '', string $domain = '', bool $secure = FALSE, bool $httponly = FALSE): bool
{
    return Http::setcookie($name, $value, $expires, $path, $domain, $secure, $httponly);
}

function session_create_id(string $prefix = ''): string
{
    return Http::sessionCreateId();  //TODO fix to use $prefix
}

function session_id(string $id = ''): string
{
    return Http::sessionId($id);   //TODO fix return session name or '' if not exists session
}

function session_name(string $name = ''): string
{
    return Http::sessionName($name);
}

function session_save_path(string $path = ''): string
{
    return Http::sessionSavePath($path);
}

function session_status(): int
{
    if (Http::sessionStarted() === false) {
        return PHP_SESSION_NONE;
    }
    return PHP_SESSION_ACTIVE;
}

function session_start(array $options = []): bool
{
    return Http::sessionStart();   //TODO fix $options
}

function session_write_close(): void
{
    Http::sessionWriteClose();
}

/**
 * Update the current session id with a newly generated one
 *
 * @param bool $delete_old_session
 * @return bool
 * 
 * @link https://www.php.net/manual/en/function.session-regenerate-id.php
 */
function session_regenerate_id(bool $delete_old_session = false): bool
{
    return Http::sessionRegenerateId($delete_old_session);
}

function set_time_limit(int $seconds): bool
{
    // Disable set_time_limit to not stop the worker
    // by default CLI sapi use 0 (unlimited)
    return true;
}

/* function exit(string $status = ''): void {  //string|int
    Http::end($status);
} // exit and die are language constructors, change your code with an empty ExitException
 */

把session,cookies等使用封装函数代替了,是个不错的想法,但是不能全部直接移植使用,估计还需要更改一些东西

swoole4 是通过 hook 原生函数的方式去兼容各种库代码

AdapterMan https://github.com/joanhey/AdapterMan/blob/master/src/Adapterman.php#L39


<?php

namespace Adapterman;

use Exception;

class Adapterman
{
    public const VERSION = "0.5.3";

    public const NAME = "Adapterman v". self::VERSION;

    private const FUNCTIONS = ['header', 'header_remove', 'http_response_code', 'setcookie', 'session_create_id', 'session_id', 'session_name', 'session_save_path', 'session_status', 'session_start', 'session_write_close', 'session_regenerate_id', 'set_time_limit'];

    public static function init(): void
    {
        try {
            self::checkVersion();
            self::checkFunctionsDisabled();

            // OK initialize the functions
            require __DIR__ . '/AdapterFunctions.php';

        } catch (Exception $e) {
            fwrite(STDERR, self::NAME . ' Error:' . PHP_EOL);
            fwrite(STDERR, $e->getMessage());
            exit;
        }

        fwrite(STDOUT, self::NAME . ' OK' . PHP_EOL);
    }

    /**
     * Check PHP version 
     *
     * @throws Exception
     * @return void
     */
    private static function checkVersion(): void
    {
        if (\PHP_MAJOR_VERSION < 8) {
            throw new Exception("* PHP version must be 8 or higher." . PHP_EOL . "* Actual PHP version: " . \PHP_VERSION . PHP_EOL);
        }
    }

    /**
     * Check that functions are disabled in php.ini
     *
     * @throws Exception
     * @return void
     */
    private static function checkFunctionsDisabled(): void
    {

        foreach (self::FUNCTIONS as $function) {
            if (\function_exists($function)) {
                throw new Exception("Functions not disabled in php.ini." . PHP_EOL . self::showConfiguration());
            }
        }
    }

    private static function showConfiguration(): string
    {
        $inipath = \php_ini_loaded_file();
        $methods = \implode(',', self::FUNCTIONS);

        return "Add in file: $inipath" . PHP_EOL . "disable_functions=$methods" . PHP_EOL;
    }
}

必须php8以上项目 用上workerman常驻内存 性能能提升一个量级

下图为laravel8 提升,其他项目比如thinkphp lumen Yii2 Slim 等 都可用此项目基础于 workerman 加速。 image

参考 workerman社区 https://www.workerman.net/q/9831

Tinywan commented 1 year ago

厉害