webman 生产部署实战:进程守护、平滑发布、监控告警与微服务化

webman 生产部署实战:进程守护、平滑发布、监控告警与微服务化

admin
2026-08-22 / 0 评论 / 7 阅读

webman 生产部署实战:进程守护、平滑发布、监控告警与微服务化

把 webman 写出来是一回事,让它安稳跑在生产上是另一回事。没有 PHP-FPM 和 supervisord 的成熟套路兜底,常驻内存服务的部署、发布、监控都有一套自己的打法。这篇是 webman 系列收官:从部署形态、平滑发布到监控告警体系,最后聊聊什么时候该拆微服务。

一、部署形态:三种选择

1. 裸机/虚拟机 + systemd(中小项目首选)

# /etc/systemd/system/webman.service
[Unit]
Description=webman app
After=network.target mysql.service redis.service

[Service]
Type=forking
WorkingDirectory=/var/www/app
ExecStart=/usr/bin/php start.php start -d
ExecReload=/usr/bin/php start.php reload
ExecStop=/usr/bin/php start.php stop
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now webman
systemctl reload webman    # 平滑发布用 reload

要点:Type=forking(start.php -d 是 daemonize 模式)、Restart=always 兜底进程崩溃、ExecReload 挂 reload 实现无感发布。

2. Docker 容器化

FROM php:8.2-cli-alpine

RUN apk add --no-cache libpq libzip-dev && docker-php-ext-install pdo_mysql opcache

COPY . /app
WORKDIR /app
RUN composer install --no-dev --optimize-autoloader

EXPOSE 8787
# 容器内前台运行(容器本身就是守护者,不需要 -d)
CMD ["php", "start.php", "start"]

容器化要点:容器里必须前台运行(去掉 -d),让 PID 1 就是 master 进程,容器崩溃重启策略(restart: always)接管守护职责。K8s 场景用 readiness 探针指向健康检查接口。

3. Supervisor 托管(多语言混合部署环境)

老牌方案,配置直观,适合还有 Python/Go 混跑的机器。

二、平滑发布:让 reload 真正"无感"

php start.php reload 的机制是逐个重启 worker(上一篇讲过),但要真正做到无感发布,还有四个坑要填:

坑一:reload 不加载的东西

reload 只重新加载 worker,master 进程内存里的东西不会更新:路由配置文件、config/ 目录、bootstrap 钩子。改了这些必须 restart(master 重建,有感知)。发布脚本要区分:

#!/bin/bash
# 简易发布脚本
git pull
composer install --no-dev --optimize-autoloader
php start.php reload      # 常规发布
# 改了 config/route/bootstrap 时:php start.php restart

坑二:发布瞬间的连接抖动

worker 逐个重启期间,正在处理中的请求要等它完成(超过 max_wait 会被强杀)。发布时把 max_wait_time 临时调大、避开高峰期,长任务(导出、批处理)走独立进程不随 worker 重启。

坑三:静态文件缓存

webman 自带静态文件支持时,浏览器缓存的旧 JS 配合新 HTML 可能白屏——资源文件名带 hash(app.a3f8c2.js)彻底解决。

坑四:发布失败的回滚

# 用软链接做版本切换,回滚 = 切回旧链接
ln -sfn /var/www/releases/20260823-0200 /var/www/app_current
php start.php restart   # 软链指向变了,restart 生效

保留最近 5 个版本目录,回滚 10 秒完成。没有回滚方案的发布都是赌博。

三、监控告警体系:四个层次

常驻内存服务必须主动监控——它出问题的方式是"安静地僵死",不是崩溃报错。

层次一:进程存活(最基础)

# 心跳脚本(cron 每分钟)
process_num=$(pgrep -f "start.php" | wc -l)
[ "$process_num" -lt 1 ] && curl -s "https://alert.example.com?msg=webman进程消失"

systemd/Docker 的 restart 能自动拉起,但频繁重启本身就是告警信号——监控 restart 次数。

层次二:业务健康检查

// 健康检查接口:不只返回 200,要真的探测依赖
Route::get('/healthz', function () {
    try {
        Db::query('SELECT 1');
        $redis = Redis::connection(); $redis->ping();
        return json(['status' => 'ok']);
    } catch (\Throwable $e) {
        return json(['status' => 'degraded', 'error' => $e->getMessage()], 503);
    }
});

K8s 的 liveness/readiness、负载均衡的健康剔除都挂这个接口。

