美文网首页
Laravel之Roadrunner镜像

Laravel之Roadrunner镜像

作者: 上善丨若水 | 来源:发表于2020-12-31 11:59 被阅读0次

Roadrunner介绍

文档:roadrunner官方文档
roadrunner 是 go 语言开发的http服务器,主要实现两个功能。
1、监听端口,接收外部客户端的 http 请求。
2、管理 php 常驻进程,使用 psr7 规范封装请求报文、头部等信息,通过 sock/pipe 方式通信,并将 php 的执行结果回传给请求客户端。

php-fpm 与 roadrunner 区别简单对比
生命周期

image.png

PHP执行说明
例:执行 HomeController@index
php-fpm的work进程未销毁前,每触发一次web请求,会读取一次 HomeController.php 文件内容,所以修改业务代码即时生效。类似work进程执行了一个 white(true) 循环,内部执行完 php 代码后,会初始化到未执行前状态等待下次请求。

roadrunner 执行创建的 psr-worker 进程未销毁前,仅第一次触发 web 请求时读取HomeController.php 文件内容,同时保存到内存中,后续触发将不再读取文件,而是从内存中取出,所以修改代码不会即时生效。类似 php 内部实现了 white(true) 循环,在循环内接收每一次 web 请求携带的参数,执行不同业务逻辑,返回响应。这是真正意义上的常驻进程。

本地初次安装使用

  1. composer 依赖安装

composer require spiral/roadrunner
composer require symfony/psr-http-message-bridge
composer require nyholm/psr7

  1. 业务项目根目录创建文件

.rr.yaml: roadrunner配置文件
psr-worker.php: php入口文件

psr-worker.php.laravel

<?php

use Spiral\Goridge;
use Spiral\RoadRunner;
use \Illuminate\Http\Request;
use Nyholm\Psr7\Factory\Psr17Factory;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory;

ini_set('display_errors', 'stderr');
require 'vendor/autoload.php';

$app = require_once __DIR__.'/bootstrap/app.php';

if (!$app) {
    throw new \RuntimeException('Not found lumen bootstrap file.');
}

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

$relay = new Goridge\SocketRelay("rr.sock", null, Goridge\SocketRelay::SOCK_UNIX);
// $relay = new Spiral\Goridge\StreamRelay(STDIN, STDOUT);

$worker = new RoadRunner\Worker($relay);

$psr7 = new RoadRunner\PSR7Client($worker);
$httpFoundationFactory = new HttpFoundationFactory();

while ($req = $psr7->acceptRequest()) {
    try {
        $symfonyRequest = $httpFoundationFactory->createRequest($req);
        $request = Request::createFromBase($symfonyRequest);

        $response = $kernel->handle($request);

        $psr17Factory = new Psr17Factory();

        $psr7factory = new PsrHttpFactory(
            $psr17Factory, $psr17Factory, $psr17Factory, $psr17Factory
        );

        $psr7response = $psr7factory->createResponse($response);
        $psr7->respond($psr7response);

        $kernel->terminate($request, $psr7response);
    } catch (\Throwable $e) {
        $psr7->getWorker()->error((string)$e);
    }
}

psr-worker.php.lumen

<?php

use Spiral\Goridge;
use Spiral\RoadRunner;
use \Illuminate\Http\Request;
use Nyholm\Psr7\Factory\Psr17Factory;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;

ini_set('display_errors', 'stderr');
require 'vendor/autoload.php';

$app = require_once __DIR__.'/bootstrap/app.php';

if (!$app) {
    throw new \RuntimeException('Not found lumen bootstrap file.');
}

$kernel = $app->make('Laravel\Lumen\Application');

$relay = new Goridge\SocketRelay("rr.sock", null, Goridge\SocketRelay::SOCK_UNIX);
// $relay = new Spiral\Goridge\StreamRelay(STDIN, STDOUT);

$worker = new RoadRunner\Worker($relay);

$psr7 = new RoadRunner\PSR7Client($worker);
$httpFoundationFactory = new HttpFoundationFactory();

