DDD聚合模式下 webinar百万参与者重复加入校验优化方案咨询
优化用户参与研讨会的唯一性校验方案
针对你提到的「百万级参与者导致Webinar聚合体积过大」的问题,以下是几个落地性强的优化方案:
1. 引入独立聚合根「WebinarParticipation」
- 将「用户加入研讨会」这一行为抽象为独立的聚合根,每个实例仅存储
webinarId、userId、joinTime等核心字段,采用(webinarId, userId)作为复合主键。 - 校验逻辑:创建
WebinarParticipation前,先查询是否存在相同复合主键的记录,不存在则完成创建,同时触发UserJoinedWebinar领域事件,通知Webinar聚合更新参与人数等统计字段(无需维护完整参与者列表)。 - 核心优势:Webinar聚合体积被大幅压缩,复合主键在数据库层面天然保证「用户仅能加入一次」的不变量,查询和写入性能都能适配百万级规模。
2. 领域服务+数据库唯一约束兜底
- 保留Webinar和User聚合,但将唯一性校验逻辑迁移到领域服务中。
- 实现步骤:
- 新建一张
webinar_user_relations关联表,字段为webinar_id和user_id,添加联合唯一索引。 - 领域服务执行加入逻辑时,先查询该关联表是否存在对应记录;
- 若不存在,调用Webinar聚合的
updateParticipantCount()方法更新参与人数,同时向关联表插入记录。
- 新建一张
- 核心优势:Webinar聚合无需维护庞大的ID列表,数据库唯一约束直接兜底避免并发场景下的重复加入,实现简单且性能稳定。
3. 事件溯源架构下的投影表优化(若适配你的架构)
- 如果Webinar聚合采用事件溯源模式,无需存储当前参与者状态,而是通过重放事件计算,但百万级事件重放效率极低。此时可以构建投影表:
- 投影表监听
UserJoinedWebinar领域事件,实时同步webinarId和userId的关联关系,并添加联合唯一索引; - 用户尝试加入时,先查询投影表验证是否已加入,无记录则触发加入事件。
- 投影表监听
- 核心优势:Webinar聚合仅存储事件流,体积极小;投影表专门承担校验和查询职责,性能不受聚合规模影响。
额外注意事项
- 并发场景下,建议使用数据库的原子操作兜底,比如MySQL的
INSERT ... ON DUPLICATE KEY UPDATE,或者PostgreSQL的INSERT ... WHERE NOT EXISTS配合事务,避免重复插入。 - 若需要展示完整参与者列表,采用CQRS模式,单独构建查询侧的视图或报表,直接从关联表/投影表中读取数据,不要让Webinar聚合承担查询职责。
内容的提问来源于stack exchange,提问作者Sepehr Abaszadeh
相关产品推荐
相关产品推荐