层次三:业务指标埋点

在全局中间件里做请求级指标采集,按分钟聚合推到 Prometheus Pushgateway(或直接暴露 /metrics):

// 指标维度:路由 × 状态码 → count / 耗时分布
$metricKey = $request->path() . ':' . $response->getStatusCode();
Metrics::tick($metricKey, microtime(true) - $start);

核心告警规则参考:

告警阈值说明
错误率5xx 占比 > 1%(5 分钟窗口)最核心的质量指标
P99 延迟> 500ms体验底线
QPS 突降环比跌 50%流量异常或半死状态
内存水位worker RSS > 256M内存泄漏前兆
重启频率10 分钟内重启 > 3 次崩溃循环

worker 内存监控php start.php status 能看到每个 worker 的内存,采集脚本每分钟解析一次,单独盯内存曲线——常驻内存服务的专属指标,FPM 时代不存在这个告警维度。

层次四:日志聚合

日志按天/大小切割,错误日志单独通道。EFK/Loki 都行,关键是错误日志要能按 trace-id 串起完整调用链——中间件生成 trace-id 写入 header 和日志上下文,跨服务传递。

四、日志与排障

生产排障三板斧:

php start.php status       # 进程/连接/请求分布
php start.php connections  # 当前连接明细
tail -f runtime/logs/*.log # 慢请求日志、错误日志

两个必开配置:

// config/log.php:慢请求单独通道
'slow' => [
    'handler' => ...,
    'formatter' => ...,
],

// config/app.php
'default_timezone' => 'Asia/Shanghai',  // 别让日志时间戳漂移

OOM 被 kill 的进程:dmesg | grep -i kill 确认是内核 OOM killer 干的,然后查内存泄漏(系列第一篇的水位监控法)。

五、微服务化:什么时候拆、怎么拆

webman 常被用作微服务基座,但拆分要跟着业务痛点走

该拆的信号

  • 发布互相拖累:营销活动改一行,核心交易要陪着全量回归
  • 资源冲突:批量任务把 CPU 打满,拖垮在线接口
  • 团队协作:多组改一个仓库,merge 冲突不断

不该拆的时候

单体 + 分层(Controller / Service / Dao)+ 自定义进程隔离(在线/离线分开跑)能解决 80% 的问题。微服务是运维成本换研发效率的交易,团队没有 3 人以上运维能力前,慎拆。

webman 微服务的标准拼图

├── API 网关(webman,路由聚合/鉴权/限流)
├── 业务服务(webman,HTTP 或 JSON-RPC 内部通信)
├── 注册发现(consul / nacos / redis)
├── 异步解耦(Redis 流 / RabbitMQ,webman 的自定义进程消费)
└── 链路追踪(trace-id 贯穿 + 日志聚合)

服务间通信的务实选择:初期用 HTTP + JSON(简单直观,好排查),流量大了再换 gRPC 或原生 TCP 协议。webman 的 workerman/http-client 支持连接池复用,内部调用开销可控。

进程内优先原则:同一个 webman 实例里,用"多应用目录"(app/api、app/admin)做逻辑隔离,比拆进程便宜得多。拆物理服务的唯一理由是上面的三个信号,而不是"架构图好看"。

六、上线 Go/No-Go 清单

发布前最后一遍:

  • [ ] systemd / Docker 的自动拉起与重启告警就位
  • [ ] healthz 探测 DB + Redis,负载均衡已接健康检查
  • [ ] 发布脚本区分 reload/restart,回滚软链方案演练过
  • [ ] 错误率 / P99 / 内存 / 重启频率四条告警全部在线
  • [ ] 慢请求日志与 trace-id 链路打通
  • [ ] 压测报告:目标 QPS × 2 压过,P99 达标
  • [ ] 数据库连接预算核算(worker × 池上限 < max_connections × 0.8)
  • [ ] 灰度方案:先切 10% 流量观察 30 分钟

写在最后

webman 系列到这里完整闭环:架构模型(常驻内存的边界)→ 工程骨架(中间件与容器)→ 数据层(连接与事务)→ 性能(协程与压测)→ 生产化(部署监控与演进)。常驻内存框架的一切实践都围绕同一个心法——你运维的不是"每次请求",而是"活着的进程"。把这个视角建立起来,webman 就是你手里性价比极高的高并发利器。

0

评论 (0)

取消
0:00