while ($req = $psr7->acceptRequest()) {
    try {
        $symfonyRequest = $httpFoundationFactory->createRequest($req);
        $request = Request::createFromBase($symfonyRequest);

        $response = $kernel->handle($request);

        $psr17Factory = new Psr17Factory();

        $psr7factory = new PsrHttpFactory(
            $psr17Factory, $psr17Factory, $psr17Factory, $psr17Factory
        );

        $psr7response = $psr7factory->createResponse($response);
        $psr7->respond($psr7response);
    } catch (\Throwable $e) {
        $psr7->getWorker()->error((string)$e);
    }
}

.rr.yaml.laravel

http:
  address: 0.0.0.0:80
  workers:
    command: "php psr-worker.php"
    relay: "unix://rr.sock"
    pool:
      numWorkers: 1
      maxJobs: 1
  http2.h2c: true

# static file serving. remove this section to disable static file serving.
static:
  # root directory for static file (HTTP would not serve .php and .htaccess files).
  dir: "public"

  # list of extensions for forbid for serving.
  forbid: [".php", ".htaccess"]

  # Always specifies list of extensions which must always be served by static
  # service, even if file not found.
  Always: [".css", ".js", ".ico", ".txt", ".svg", ".woff", ".ttf", ".gif", ".eot", ".swf"]

.rr.yaml.lumen*

http:
  address: 0.0.0.0:80
  workers:
    command: "php psr-worker.php"
    relay: "unix://rr.sock"
    pool:
      numWorkers: 1
      maxJobs: 1
  http2.h2c: true

psr-worker.php 区别:
Laravel 需要调用 terminate 方法,执行一些类似 session 写入的后置逻辑。
.rr.yaml 区别:
Laravel 需要增加 static 配置,来指定静态文件访问。
Windows 环境请注意:
由于默认设置的监听 Unix Sock,在 Windows 环境下会无法运行,需要做两处改动。
.rr.yaml
relay: "tcp://:7000"
psr-worker.php
$relay = new Goridge\SocketRelay("localhost", 7000);

  1. docker-compose.yml 配置

user:
image: registry.cn-hangzhou.aliyuncs.com/duojii/roadrunner-base:dev
volumes:
- /home/www/user:/var/www # 宿主机代码目录映射到容器中
command: rr serve -v -d -c .rr.yaml
environment:
XDEBUG_PORT: 9001
XDEBUG_HOST: 192.168.0.119
ports:
- "8000:80"           # 端口映射

注意事项

  1. 修改代码后如果不重启镜像,新代码如何生效?
    a) 执行一次 http 请求,worker 进程自动重启
    .rr.yaml 指定 worker 进程数量 和 执行任务次数

numWorkers:1
maxJobs:1
numWorkers:#number of workers to be serving.
maxJobs:#maximum jobs per worker, 0 – unlimited.

设置后只存在一个 psr-worker 进程,每执行一次请求,psr-worker 进程会销毁重建

注意:如果修改预先加载处的代码,比如 Provider、Middleware,第一次触发仍会执行内存中的旧代码,第二次新代码才会生效。

b) 进入容器,执行命令:rr http:reset,将重启所有的 php 进程。

c) Reload Configuration 自动监控文件改动
.rr.yaml 增加 reload 监控配置项

# reload can reset rr servers when files change
reload:
  # refresh interval (default 1s)
  interval: 1s

  # file extensions to watch, defaults to [.php]
  patterns: [".php"]

  # list of services to watch
  services:
    http:
      # list of dirs, "" root
      dirs: [""]
    
      # ignored dirs
      ignore: [""]

      # include sub directories
      recursive: true

注意: dirs 配置空字符串,会默认检测根目录内所有文件,非常消耗 CPU 资源同时等待时间会很久,而不是设置的 1s。所以尽量手动设置检测目录,比如监控 app 和 routes 内 php 文件,则配置 dirs: ["app", "routes"]。也可以增加配置 ignore,指定目录内的文件修改会被忽略。

