roadrunner 分析 - (sunznx) 振翅飞翔
22 March 2021
  1. roadrunner 是什么,解决什么问题
  2. roadrunner 如何实现

是什么

Roadrunner: What is it?

roadrunner 是一个 php 的加速方案,使用 go 实现。

如何实现

go 使用『goroutine』启动 php 进程,php 进程执行如下命令:

php ./vendor/bin/rr-worker start --relay-dsn unix:///usr/local/var/run/rr-rpc.sock

rr-worker 主要做了如下:

$psr7_worker = new \Spiral\RoadRunner\Http\PSR7Worker($this->createWorker($options->getRelayDsn()) ... );

while ($req = $psr7_worker->waitRequest()) {
    ...

    if ($options->getRefreshApp()) {
        $sandbox = $this->createApplication($options->getAppBasePath());
        $this->bootstrapApplication($sandbox, $psr7_worker);
    } else {
        $sandbox = clone $app;
    }

    $this->setApplicationInstance($sandbox);

    /** @var HttpKernelContract $http_kernel */
    $http_kernel = $sandbox->make(HttpKernelContract::class);

    $request = Request::createFromBase($http_foundation_factory->createRequest($req));
    $response = $http_kernel->handle($request);

    $psr7_response = $http_factory->createResponse($response);
    $psr7_worker->respond($psr7_response);

    $http_kernel->terminate($request, $response);
}

// 1. 创建一个 worker,worker 通过 rpc 接收 go 传过来的 http  (go 会根据 relayDsn 监听外部 http 请求)
// 2. 通过 $psr7_worker->waitRequest() 拿到 go 传过来的 http 数据封装成 psr7 的 http request class
// 3. 之后就是正常的 laravel 请求的过程

实际上可以使用 workerman 来实现 -_-

// 告诉 workerman 将 http 请求解析成 WorkermanPsr7Request  [[https://github.com/walkor/psr7]]
WorkermanHttp::requestClass(WorkermanPsr7Request::class);

$workermanWorker = new WorkermanWorker("[[http://0.0.0.0:2346");]]
$workermanWorker->count = 4;
$workermanWorker->reusePort = true;

$app = $this->createApplication('/path/to/project-src/');
$this->bootstrapApplication($app);

$http_foundation_factory = $this->createHttpFoundationFactory();

$workermanWorker->onMessage = function (WorkermanConnectionInterface $connection, ServerRequestInterface $req) use ($app, $http_foundation_factory) {
    $sandbox = $this->createApplication('/path/to/project-src/');
    $this->bootstrapApplication($sandbox);

    // $sandbox = clone $app;

    $this->setApplicationInstance($sandbox);

    /** @var HttpKernelContract $http_kernel */
    $http_kernel = $sandbox->make(HttpKernelContract::class);

    $request = Request::createFromBase($http_foundation_factory->createRequest($req));
    $response = $http_kernel->handle($request);

    $psr7_response = $this->createWorkermanPsr7Response($response);
    $connection->send($psr7_response);

    $http_kernel->terminate($request, $response);
};

WorkermanWorker::runAll();