在多人同桌协同扫码点餐的典型高并发场景中,系统面临着极其苛刻的实时状态同步与并发控制挑战。 设想一个场景:同一桌台的 5 位就餐者同时使用各自的移动终端扫码进入点餐界面。用户 A 正在添加商品,用户 B 正在修改菜品规格加料,用户 C 正在执行减量删除。
如果采用传统的单体数据库锁或全量状态覆盖,会导致极其严重的“幽灵条目”与商品数量计算覆盖错误;而如果每次操作都向服务端发起全量同步 RPC 请求,在就餐高峰期将瞬间打爆 API 网关与缓存层。
本文将深度拆解,我们如何基于 无冲突复制数据类型(CRDTs) 思想,结合 Redis Hash 与 Lua 原子脚本,构建一套支持毫秒级多端合并、绝对一致性的分布式协同购物车底层中台。
一、 状态建模:基于 PN-Counter 的协同购物车数据结构设计
为了保证在无中心强锁的状态下实现多端操作的自动收敛,我们在持久缓存层将购物车中的每一个 SKU 项抽象为一个基于正向递增与负向递减计数器的结构(PN-Counter)。
在 Redis 中,我们将一桌的购物车建模为一个 Hash 结构,Key 为 cart:{tenant_id}:{table_id}:
- Field 命名规则:
{sku_id}:{spec_hash}(唯一标识菜品及其规格加料组合)。 - Value 存储结构:序列化 JSON,包含当前绝对数量、最后操作时间戳与版本序列号。
二、 原子操作与状态收敛:基于 Redis Lua 的极速增删改
为了防止并发更新时产生脏读,所有的购物车写入动作全部封装为底层的 Lua 脚本在 Redis 内存中原子执行:
-- collaborative_cart_update.lua local cart_key = KEYS[1] local item_field = ARGV[1] local delta_qty = tonumber(ARGV[2]) local item_payload_json = ARGV[3] local expire_time = tonumber(ARGV[4]) -- 1. 提取当前商品项 local existing_item = redis.call('HGET', cart_key, item_field) local current_qty = 0 if existing_item then local decoded = cjson.decode(existing_item) current_qty = decoded['qty'] end -- 2. 计算变更后数量 local final_qty = current_qty + delta_qty if final_qty <= 0 then -- 数量归零,物理移除 Field redis.call('HDEL', cart_key, item_field) else -- 更新数量并写回 Payload local new_item = cjson.decode(item_payload_json) new_item['qty'] = final_qty redis.call('HSET', cart_key, item_field, cjson.encode(new_item)) end -- 3. 刷新购物车生命周期 redis.call('EXPIRE', cart_key, expire_time) return 1
三、 广播下发:基于 WebSocket 集群的轻量级增量 Diff 扩散
当某个用户在端侧完成菜品增删并经由 Lua 执行成功后,网关层不进行全量购物车广播,而是将变更抽象为一个轻量级的 CartItemDeltaEvent。 通过 Redis Pub/Sub 广播至连接该桌其他用户的 WebSocket 网关节点。其他终端接收到增量 Diff 报文后,直接在本地内存状态树(如 Redux)中执行局部局部组件重绘,网络传输带宽降低 90% 以上,实现了多端毫秒级的流畅协同点餐体验。
【架构思想沉淀】多人协同操作的核心壁垒,在于将并发冲突在最底层的状态数据结构层面进行数学化解耦。通过将复杂业务状态拆解为原子化的计数器与不可变操作序列,配合内存级的高性能脚本引擎,我们才真正拥有了抗击高峰期高并发协同业务洪峰的工程底座。
关于作者与团队:本文由 青海青帝信息科技有限公司 核心后端基础架构研发团队原创发布。 团队专注于云原生多租户微服务底座、高并发内存级流转引擎、本地化私有中台重构与软硬件协同架构落地。期待与广大开源社区及技术同仁深入切磋。