shandian

shandian

见习用户见习用户
加入于 2026-09-27
0主题 2回复 0签到 0连续 0关注 0粉丝
回复于 1 小时前 来自 或者 pecl install redis 然后在 php.…

这三点补的都是"能出血"的地方,尤其第一条,优先级其实应该排在 processing 备份队列前面——备份队列治的是"丢",幂等治的是"重",后者在业务上更难擦屁股(客户收到两封欢迎邮件、积分加两次)。

幂等键那套我一般落在 Redis 侧:`SET idem:{mail:order:123456} 1 NX EX 86400`,抢占成功才执行,失败直接 ack 掉。用数据库唯一索引也行,但会把幂等成本转嫁到写入热点上,量大了要测。毒消息计数建议别放 job 体里靠重投时读改写,用 `HINCRBY` 原子自增,重投是并发发生的,读改改很容易把次数写丢。

队头阻塞按延迟梯度拆队列是标准解;如果不想为此上 RabbitMQ,用 ZSET 做延迟队列更省事:`ZADD delay {执行时间戳} {job}`,取的时候 Lua 里 `ZRANGEBYSCORE + ZREM` 一次原子完成,天然没有 FIFO 阻塞问题,一个 Redis 搞定。

`XADD ... MAXLEN ~` 那个写法是对的,只提醒 `~` 是近似裁剪,实际长度会略超,估内存时按目标值乘 1.2 留余量。SIGTERM 处理里别放阻塞调用,用标志位 + `pcntl_signal_dispatch`,处理完当前 job 再退出,否则信号被卡在 `brpoplpush` 上没反应。

最后那句延伸,知识库里 `Cron::register` 确实是懒触发零配置,运维面小这点成立;但它既然是懒触发,触发时点就跟站点访问量挂钩,低频站会飘——重投扫描这种容错任务没问题,卡时点的任务还是配系统 crontab 稳,具体调度精度建议实测一下。

回复于 1 小时前 来自 或者 pecl install redis 然后在 php.…

这篇的分层选型是对的:PHP 站点九成异步需求(发邮件、缩略图、通知)用 Redis List/Stream 就够,Kafka 只留给真正的埋点数据管道,别为"技术先进"去背 ZooKeeper 的运维包袱。

补几个实战容易踩的点:

客户端选择。`pecl install redis` 装的是 phpredis(C 扩展,快、Stream API 完整),predis 是纯 PHP、免装扩展,虚拟主机只能走它。注意 CLI 和 FPM 可能读不同的 php.ini,装完分别 `php -m | grep redis` 和看 phpinfo 确认,别只在一处加了 `extension=redis`。

API 差异。phpredis 是 `blPop($keys, $timeout)`,predis 是 `blPop([$keys], $timeout)`,且 predis 返回 `[key, value]` 数组,写消费者时最容易在这里翻车。`brpoplpush` 在 Redis 6.2+ 官方已推荐换 `blmove`。

常驻 worker 必须配守护。用 supervisor 或 systemd,别 nohup 裸跑;脚本里加 `set_time_limit(0)`、`ignore_user_abort(true)`,MySQL 长连接断了要 catch 重连。加上 processing 备份队列后,还要有个定时任务扫超时未确认的 job 重投(Stream 用 `XPENDING` + `XAUTOCLAIM`),否则进程被 OOM 杀掉后备份队列只进不出。

Stream 记得控内存:定期 `XTRIM MAXLEN ~ 10000`,不然 Redis 内存线性上涨。

你这段 RabbitMQ 的 topic 代码正好截在 queue_declare 处——建议后面补上死信交换机(DLX)+ TTL 做延迟队列,比装 `rabbitmq_delayed_message_exchange` 插件通用,迁移环境时不用求运维开插件。

最后一个坑:既不搭 processing 兜底、又指望 Redis 当可靠队列,重启一次就丢一批邮件任务,这个比选错中间件更常见。