Node.js多Worker场景下MySQL原子读写及高性能共享内存方案咨询
可行性结论
该需求完全可以基于MySQL实现,数百级WebSocket并发场景下性能冗余度极高,完全满足ACID要求,不会出现计数失真、并发冲突问题。
MySQL落地实现方案
首先建InnoDB引擎的服务器负载表,结构如下:
CREATE TABLE `server_load` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `server_addr` varchar(128) NOT NULL COMMENT '服务器访问地址', `conn_count` int unsigned NOT NULL DEFAULT '0' COMMENT '当前承载连接数', `is_available` tinyint NOT NULL DEFAULT '1' COMMENT '1=可用 0=不可用', PRIMARY KEY (`id`), KEY `idx_available_count` (`is_available`,`conn_count`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
核心逻辑不要拆成「先查询再更新」的两步操作,也不要用普通事务包裹两步SQL,直接用单条原子SQL完成「选最低负载可用节点+计数+1+返回选中节点」全流程:
-- MySQL 8.0及以上版本支持RETURNING语法,直接返回更新后的节点信息 UPDATE server_load SET conn_count = conn_count + 1 WHERE id = ( SELECT id FROM ( SELECT id FROM server_load WHERE is_available = 1 ORDER BY conn_count ASC LIMIT 1 FOR UPDATE SKIP LOCKED ) AS tmp ) RETURNING id, server_addr, conn_count;
如果是5.7及以下老版本MySQL不支持RETURNING,可以把更新和查结果放在同个事务里,因为FOR UPDATE SKIP LOCKED已经加了行锁,不会出现并发冲突:
BEGIN; SELECT id, server_addr, conn_count FROM server_load WHERE is_available = 1 ORDER BY conn_count ASC LIMIT 1 FOR UPDATE SKIP LOCKED; -- 拿到上一步返回的id后执行更新 UPDATE server_load SET conn_count = conn_count +1 WHERE id = ?; COMMIT;
该方案的可靠性说明:
- 所有操作基于InnoDB事务机制,原子性、一致性、隔离性、持久性完全满足ACID规范
FOR UPDATE SKIP LOCKED会给选中的单条记录加排他锁,并发请求不会阻塞在同一行锁上,会自动跳过已加锁的记录选择下一个符合条件的节点,既不会出现重复选同一台服务器导致计数不准的问题,也不会阻塞无关资源的操作- 联合索引
idx_available_count覆盖了查询过滤、排序的全字段,不需要回表,单条SQL执行耗时在亚毫秒级,数百并发场景下几乎无性能压力,常规配置的MySQL实例可以轻松支撑数万QPS的调度请求 - 业务侧连接断开时,执行
UPDATE server_load SET conn_count = conn_count -1 WHERE id = ?回退计数即可,服务器上下线直接修改is_available字段值。
性能更优的替代方案
如果后续并发规模上涨到万级以上,想要更低的调度延迟,可以选择以下内存级方案,性能比MySQL高1~2个量级:
- Redis方案:将服务器负载数据存在Redis有序集合中,用
conn_count作为成员score,编写Lua脚本实现「取score最小的可用成员+对应score+1」逻辑,Redis单线程执行Lua脚本天然保证原子性,整个操作在内存中完成,延迟在微秒级,只需要开启AOF持久化避免宕机丢数据即可,运维成本也很低。 - 调度服务本地原子计数方案:如果调度服务是单实例部署,直接在服务内存中用原子变量维护每台服务器的连接计数,每次调度直接选计数最小的节点,零网络开销,性能最高。如果调度服务多实例部署,配合轻量gossip协议同步各节点负载数据即可,适合超大规模集群场景。
选型建议
当前数百并发的场景直接用MySQL方案即可,不需要额外引入新组件,运维成本最低,稳定性经过大量生产场景验证。等后续并发规模涨到万级以上再考虑切换Redis方案也完全来得及。
内容的提问来源于stack exchange,提问作者BGPHiJACK
相关产品推荐
相关产品推荐

