roadrunner中文文档(四)app服务器

2021年6月8日13:18:46

服务器命令

RoadRunner 应用程序可以通过从 PHP 应用程序的根调用一个简单的命令来启动。

$ rr serve

您还可以使用自定义位置的配置启动 RoadRunner:

$ rr serve -c ./app/.rr.yaml

重新加载所有 RoadRunner 服务:

$ rr reset

您可以将此命令附加为 IDE 中的文件观察器。

仅重置特定插件:

$ rr reset http

运行 golang pprof 服务器(调试模式):

$ rr serve -d -c .rr.yaml

以交互模式查看所有活动工作人员的状态。

$ rr workers -i
Workers of [http]:
+---------+-----------+---------+---------+-----------------+
|   PID   |  STATUS   |  EXECS  | MEMORY  |     CREATED     |
+---------+-----------+---------+---------+-----------------+
|    9440 | ready     |  42,320 | 31 MB   | 22 days ago     |
|    9447 | ready     |  42,329 | 31 MB   | 22 days ago     |
|    9454 | ready     |  42,306 | 31 MB   | 22 days ago     |
|    9461 | ready     |  42,316 | 31 MB   | 22 days ago     |
+---------+-----------+---------+---------+-----------------+

日志记录

RoadRunner 提供了单独控制每个插件的日志的能力。

全局配置

要全局配置日志记录,请使用logsconfig 部分:

logs:
  mode: production
  output: stderr

使用开发模式。它启用开发模式(使 DPanicLevel 日志恐慌),使用控制台编码器,写入标准错误,并禁用采样。堆栈跟踪会自动包含在 WarnLevel 及更高级别的日志中。

logs:
  mode: development

输出到单独的文件:

logs:
  mode: production
  output: file.log

要使用控制台友好输出:

logs:
  encoding: console # default value

要抑制特定日志级别下的消息:

logs:
  encoding: console # default value
  level: info

频道

此外,您可以使用channels部分单独配置每个插件日志消息:

logs:
  encoding: console # default value
  level: info channels: server.mode: none # disable server logging. Also `off` can be used. http: mode: production output: http.log

概括:

  1. 级别:panicerrorwarninfodebug。默认值:debug
  2. 编码:consolejson. 默认值:console
  3. 模式:productiondevelopmentraw. 默认值:development
  4. 输出:file.logstderrstdout。默认stderr.
  5. 错误输出:err_file.logstderrstdout。默认stderr.

随意注册您自己的ZapLogger扩展。

自动重载

RoadRunner 能够自动检测 PHP 文件更改并重新加载连接的服务。这种方法使您无需max_jobs: 1手动或手动重置服务器即可开发应用程序。

配置

要为 http 服务启用重新加载:

reload:
  # sync interval
  interval: 1s
  # global patterns to sync patterns: [ ".php" ] # list of included for sync services services: http: # recursive search for file patterns to add recursive: true # ignored folders ignore: [ "vendor" ] # service specific file pattens to sync patterns: [ ".php", ".go", ".md" ] # directories to sync. If recursive is set to true, # recursive sync will be applied only to the directories in `dirs` section dirs: [ "." ]

性能

reload组件会影响应用服务器的性能。确保仅在开发模式下使用它。将来我们计划重写此插件以使用通知事件的本机操作系统功能。

生产用途

在生产环境中运行 RoadRunner 时,必须承认多个提示和建议。

状态和记忆

状态和内存不在不同的工作实例之间共享,而是为单个工作实例共享。由于单个工作人员通常处理多个请求,因此您应该小心:

  • 确保关闭所有描述符(尤其是在出现致命异常的情况下)。
  • [可选]gc_collect_cycles如果您想保持低内存,请考虑在每次执行后调用(这会稍微减慢您的应用程序的速度)。
  • 观察内存泄漏 - 您必须对使用的组件更加挑剔。如果出现内存泄漏,Worker 将被重新启动,但通过正确设计应用程序来完全避免这个问题应该不难。
  • 避免状态污染(即内存中的全局变量或用户数据缓存)。
  • 数据库连接和任何管道/套接字都是潜在的故障点。处理它的简单方法是在每次迭代后关闭所有连接。请注意,它不是性能最高的解决方案。

配置

  • 确保不要在 RPC 服务中监听 0.0.0.0(除非在 Docker 中)。
  • 使用管道连接到一个工人以获得更高的性能(Unix 套接字只是慢一点)。
  • 将您的泳池时间调整为您喜欢的值。
  • workers = 系统中的 CPU 线程数,除非您的应用程序受 IO 限制,否则请试探性地选择该数量。
  • max_jobs如果您在一段时间内遇到任何应用程序稳定性问题,请考虑为您的员工使用。
  • RoadRunner 使用 Keep-Alive 连接的性能提高 40%。
  • 将内存限制设置为至少 10-20% 以下max_memory_usage
  • 由于 RoadRunner 工作人员从 cli 运行,您需要通过opcache.enable_cli=1.
  • 在云环境中运行 rr 时,请确保使用健康检查端点
  • 使用user配置中的选项从基于 Linux 的系统上的特定用户启动工作进程。