两种推荐配置
1、设置监听目录
dirs: ["app", "config", "routes", "storage"]
ignore: [""]
2、设置监听忽略目录
dirs: [""]
ignore: ["bootstrap", "database", "public", "resources", "tests", "vendor"]
上述配置测试 Laravel5.6 项目,第二种 CPU 消耗略高

d) maxJobs 必须不设置或设置成 0,否则此种方案是没有意义的。快键键映射触发执行 sh 脚本,对指定项目执行 rr http:reset 命令。以 terminal-vim 环境为例,IDE 理论上也存在映射功能,此处不研究。(Windows 用户可尝试快键键是否可以映射 docker 容器命令)
1、docker-compose.yml 同目录下创建 reset-rr-worker.sh 脚本文件

#!/bin/bash

# 已启用 rr 镜像的项目目录列表
itemArray=(
'management-frontend-lanqb'
'sales-backend-lanqb'
'sales-backend-duoji'
'user-management-backend-lanqb'
'school-backend-lanqb'
'copartner-backend-lanqb'
)

# 当前执行脚本的项目目录,用于拆分项目名和跳转回去
path=`PWD`
echo "execute path:${path}"
# 截取传入的项目名
newPath=${path##*/}

# 切换本地docker-compose目录
cd ~/www/local-dev-env

for item in ${itemArray[@]};
do
    if [ "$newPath" == "$item" ]
    then
        docker-compose exec -T $item /usr/local/bin/rr http:reset
        if [ $? -ne 0 ]; then
            echo "rr-worker reset failed"
        else
            echo "rr-worker reset succeed"
        fi

        exit 0
    fi
done

echo "invalid path"

2、init.vim 文件增加快键键映射,要对应本地的脚本文件目录

noremap <leader>R :! ~/www/local-dev-env/reset-rr-worker.sh<CR>

开发过程中,可以两键重启进程,刷新代码。

四种方案各有优劣,应根据实际情况自行选择,部分缺点如下:

1、每次请求都将销毁重启 worker 进程,即使代码没有改动。部分位置代码第二次请求才会改动。
2、需要进入容器内部,手动执行命令。
3、CPU 有额外消耗。
4、非 terminal-vim 模式,配置可能比较麻烦,另外也需要本地单独配置目录。强烈推荐 mac、windows (如果 IDE 可以映射)用户使用,两种环境 docker 读取主机文件较慢,减少不必要的进程重启过程。

相关文章

  • Laravel之Roadrunner镜像

    Roadrunner介绍 文档:roadrunner官方文档[https://roadrunner.dev/doc...

  • Composer 镜像

    先说结论:推荐 Laravel China 镜像 和 cnpkg 镜像。 镜像的作用 现在 php 的开发已经离不...

  • laravel使用composer中国镜像安装

    composer指定安装Laravel镜像为中国镜像:composer config -g repo.packag...

  • 初识laravel

    1、composer中国镜像 2、全局使用composer中国镜像 3、使用composer安装laravel5....

  • Composer 部署laravel框架

    使用composer方式部署laravel项目 第一步:切换镜像为国内镜像镜像官网:https://pkg.php...

  • laravel笔记 (1)

    composer 更改为中国镜像 查看全局配置 创建laravel5.4项目 启动 laravel 网站 开发模式...

  • larvael一(用户、多语言、migrate、model、co

    composer切换国内镜像 开启多线程下载 安装laravel5.8 创建laravel自带用户模块(项目根目录...

  • 【Composer】国内镜像使用

    1. 全局配置 2. 仅在项目中使用 取消镜像 使用国内镜像安装laravel 示例 如果指定国内镜像,下载会很慢...

  • laravel / homestead镜像

    1、团队开发时,所有开发者应该使用相同的集成开发环境,以免减少产出后的问题。因此,使用虚拟机可以进行统一。 2、使...

  • laravel 从Debugbar开始

    1.创建laravel项目 先添加国内镜像 进到项目目录执行如下命令 2.php启动laravel站点 相关操作命...

网友评论

      本文标题:Laravel之Roadrunner镜像

      本文链接:https://www.haomeiwen.com/subject/eauloktx.html