Hyperf单机扛不住3000 QPS以上峰值的根本原因是架构未分层,必须解耦连接池、队列和服务发现;Redis Cluster需显式配置全部master节点地址、禁用AOF、设maxmemory-policy为noeviction;async-queue须按通道分级并发控制,各通道pool指向专用redis_cluster池;wait_timeout应设2.0~5.0;服务发现必须用Consul/Nacos动态拉取节点,配合熔断与连接池使用状态监控。

单机Hyperf扛不住3000 QPS以上峰值,不是代码问题,是架构没分层——连接池、队列、服务发现三者必须解耦,否则一压就崩。
Redis Cluster配置必须显式写死master节点
自动发现(auto-discovery)在高并发下极易失败,消费者进程会静默卡死,日志里没有任何报错。这不是Redis本身的问题,而是Hyperf的cluster client在连接异常时无法触发重试逻辑。
- 在
config/autoload/redis.php中定义redis_cluster池时,nodes字段必须列出全部3个master地址,例如:['192.168.10.1:7000', '192.168.10.2:7000', '192.168.10.3:7000'] - 禁用
redis.conf中的appendonly yes(即关闭AOF),改用RDB + 增量同步,避免AOF rewrite期间阻塞写入 -
maxmemory-policy不能设为volatile-lru,必须设为noeviction,否则队列消息可能被误淘汰
async_queue.php里要按通道切分并发控制
全局concurrent.limit = 10在混合业务场景下等于埋雷:一个慢任务(如报表生成)会拖垮整个队列,微信消息推送延迟飙升。
- 为不同优先级任务建独立通道,例如:
wx_msg_channel设processes => 4+limit => 25,保证实时性 -
report_channel设processes => 1+limit => 3,限制资源占用,防止单任务吃光CPU - 所有通道的
pool必须指向redis_cluster,不能复用默认redis池,否则单机Redis连接数瞬间打满
连接池wait_timeout设2.0~5.0是硬门槛
设成0.1会满屏WaitTimeoutException,设成15会让故障掩盖真实瓶颈——比如MySQL gone away后连接泄漏,协程一直卡在等连接上,而不是快速失败。
- 用
swoole_get_local_socket_count()或ss -s | grep ESTAB观察ESTABLISHED连接数是否长期贴近max_connections,如果是,说明池子真不够用,不是超时设小了 - Redis pipeline场景下,
max_connections不能只看QPS×耗时,得按「pipeline命令数 × 并发协程数」预估;例如100协程 × 每次10条命令 = 至少需1000连接 - 别漏算定时任务和WebSocket长连接——它们常驻协程会永久持有连接,容易导致新请求拿不到连接
服务发现必须用consul/nacos,不能靠DNS或静态IP列表
VPC内节点重启后IP可能漂移,静态配置会导致部分节点流量堆积甚至雪崩。least_conn负载均衡策略在动态节点下才真正有效。
- 在
config/autoload/services.php中启用hyperf/service-governance,注册中心选consul或nacos - 消费者配置中
nodes留空,让框架从注册中心动态拉取健康节点列表 - 配合
hyperf/circuit-breaker,设置failure_rate_threshold => 50,5秒内失败超一半就熔断,避免下游故障传导
最易被忽略的是定时任务和WebSocket长连接对连接池的隐性占用——它们不走HTTP生命周期,协程不退出就不归还连接。上线前务必用Coroutine::list()和swoole_get_local_socket_count()交叉验证连接实际使用状态。


















