首页
直播
壁纸
友链
搜索
1
微信小程序支付全链路实战:JSAPI 下单、调起支付、回调验签与退款
266 阅读
2
微信小程序云开发实战:云函数、云数据库与云存储的正确使用姿势
256 阅读
3
微信小程序自定义 tabBar 实战:custom-tab-bar 从适配到深色模式
255 阅读
4
微信小程序 Skyline 渲染引擎实战:worklet 动画从原理到落地
253 阅读
5
微信小程序分包进阶:独立分包、预下载与分包异步化实战
246 阅读
服务器运维
后端技术
前端技术
梯子
数据库
小程序
登录
搜索
标签搜索
fastadmin
Redis
微信小程序
前端开发
RabbitMQ
Go
服务器
codex
buildadmin
小程序
mysql
Nginx
Docker
Vue3
Node.js
MySQL优化
Linux
TypeScript
JWT
PHP
沿途的风景
累计撰写
74
篇文章
累计收到
0
条评论
首页
栏目
服务器运维
后端技术
前端技术
梯子
数据库
小程序
页面
直播
壁纸
友链
搜索到
2
篇与
» 高可用
的结果
2026-08-22
webman 生产部署实战:进程守护、平滑发布、监控告警与微服务化
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.targetsystemctl 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 就是你手里性价比极高的高并发利器。
2026年08月22日
7 阅读
0 评论
0 点赞
2026-04-22
Redis 集群方案详解:主从复制、哨兵与 Cluster
前言当单机 Redis 无法满足业务需求时,就需要引入集群方案。Redis 提供了三种主要的集群模式:主从复制、哨兵模式和 Cluster 集群。本文将系统讲解三种方案的原理、搭建和适用场景。一、主从复制1.1 架构 ┌──────────────┐ │ Master │ │ (读+写) │ └──────┬───────┘ │ 复制 ┌──────────┼──────────┐ │ │ │ ┌──────▼───┐ ┌───▼────┐ ┌──▼─────┐ │ Slave 1 │ │Slave 2 │ │Slave 3 │ │ (只读) │ │(只读) │ │(只读) │ └──────────┘ └────────┘ └────────┘1.2 工作原理全量同步:Slave 首次连接 Master 时,Master 执行 BGSAVE 生成 RDB 文件,发送给 Slave增量同步:全量同步完成后,Master 将新的写命令实时同步给 Slave断线重连:Slave 断线后重连,通过 replid + offset 判断是否可以增量同步1.3 搭建配置# slave1.conf port 6380 # 配置主节点 slaveof 192.168.1.10 6379 # 从节点只读 slave-read-only yes # 主节点密码 masterauth your_password# 启动从节点 redis-server slave1.conf # 验证主从关系 redis-cli -p 6380 INFO replication # role:slave # master_host:192.168.1.10 # master_port:63791.4 优缺点优点缺点配置简单Master 宕机需手动切换读写分离,提升读性能不具备自动故障转移数据有副本全量同步时可能阻塞 Master二、哨兵模式(Sentinel)2.1 架构┌──────────┐ ┌──────────┐ ┌──────────┐ │Sentinel 1│ │Sentinel 2│ │Sentinel 3│ │ (监控) │ │ (监控) │ │ (监控) │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ └──────┬───────┴──────┬──────┘ │ │ ┌──────▼──────┐ ┌────▼─────┐ │ Master │ │ Slave │ │ (读+写) │ │ (只读) │ └─────────────┘ └──────────┘2.2 工作原理监控:Sentinel 不断向 Master/Slave 发送 PING 命令主观下线:某个 Sentinel 发现节点无响应,标记为主观下线客观下线:超过半数 Sentinel 都报告节点下线,标记为客观下线选举 Leader:Sentinel 之间选举一个 Leader 执行故障转移故障转移:Leader 选一个 Slave 提升为新 Master,通知其他 Slave 和客户端2.3 搭建配置# sentinel1.conf port 26379 # 监控的 Master(名称 IP 端口 仲裁人数) sentinel monitor mymaster 192.168.1.10 6379 2 # Master 无响应 30 秒判定下线 sentinel down-after-milliseconds mymaster 30000 # 故障转移超时时间 sentinel failover-timeout mymaster 180000 # 同时只允许1个Slave做同步 sentinel parallel-syncs mymaster 1 # Master 密码 sentinel auth-pass mymaster your_password# 启动3个Sentinel redis-sentinel sentinel1.conf redis-sentinel sentinel2.conf redis-sentinel sentinel3.conf2.4 故障转移过程1. Master宕机 │ 2. Sentinels检测到Master无响应 │ 3. 超过quorum(2)个Sentinel标记为客观下线 │ 4. 选举Leader Sentinel │ 5. Leader选择最优Slave提升为Master: - 排除故障Slave - 选择offset最大的Slave(数据最新) - 优先级高的Slave优先 │ 6. 其他Slave指向新Master │ 7. 通知客户端新Master地址 │ 8. 旧Master恢复后变为Slave2.5 客户端连接// PHP 客户端连接 Sentinel $sentinels = [ 'tcp://192.168.1.10:26379', 'tcp://192.168.1.11:26379', 'tcp://192.168.1.12:26379', ]; $redis = new RedisSentinel($sentinels, [ 'name' => 'mymaster', 'password' => 'your_password', ]); // 自动路由到当前 Master $redis->set('key', 'value');三、Cluster 集群3.1 架构┌─────────────────────────────────────────────────────┐ │ Redis Cluster │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ Node A │ │ Node B │ │ Node C │ │ │ │Master │ │Master │ │Master │ │ │ │槽0-5460 │ │槽5461- │ │槽10923- │ │ │ │ │ │ 10922 │ │ 16383 │ │ │ └────┬────┘ └────┬────┘ └────┬────┘ │ │ │ │ │ │ │ ┌────▼────┐ ┌────▼────┐ ┌────▼────┐ │ │ │ Node A' │ │ Node B' │ │ Node C' │ │ │ │ Slave │ │ Slave │ │ Slave │ │ │ └─────────┘ └─────────┘ └─────────┘ │ └─────────────────────────────────────────────────────┘3.2 核心概念哈希槽(Hash Slot)Redis Cluster 有 16384 个哈希槽,分布在所有 Master 节点上:# 计算key属于哪个槽 slot = CRC16(key) % 16384 # 示例 # key="user:1001" → CRC16 → slot=12345 # slot 12345 属于 Node C (10923-16383)节点通信(Gossip协议)每个节点定期向其他节点发送 PING 消息,交换集群状态信息。3.3 搭建 Cluster方式一:手动搭建(6节点,3主3从)# 创建6个配置文件 for port in 7001 7002 7003 7004 7005 7006; do mkdir -p /redis/cluster/$port cat > /redis/cluster/$port/redis.conf << EOF port $port cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes dir /redis/cluster/$port EOF done # 启动6个节点 for port in 7001 7002 7003 7004 7005 7006; do redis-server /redis/cluster/$port/redis.conf & done # 创建集群 redis-cli --cluster create \ 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 \ 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 \ --cluster-replicas 1方式二:Docker Compose 搭建version: '3.8' services: redis-node-1: image: redis:7 command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7001 ports: - "7001:7001" networks: - redis-cluster redis-node-2: image: redis:7 command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7002 ports: - "7002:7002" networks: - redis-cluster # ... node-3 到 node-6 同理 redis-cluster-init: image: redis:7 command: > bash -c "sleep 10 && echo yes | redis-cli --cluster create redis-node-1:7001 redis-node-2:7002 redis-node-3:7003 redis-node-4:7004 redis-node-5:7005 redis-node-6:7006 --cluster-replicas 1" depends_on: - redis-node-1 - redis-node-2 - redis-node-3 - redis-node-4 - redis-node-5 - redis-node-6 networks: - redis-cluster networks: redis-cluster: driver: bridge3.4 客户端使用// PHP 使用 Redis Cluster $redis = new RedisCluster( null, // null 表示自动发现节点 [ '127.0.0.1:7001', '127.0.0.1:7002', '127.0.0.1:7003', ], 2, // 连接超时 2, // 读写超时 true, // 持久化连接 'password' ); // 使用方式与单机一致,客户端自动路由 $redis->set('user:1001', 'Alice'); $redis->set('user:1002', 'Bob'); $redis->set('user:1003', 'Charlie'); // 不同的key可能落在不同节点 // user:1001 → slot 12345 → Node C // user:1002 → slot 6789 → Node B // user:1003 → slot 456 → Node A3.5 Hash Tag如果需要让多个 key 落在同一个槽,使用 Hash Tag:# 用 {} 指定hash计算的部分 SET {user:1001}:profile "Alice's profile" SET {user:1001}:settings '{"theme":"dark"}' SET {user:1001}:cart "[]" # 三个key都计算 user:1001 的CRC16,落在同一个槽 # 可以在同一节点执行批量操作 MGET {user:1001}:profile {user:1001}:settings {user:1001}:cart四、三种方案对比特性主从复制Sentinel 哨兵Cluster 集群数据分片否否是(16384槽)自动故障转移否是是读写分离是是是Master单点瓶颈是是否最少节点数23+Sentinel6复杂度低中高适用场景读多写少中小规模大规模五、选型建议数据量 < 10GB? ├── 是 → 单机Redis够用 │ └── 需要高可用? │ ├── 是 → Sentinel(3节点+3哨兵) │ └── 否 → 单机 │ └── 否 → 数据量大/并发高 └── Redis Cluster(3主3从起步)生产环境推荐中小项目:Sentinel 哨兵(1主2从+3哨兵)大型项目:Redis Cluster(3主3从起步,按需扩展)极大规模:Cluster + 多机房部署 + 代理层六、运维注意事项6.1 内存监控# 查看各节点内存使用 redis-cli -p 7001 INFO memory | grep used_memory_human redis-cli -p 7002 INFO memory | grep used_memory_human redis-cli -p 7003 INFO memory | grep used_memory_human # 集群整体状态 redis-cli -p 7001 CLUSTER INFO redis-cli -p 7001 CLUSTER NODES6.2 扩容(Cluster)# 新增节点 redis-server /redis/cluster/7007/redis.conf # 加入集群 redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7001 # 分配槽位(从现有节点迁移部分槽到新节点) redis-cli --cluster reshard 127.0.0.1:7001 \ --cluster-from <现有节点ID> \ --cluster-to <新节点ID> \ --cluster-slots 1000 \ --cluster-yes6.3 数据迁移# 在线迁移(不停服) redis-cli --cluster rebalance 127.0.0.1:7001 \ --cluster-use-empty-masters \ --cluster-threshold 1总结方案核心价值关键限制主从复制读写分离、数据备份无自动故障转移Sentinel自动故障转移、高可用单Master写入瓶颈Cluster数据分片、水平扩展不支持跨槽事务、复杂度高选择原则:先评估数据量和并发量,小规模用 Sentinel,大规模用 Cluster,不要过度设计。
2026年04月22日
15 阅读
0 评论
0 点赞
0:00