在 Linux 上将 RR 服务器作为守护进程运行

在 RR 存储库中,您可以找到 rr.server systemd 单元文件。该文件的结构如下:

[Unit]
Description=High-performance PHP application server

[Service]
Type=simple
ExecStart=/usr/local/bin/roadrunner serve -c <path/to/.rr.yaml>
Restart=always
RestartSec=30

[Install]
WantedBy=default.target

用户应该做的唯一一件事就是ExecStart用您自己的选项更新选项。为此,请设置正确的roadrunner二进制路径、所需标志和 .rr.yaml 文件的路径。通常,此类用户单元文件位于.config/systemd/user/. 对于 RR,它可能是.config/systemd/user/rr.service. 要启用它,请使用以下命令:systemctl enable --user rr.servicesystemctl start rr.service. 就是这样。现在 roadrunner 应该在你的服务器上作为守护进程运行。

此外,您可以在此处找到有关 systemd 单元文件的更多信息:链接

应用指标

RoadRunner 服务器包括一个基于Prometheus的嵌入式指标服务器。

启用指标

要启用指标添加metrics部分到您的配置:

metrics:
  address: localhost:2112

完成后,您可以使用http://localhost:2112/metricsurl访问 Prometheus 指标。

确保安装指标扩展:

$ composer require spiral/roadrunner-metrics

应用指标

您还可以使用到服务器的 RPC 连接发布特定于应用程序的指标。首先,您必须在配置文件中注册一个指标:

metrics:
  address: localhost:2112
  collect:
    app_metric_counter: type: counter help: "Application counter."

从应用程序发送指标:

$metrics =new RoadRunner\Metrics\Metrics(
    Goridge\RPC\RPC::create(RoadRunner\Environment::fromGlobals()->getRPCAddress())
);

$metrics->add('app_metric_counter', 1);

支持的类型:仪表、计数器、汇总、直方图。

标记指标

您可以使用标记(标签)指标对值进行分组:

metrics:
  address: localhost:2112
  collect:
    app_type_duration: type: histogram help: "Application counter." labels: ["type"]

您应该在推送指标时为标签指定值:

$metrics =new RoadRunner\Metrics\Metrics(
    Goridge\RPC\RPC::create(RoadRunner\Environment::fromGlobals()->getRPCAddress())
);

$metrics->add('app_type_duration', 0.5, ['some-type']);

声明指标

您可以从 PHP 应用程序本身声明指标:

$metrics->declare('test',
    RoadRunner\Metrics\Collector::counter()->withHelp('Test counter')
);


健康端点

RoadRunner 服务器包含一个健康检查端点,用于返回工作人员的健康状况。

启用健康

要启用运行状况检查端点,请status在您的配置中添加一个部分:

status:
  address: localhost:2114

要访问修复检查,请使用以下 URL:

http://localhost:2114/health?plugin=http

您可以使用健康检查检查一个或多个插件。目前,仅支持 HTTP。

启用后,运行状况检查端点将响应以下内容:

  • HTTP 200如果至少有一名工作人员准备好处理请求。
  • HTTP 500如果没有工作人员准备好为请求提供服务。

用例

运行状况检查端点可用于以下用途:

搭建服务器

RoadRunner 使用 Endure 来管理依赖项,这允许您为每个单独的项目调整和扩展应用程序功能。

安装 Golang

要构建应用服务器,您需要安装Golang 1.16+

创建 main.go

main.go文件复制项目的根目录中。

package main

