首页 > 数据库 > 数据库开发技术 > 解决一个互斥问题,系统并发用户数提升了10倍!
互斥锁在并发场景下是确保业务操作原子性、解决互斥访问问题的重要工具。虽然在互联网分布式系统和嵌入式并发中广泛使用,但不当选择和使用互斥锁可能导致性能瓶颈。
我将分享一个互联网场景下的互斥锁优化案例。通过分析优化前的软件实现、性能瓶颈,以及优化解决方案,我将揭示优化互斥锁的方法,如何将业务 RPS(请求吞吐量)性能指标提升10倍以上。这将帮助你在实际业务中准确判断哪些互斥锁可优化,哪些不可。此外,你还将学会手动实现事务机制(支持业务操作回滚),替代互斥锁以进一步提升软件性能。
优化前的业务实现为什么会有性能问题?
用户给在线表单提交一条记录,在这条记录中会包含很多个字段内容,其中有些字段在插入时有一个规则要求,即不能与已有的字段值重复。

在该业务中,使用了Redis锁实现互斥访问,确保被锁定的业务逻辑执行具有原子性。这导致被锁定的计算逻辑在系统中是串行执行的。
该业务使用Redis锁来确保插入字段值的唯一性。检查字段不重复时,系统会遍历所有要求唯一性的字段项,若发现任何一个字段值重复,则插入失败。其他关键业务操作也通过加锁实现原子性执行,成功则进入下一步,否则直接退出。
最后,所有字段插入由于加锁原子性,前面的唯一性检测条件仍然有效。在优化前的代码中,需要重复性校验的字段记录在Redis中,操作1和操作3都基于Redis实现。
为什么不使用关系数据库中的字段唯一性检测呢?因为业务系统中有大约1000万张表单,每张表单的字段唯一性规则可能不同,且可由用户随意修改。因此,将所有表单字段存储在一张大表中,无法使用数据库表上的字段唯一性规则来处理这个问题。
原来的这种 Redis 加锁的实现方式比较简单,而且是按照单个表单来进行加锁的,所以在单个表单并发提交请求吞吐量不是很大的情况下,并不会对系统性能产生太大的影响。
随着系统业务规模增大,某些表单的并发请求吞吐量可能激增。当单个表单提交请求超过并发吞吐量上限时,可能导致两个严重性能问题:
首先,用户在提交表单时可能遇到页面卡死,导致数据提交失败;
其次,基于进程模型的后端服务系统资源有限,个别表单的处理进程被阻塞,可能导致整个系统无法正常处理业务请求。
因此,提升单个表单提交请求吞吐量成为系统性能优化的关键问题。现在我们需要弄清楚的是,互斥锁是如何影响表单请求吞吐量性能的。
互斥锁是如何影响最大请求吞吐量的?
互斥锁在并发场景中的主要作用是确保关键业务操作的原子性,防止多个线程同时对共享资源进行修改或访问,从而避免数据不一致或冲突。然而,互斥锁的使用也会带来一些性能开销,影响最大请求吞吐量,具体影响体现在以下几个方面:
串行执行:互斥锁会导致一部分业务逻辑串行执行,即多个线程需要等待获取锁才能执行关键操作。这降低了并发度,限制了系统处理请求的速度。
竞争与等待:多个线程争夺同一把锁时,会发生竞争。竞争导致了一些线程必须等待锁的释放,这会增加请求的响应时间。
上下文切换开销:由于互斥锁的竞争和等待,操作系统可能会进行线程上下文的切换,从而引入额外的开销。
死锁风险:不当使用互斥锁可能导致死锁,即多个线程相互等待对方释放锁,造成程序无法继续执行。
性能优化解决方案
这个案例有一个明显的特点:在绝大多数情况下,不会出现并发提交相同字段值的情况。因此,在99.9%的情况下,即使没有互斥锁,业务逻辑也是正确的。因此,可以采用手动实现事务机制来优化互斥锁,提升性能。
在这个案例中,互斥锁的核心问题是判断字段不重复和字段插入操作的原子性。因此,可以考虑采用一些优化机制,单独实现这两个操作组合的原子性。需要注意的是,如果被加锁的业务操作还有更复杂的一致性要求,比如数据库写冲突等,那么这种互斥锁实现就不能简单地被优化掉。

我们将“字段不重复检测”、“单个字段插入”和“其他操作”三个操作绑定在一起,实现了一种事务机制,支持在后续操作失败时回滚到前面的操作。原先的Redis互斥锁主要是为了实现“字段不重复检测”和“字段插入操作”的原子性。
通过手动实现事务机制,我们可以将这两个操作放在开始执行,并使用Redis的Pipeline机制保证它们的原子性,避免被其他Redis操作干扰。接下来的操作(用户提交数据时的关键业务操作)成功则提交任务成功,失败则回滚字段插入操作。为了实现事务机制,我们在字段插入时记录插入前的状态和插入后的变更状态,实现了失败后的回滚机制。
曾考虑使用Redis事务或MongoDB事务,但由于一些原因未采纳,例如MongoDB事务需要数据迁移和升级系统MongoDB集群的数据库版本等,而Redis事务的代码实现不够友好。
最重要的原因是它们将字段插入操作的冲突时间延长到了步骤3“其他操作”结束之后,显著增加了事务冲突失败的概率。因此,采用了前述优化后的实现机制,去除了互斥锁,使用户提交记录可以更大程度地并行。优化后的实现方式中,只有Pipeline操作会排队处理,由于单个Pipeline的执行时长在1ms~3ms之间,因此最终表单的最大请求吞吐量从原来的30RPS(每秒请求数)提升到了约300RPS,实现了性能提升超过10倍的目标。
小结:
在高性能分布式系统设计中,同步互斥是关键技术之一。在软件开发中,由于设计或实现不高效,可能导致整个软件系统性能不理想。通过一个实际性能优化案例,我介绍了业务中使用互斥锁可能遇到的性能问题,包括对请求吞吐量的影响以及优化互斥锁来提升系统性能的方法和过程。每个业务系统中同步互斥问题都具有特定的复杂性,学到的是如何分析同步互斥对性能的影响,以及通过优化同步互斥的实现来提升性能。在今天的案例中,采用了先默认成功执行操作,后续出现异常时回滚的机制,这是一种可以在项目优化中应用的方法。
原文作者:二进制跳动;如有侵权,请联系管理员删除。