2026/4/18 12:41:22
网站建设
项目流程
需要前置审批的网站,济南做网站的高端品牌,wordpress 本地搭建,建设集团公司简介“秒杀”是电商平台最典型的高并发促销场景#xff0c;双十一等大促活动也常以秒杀能力作为数据库技术实力的标志。随着小红书电商业务快速增长#xff0c;直播带货等爆品场景对极致下单速度的需求更加突出#xff0c;希望将下单吞吐提升至 1W/s。 基于 MySQL 内核实现的合并…“秒杀”是电商平台最典型的高并发促销场景双十一等大促活动也常以秒杀能力作为数据库技术实力的标志。随着小红书电商业务快速增长直播带货等爆品场景对极致下单速度的需求更加突出希望将下单吞吐提升至 1W/s。基于 MySQL 内核实现的合并秒杀优化相对排队秒杀方案将秒杀写入能力再提升 5 倍相对MySQL 社区版本更有百倍的性能提升。在设计上保持了和排队秒杀一致的能力该能力对业务完全透明仅需升级 MySQL 内核无需改动 SQL即可获得 5 倍以上性能提升。该方案不仅显著提升库存、优惠券、红包等高抢购场景的用户体验也能在热门笔记点赞等高频写入场景实现数量级性能增强。24年小红书数据库团队首次通过对热点线程排队将自研版本秒杀性能提升了10倍但依然跟不上业务的快速发展。尤其是在直播带货、热门笔记点赞、爆品抢购等场景下业务迫切需要更快的秒杀速度本次数据库团队在自研内核上迭代实现了合并秒杀方案将热点行更新速度提升5倍至1.5W/s极大提升了用户的使用体验。合并秒杀版本在方案设计时考虑了和排队版本的兼容性内核会根据SQL自动选择最优的秒杀方案。对于热点SQL内核会依据SQL自动选择合并秒杀、排队秒杀和普通更新的最优解只需升级MySQL内核版本无需业务侧修改SQL即可享受到5倍以上的性能提升。从下面性能分析图可以看到在128线程秒杀时TPS从4276提升至23543提升约5.5倍。在1024线程极端场景下仍然有4.7倍性能提升。随着线程数的升高线程切换的开销越来越大TPS也逐步下降因此建议线程数保持在128-256之间以获得最佳性能。测试数据均为sysbench模拟标准库存扣减模型进行的压测数据。首先对秒杀场景进行分析抽象出了它的事务模型。下面所示为最经典的库存扣减模型begin;insert into inventory_log value (...);-- 插入库存修改的流水表update inventory set quantityquantity-1 where sku_id? and quantity 0;-- 扣减库存表commit;随着并发数的增加数据库的update写入性能急剧下降最终基本处于不可用的状态TPS约为100-200出现非常严重的卡顿下面将依次分析不同方案的性能瓶颈点和解决思路。3.1 排队秒杀提升点合并秒杀版本重点解决了性能下降问题将秒杀性能维持在一个性能基本不变的状态。左右滑动查看3.2 合并秒杀提升点再次分析上面的库存扣减模型每个事务都是begininsertupdatecommit这种格式。那么insert是插入不同的行主键不一样所以可以并发但是update是对同一行的改写无法并发红色的标识为临界区行锁。所以性能的瓶颈点在update同一行的修改上秒杀V2将解决该瓶颈点。左右滑动查看3.3 方案总结将上述方案的瓶颈点和解决思路整合如下对比所示直观反映了各方案的优化思路。左右滑动查看合并秒杀将多个事务 SQL 合并到一个事务进行提交修改了MySQL的事务模型必然涉及到MySQL事务系统、锁系统、Binlog系统等模块的修改。合并秒杀方案提供了如下优势生态组件无感知将改动内容收敛到MySQL内核输出的 Binlog内容和格式没有变化对于DTS/Canel等组件无感知避免了联动组件升级内核升级无感知不修改InnoDB格式不影响版本兼容性和版本回退业务SQL无修改和排队秒杀版本SQL语法兼容可以动态开关。业务/DBA可以随时将合并秒杀退化到排队秒杀也可以随时开启。可以同时将合并秒杀排队秒杀无秒杀在一个数据库同时跑起来减少业务迁移成本。一句话总结本方案合并秒杀通过Leader预读取库存数据写入缓存在缓存中进行Follower库存数据合并扣减最后Leader一次性将合并数据写入存储引擎提升了写入性能。4.1 缓存可见性为了合并秒杀要解决如下两个问题数据的可见性目前MySQL的数据是线程可见的这样最方便。但是合并秒杀是需要多个线程之间共享数据的。数据一致性问题Leader-Follower的数据同步问题要做好状态的流转。4.1.1 数据可见性为了解决以上问题按照表维度添加了全局缓存多个线程操作同一张表的结构体访问同一份缓存缓存的生命周期和表结构是一样的方便缓存管理。4.1.2 数据一致性解决了数据的可见性问题剩下的核心点就是解决Leader-Follower的数据同步问题保证数据的一致性。下面一张图系统的展示了一个Leader两个Follower线程是如何配合扣减三次的首先三个客户端发送了相同的update语句。经过了Queue PK由于开启了合并秒杀跳过了排队秒杀过程三个线程开始抢独占锁最先抢到的将自己标记为Leader然后读取InnoDB数据和更新数据将修改后的数据写入全局缓存。Leader做完了工作释放独占锁开始进入收集状态等待若干毫秒另外两个Follower开始抢独占锁。抢到的标记为Follower然后将全局缓存数据写入线程缓存然后更新线程缓存完成扣减最后将线程缓存数据再写入全局缓存。释放独占锁进入等待唤醒状态。在全局缓存中完成Follower的库存扣减后面的线程依次进入Follower过程按照读全局缓存-完成扣减-更新全局缓存的过程依次执行了update语句扣减Leader线程完成了收集重新申请独占锁将全局缓存数据作为本组最终扣减的值。开始进入2PC过程完成最终数据提交。Leader完成后会唤醒Follower所有SQL结束4.2 行锁极致优化上面的过程看起来配合的非常好是否还有优化空间再次回到下面的这张图将update分为两个步骤一个是收集更新缓存阶段phase 1一个是commit阶段phase 2。如果将多个组提交按照时间串起来可以看到上一个组必须commit完释放了行锁才能让下一个组重新申请行锁。如下图所示。所以整个流水线在组内是合并提交的但是组和组之间是完全的串行。如按照两个阶段分为两个组那么在第一个组进行commit的时候第二个组完全可以开始收集无需等待第一组commit完成。这样整体的执行时间会进一步压缩。以两个组为例第一个组从1000扣减50为950那么在第一个组提交950的时候第二个组可以从950开始扣减。如下图所示绿色部分就是节省的时间。4.3 Binlog并行提交整个组的Binlog是同一批由Leader统一提交。4.4 Crash Recovery优化Crash Recovery过程简单来说先由Binlog生成一个事务集合然后拿到Redolog进行对比该提交就提交该回滚就回滚。合并秒杀是Leader提交Binlog将整个组的Binlog都写入Redolog记录的是合并前后的值例如1000-900)但是binlog记录的是每个事务的改动1000-999, 999-998)。所以要回滚Redolog的内容或者提交Redolog的内容必须要求整个Binlog组的完整性左右滑动查看对于以上两种场景Crash Recovery需要做好兼容处理。具体的思路如下:以数据组为单位进行扣减数据的提交和回滚相对事务粒度更大一些。正如上面所述在内核中使用的Hint关键字如下致谢感谢阿里云RDS团队在方案中的技术支持并在关键问题定位与优化建议方面提供了帮助。https://mp.weixin.qq.com/s/Q-tap7xI3Y5diTMEt5hMyw