import (
    "log"

    endure "github.com/spiral/endure/pkg/container"
    // plugins "github.com/spiral/roadrunner-binary/v2/cli" httpPlugin "github.com/spiral/roadrunner/v2/plugins/http" "github.com/spiral/roadrunner/v2/plugins/informer" "github.com/spiral/roadrunner/v2/plugins/kv/boltdb" "github.com/spiral/roadrunner/v2/plugins/kv/memcached" "github.com/spiral/roadrunner/v2/plugins/kv/memory" "github.com/spiral/roadrunner/v2/plugins/logger" "github.com/spiral/roadrunner/v2/plugins/metrics" "github.com/spiral/roadrunner/v2/plugins/redis" "github.com/spiral/roadrunner/v2/plugins/reload" "github.com/spiral/roadrunner/v2/plugins/resetter" "github.com/spiral/roadrunner/v2/plugins/rpc" "github.com/spiral/roadrunner/v2/plugins/server" "github.com/temporalio/roadrunner-temporal/activity" temporalClient "github.com/temporalio/roadrunner-temporal/client" "github.com/temporalio/roadrunner-temporal/workflow" ) func main() { var err error cli.Container, err = endure.NewContainer(nil, endure.SetLogLevel(endure.ErrorLevel), endure.RetryOnFail(false)) if err != nil { log.Fatal(err) } err = cli.Container.RegisterAll( // logger plugin &logger.ZapLogger{}, // metrics plugin &metrics.Plugin{}, // http server plugin &httpPlugin.Plugin{}, // reload plugin &reload.Plugin{}, // informer plugin (./rr workers, ./rr workers -i) &informer.Plugin{}, // resetter plugin (./rr reset) &resetter.Plugin{}, // rpc plugin (workers, reset) &rpc.Plugin{}, // server plugin (NewWorker, NewWorkerPool) &server.Plugin{}, // temporal plugins &temporalClient.Plugin{}, &activity.Plugin{}, &workflow.Plugin{}, ) if err != nil { log.Fatal(err) } cli.Execute() }

您现在无需构建go run main.go serve.

了解如何创建http 中间件以拦截 HTTP 流。

RPC 集成

您可以使用共享 RPC 总线从 PHP 工作人员连接到 RoadRunner 服务器。为此,您必须创建一个RPC类的实例,并将其配置为使用.rr文件中指定的地址。

要求

要在 RPC 模式下从 PHP 应用程序连接到 RoadRunner,您需要:

  • ext-sockets
  • ext-json

配置

要更改默认的 RPC 端口 (localhost:6001),请使用:

rpc:
  listen: tcp://127.0.0.1:6001
$rpc = Goridge\RPC\RPC::create(RoadRunner\Environment::fromGlobals()->getRPCAddress());

您可以立即使用此 RPC 调用嵌入式 RPC 服务,例如 HTTP:

var_dump($rpc->call('informer.Workers', 'http'));

您可以在本节中阅读如何创建自己的服务和 RPC 方法。

编写插件

RoadRunner 使用 Endure 容器来管理依赖项。这种方法类似于具有自动方法注入的 PHP 容器实现。您可以创建自己的插件、事件侦听器、中间件等。

要定义您的插件,请使用公共Init方法创建一个带有错误返回值的结构(您可以spiral/errors用作error包):

package custom

const PluginName = "custom"

type Plugin struct{} func (s *Plugin) Init() error { return nil }

您可以通过创建自定义版本的main.go文件并构建它来注册您的插件。

依赖关系

您可以通过在您的Init方法中请求依赖项来访问其他 RoadRunner 插件:

package custom

import (
    "github.com/spiral/roadrunner/v2/plugins/http"
    "github.com/spiral/roadrunner/v2/plugins/rpc"
)

type Service struct { } func (s *Service) Init(r *rpc.Plugin, rr *http.Plugin) error { return nil }

确保请求依赖项作为指针。

配置

在大多数情况下,您的服务需要一组配置值。RoadRunner 可以使用config插件(通过接口)自动填充和验证您的配置结构:

配置示例:

custom:
  address: tcp://localhost:8888

插入:

package custom

import (
    "github.com/spiral/roadrunner/v2/plugins/config"
    "github.com/spiral/roadrunner/v2/plugins/http"
    "github.com/spiral/roadrunner/v2/plugins/rpc" "github.com/spiral/errors" ) const PluginName = "custom" type Config struct{ Address string `mapstructure:"address"` } type Plugin struct { cfg *Config } // You can also initialize some defaults values for config keys func (cfg *Config) InitDefaults() { if cfg.Address == "" { cfg.Address = "tcp://localhost:8088" } } func (s *Plugin) Init(r *rpc.Plugin, h *http.Plugin, cfg config.Configurer) error { const op = errors.Op("custom_plugin_init") // error operation name if !cfg.Has(PluginName) { return errors.E(op, errors.Disabled) } // unmarshall err := cfg.UnmarshalKey(PluginName, &s.cfg) if err != nil { // Error will stop execution return errors.E(op, err) } // Init defaults s.cfg.InitDefaults() return nil } 

errors.Disabled是一种特殊的错误,它指示 Endure 禁用此插件和此根的所有依赖项。如果至少插件保持活动状态,RR2 将在此错误类型后继续工作。

服务

在您的结构中创建ServeStop方法,让 RoadRunner 启动和停止您的服务。

type Plugin struct {}

func (s *Plugin) Serve() chan error { const op = errors.Op("custom_plugin_serve") errCh := make(chan error, 1) err := s.DoSomeWork() err != nil { errCh <- errors.E(op, err) return errCh } return nil } func (s *Plugin) Stop() error { return s.stopServing() } func (s *Plugin) DoSomeWork() error { return nil }

Serve方法是线程安全的。它运行在由Endure容器管理的单独 goroutine中。一个注意事项是,您应该在调用Stop容器时取消阻止它。否则,超时后服务将被杀死(可在 Endure 中设置)。

在运行时收集依赖项

RR2 提供了一种通过Collects接口在运行时收集依赖项的方法。这对于中间件或具有附加功能的扩展插件非常有用,而无需更改它。让我们创建一个 HTTP 中间件:

步骤(以实际http插件和Middleware界面为例):

  1. 声明一个必需的接口

    // Middleware interface
    type Middleware interface {
    Middleware(f http.Handler) http.HandlerFunc
    }
  2. 实现方法,它应该有一个参数名称(endure.Named接口)和Middleware(步骤 1)。

// Collects collecting http middlewares
func (s *Plugin) AddMiddleware(name endure.Named, m Middleware) {
    s.mdwr[name.Name()] = m
}
  1. Collects为所需结构实现持久接口并返回在步骤 2 方法上实现的。
// Collects collecting http middlewares
func (s *Plugin) Collects() []interface{} { return []interface{}{ s.AddMiddleware, } }

Endure 将自动检查注册的结构是否实现了该AddMiddleware方法的所有参数(如果参数是结构,则会找到一个结构)。在我们的例子中,一个结构应该实现endure.Named接口(它返回插件的用户友好名称)和Middleware接口。

RPC 方法

您还可以使用 EndureCollects接口为 PHP 工作人员公开一组 RPC 方法。Endure 将自动获取结构并在PluginName名称下公开 RPC 方法。

用 RPC 方法扩展你的插件,插件根本不会改变。唯一要做的一件事是使用 RPC 方法创建一个文件(我们称之为rpc.go),并在此处公开插件的所有 RPC 方法,而无需更改插件本身:基于informer插件的示例:

我假设我们创建了一个文件rpc.go。下一步是创建一个结构:

  1. 创建一个结构:(记录器是可选的)
package custom

type rpc struct {
    srv *Plugin
    log logger.Logger
}
  1. 创建一个要公开的方法:
func (s *rpc) Hello(input string, output *string) error {
    *output = input
    return nil
}
  1. 使用Collects接口向 Endure 公开 RPC 服务:
// CollectTarget resettable service.
func (p *Plugin) CollectTarget(name endure.Named, r Informer) error {
    p.registry[name.Name()] = r
    return nil
}

// Collects declares services to be collected.
func (p *Plugin) Collects() []interface{} {
    return []interface{}{
        p.CollectTarget,
    }
}

// Name of the service.
func (p *Plugin) Name() string {
    return PluginName
}

// RPCService returns associated rpc service.
func (p *Plugin) RPC() interface{} {
    return &rpc{srv: p, log: p.log}
}

让我们来看看这些方法:

  1. CollectTarget:告诉 Endure,我们要收集所有实现endure.NamedInformer接口的插件。
  2. Collects: 忍接口实现。
  3. Name:endure.Named返回用户友好插件名称的接口实现。
  4. RPC: RPC plugin 收集所有实现RPC接口和endure.Named. RPC 接口不接受任何参数,但返回接口(插件)。

要使用RPC 实例在 PHP 中使用它:

var_dump($rpc->call('custom.Hello', 'world'));

服务插件

服务插件是在 RR 中引入的v2.0.5

主要能力

  1. 执行 PHP 代码、二进制文件、bash/powershell 脚本。
  2. 指定时间后重新启动。
  3. 控制特定命令的执行时间。
  4. 提供统计到Informer约插件%CPUPID和使用RSS memory

配置

service:
  some_service_1:
    command: "php tests/plugins/service/test_files/loop.php"
    process_num: 10 exec_timeout: 0 remain_after_exit: true restart_sec: 1 some_service_2: command: "tests/plugins/service/test_files/test_binary" process_num: 1 remain_after_exit: true restart_delay: 1s exec_timeout: 0

描述:

  1. 服务插件支持任意数量的嵌套命令。

  2. command- 要执行的命令。这里对命令没有限制。这里可能是二进制文件、PHP 文件、脚本等。

  3. process_num - 默认值:1,命令触发的进程数。

  4. exec_timeout - 默认值:0(无限制),允许进程运行的最大时间。

  5. remain_after_exit- 默认值:假。退出后保留进程。例如,如果你需要每 10 秒重启一次进程 exec_timeout应该是 10s,并且remain_after_exit应该设置为 true。注意:如果您从外部终止该进程并且如果remain_after_exit为 true,则该进程将重新启动。

  6. restart_sec- 默认值:30 秒。进程停止和重新启动之间的延迟。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值