在如今数据库管理中,应对MySQL中的热点数据更新一直是业内的一大挑战,尤其在秒杀等高并发场景中显得尤为重要。如果处理不当,可能会造成数据库系统崩溃。
针对MySQL层面上如何有效应对高并发的热点数据更新问题,特别是像库存扣减这样的情况,有一些解决方案可供考虑:
- 缓存优化:通过合理利用缓存技术,如Redis等,将热点数据缓存起来,减少直接对数据库的访问压力,提高读取效率。
- 分库分表:可以考虑对热点数据进行分库分表存储,将数据分散存储在不同的数据库实例中,从而降低单一数据库的压力。
- 异步处理:将热点数据的更新操作异步化,例如通过消息队列,将更新请求先暂存起来,然后异步处理,减少直接对数据库的并发访问。
- 乐观锁:使用乐观锁机制,在更新数据时先进行版本号比对,避免多个并发请求同时修改同一条数据,降低数据更新冲突的概率。
- 业务拆分:根据业务特点,将热点数据进行合理拆分,减少对同一份数据的频繁更新操作,从而降低热点集中度。
综上所述,通过以上策略的综合运用,可以有效应对MySQL中高并发热点数据更新的挑战,提升系统的并发处理能力和稳定性。
上述提到的缓存优化、异步处理、乐观锁、悲观锁其实在往期文章中已经有所阐述,详细的可了解文章:
日活3kw的实际库存业务场景中的超卖到底怎么解决的
这一次我们主要聊一聊MySQL热点数据是如何更新的。在实际的电商平台中是如何处理这种棘手的问题的。
方案一
拆分库存,将原本的大库存分解为多个小库存,这样一次扣减操作可以分散到不同的库或表中进行,从而降低锁的粒度,提高并发性。
- 优点:实施简单直接。
- 缺点:可能导致碎片问题,同时库存调控会变得不够便捷。
设计思路如图:
方案二
请求合并策略:将多个库存扣减请求合并为一个请求,以实现批量更新的操作。
- 优点:操作简单,易于实施。
- 缺点:适用于异步场景或在经过详细分析后确定可合并的情况。
方案三
Update转换为Insert:通过直接插入一条占用记录的方式,将更新操作转换为插入操作,然后通过异步统计剩余库存或通过SQL统计流水方式计算剩余库存。
- 优点:避免了Update操作,减少了锁冲突。
- 缺点:插入时控制不当容易导致超卖情况,而且插入后剩余库存统计可能会变得困难。
除了上述三种方案外,让我详细介绍一种在我们公司内部成功应用并在双十一等高并发场景下表现出色的秒杀方案。该方案也是主流互联网公司主流的解决方案。
终极解决方案:MySQL数据库改造
该方案针对于中小型企业并不适用,其一是没必要,毕竟并发峰值并没有那么高,其二就是技术人员的自身实力并不稳定,如果去做可能会有风险。
一项终极解决方案是对MySQL数据库进行改造,主要针对频繁更新或秒杀等高并发业务场景,以显著优化热点行数据的更新操作性能。通过启用热点更新自动检测功能,系统会自动检测是否存在单行的热点更新,然后让大量并发的更新操作排队执行,从而减少大量行锁带来的并发性能下降。
具体来说,他们对MySQL数据库进行了改造,使得针对同一热点行的更新语句在执行层面进行排队。这种排队相比于传统的更新操作排队更轻量级,因为它不需要自旋,也不需要争夺锁。
这一方案的优势在于开发人员无需额外操作,只需开启热点检测即可。然而,缺点在于改造MySQL数据库需要投入一定成本。不过,目前许多云数据库已经开始支持这种功能。
- 腾讯云数据库
- https://cloud.tencent.com/document/product/236/63239
- AWS
- https://docs.aws.amazon.com/zh_cn/systems-manager/latest/userguide/sysman-inventory-cliwalk.html
这种方法的实施可以有效提升对于热点数据的更新操作性能,为处理高并发场景下的业务提供了一种可靠的技术支持。
其实说了这么多解决方案,其实中小企业中的实际业务场景中并不需要考虑的这么多,毕竟不是所有公司都是BAT。我们只需要如果在必要时刻有一定的解决思路即可,无论是什么方案都是在实际库存业务场景中摸索出来的。架构也是一点点演进优化而来,一口是吃不了一个胖子的。
归根结底要知道的事无论是BAT哪家公司还是其他的互联网大厂,最后一道防线主要仍然依赖于MySQL数据库进行库存扣减操作。这种做法主要基于其可靠性考量,避免了像Redis扣减方案中可能出现的数据不一致和少卖等问题。
之所以MySQL数据库在扣减库存方面被广泛采用,主要是因为其稳定性和数据一致性方面的优势。在高并发的秒杀场景下,确保每一笔交易的准确性和可靠性至关重要,因此选择MySQL作为库存扣减的基础工具被认为是一种最为可靠的做法。
我们实际的解决方案:对账系统
我们实际的解决方案其实在上一篇文章中有提到过,最后保证的库存一致性就是通过对帐系统
如何做对账系统
在分布式系统中,尽管我们会采用各种分布式事务方案来确保各个系统之间的一致性,但往往情况并非如人所愿。
特别是现在许多公司都采用最终一致性方案,而最终一致性意味着无论是本地消息表、事务消息还是任务重试,系统之间的调用都存在失败的可能性。
一旦发生失败,就需要一套机制来发现这些不一致性问题,这时候就需要进行数据对账。
一般来说,根据对账的时机,对账可以分为两种类型:离线对账和(准)实时对账。
实时对账一般是准实时的,即无法保证无延迟,但通常可以控制在秒级延迟内。而离线对账则通常是在第二天(D 1)进行核对。
对于分布式系统中的数据一致性和对账问题,准实时对账提供了一种在较短延迟内发现不一致性的机制,而离线对账则更侧重于在第二天对数据进行全面核对。这些对账机制在确保系统运行稳定性和数据一致性方面发挥着重要作用。
在金融和商业领域常见的对账机制中,有两种常用的时间标识:D 1和T 1。 D 1中的D代表自然日,包括工作日和节假日,而 1表示在数据发生后的第二天进行核对。这意味着对账操作会在数据发生后的第二天进行,无论是工作日还是节假日。 而T 1中的T代表交易日,通常指的是工作日,因此T 1表示在数据发生后的下一个工作日进行核对。这种对账方式更加关注数据发生后的下一个工作日进行核对,以确保交易的准确性和一致性。 这两种对账机制在金融和商业领域中扮演着重要角色,帮助确保交易数据的准确性和完整性,同时为业务运营提供了有效的监控和核对手段。
在对账技术实现中,通常主要采用两种方法:编写代码核对和编写SQL核对。
编写代码核对是指查找需要比对的两条记录,然后进行字段比对,发现不一致的情况后进行处理。这种方法通常通过定时任务来实现,定时任务会扫描表格或者远程拉取数据,然后在业务代码中进行核对。虽然这种方法比较通用,无论是数据库、文件还是远程接口都可以进行核对,但缺点是随着数据量的增加,代码核对的时效性会变差,而且代码运行可能会出现失败的情况。特别是当数据量巨大时,可能会面临扫表速度慢、内存不足导致OOM等问题。
因此,一般不推荐采用编写代码的方式进行核对。
相比之下,编写SQL是一种更好的方式。由于数据通常存储在数据库(包括数据仓库或大数据框架)中,可以通过SQL查询来进行核对。以下是一个比较两个系统中金额是否一致的SQL示例:
代码语言:javascript复制SELECT
A.amount AS amount_A,
B.amount AS amount_B
FROM
table_A A
JOIN
table_B B ON A.id = B.id
WHERE
A.date = '2024-03-09'
AND B.date = '2024-03-09'
AND A.amount <> B.amount;
通过编写SQL进行核对可以利用数据库的强大功能和优化能力,提高核对效率和准确性,尤其适用于数据存储在数据库中的情况。
在进行数据核对时,有多种方案可供选择,具体取决于您的需求和系统架构。以下是一些常见的数据核对方案:
- 离线数仓:
- 适用场景:用于离线数据核对。
- 工作流程:每日将需要离线存储的数据同步到数仓,然后在数仓中编写SQL进行数据核对。
- 在线数据库:
- 适用场景:需要更快速响应的在线数据核对。
- 注意事项:在在线库执行SQL进行核对,可以考虑在备库中执行以避免影响真实业务。跨系统核对时可能需要跨库join,但并非所有数据库引擎都支持此功能。
- 准实时数据库:
- 适用场景:数据同步到实时数仓进行核对和实时查询。
- 工作流程:通过监听binlog等方式将数据同步到实时数仓(如AnalyticDB),在该数仓中进行数据核对。同步数据可用于查询和报表生成。
- ETL核对:
- 适用场景:数据提取、清洗、转化和加工过程中进行核对。
- 工作流程:利用ETL工具进行数据核对,可以在数据处理的各个阶段进行核对操作。
- Flink核对:
- 适用场景:实时流处理框架用于数据核对。
- 工作流程:利用Flink等流处理框架进行数据核对,实现实时或近实时的数据核对操作。
根据具体需求和系统架构,您可以选择适合的数据核对方案来确保数据的一致性和准确性。
核对的预警
当通过SQL语句发现数据不一致时,通常有多种处理方式:
- 告警通知开发人员:
- 处理方式:立即发出告警通知给相关开发人员。
- 跟进方式:确保开发人员及时跟进处理问题。
- 人工跟进:确保人工参与处理,以便及时解决潜在的数据一致性问题。
- 延迟核对或二次核对:
- 处理方式:将有问题的数据标记出来,进行延迟核对或二次核对。
- 操作方式:在一定时间后重新核对数据,以确保数据一致性。
- 调整报警规则:
- 屏蔽报警规则:将需要重新核对的数据在报警规则中屏蔽,避免频繁报警。
- 调整阈值:根据情况调整报警阈值,例如设置多次失败后再报警,或调高告警阈值。
通过以上方式,可以实现职责的明确分工:核对负责核对数据,报警负责发出报警通知。确保有效的报警得到及时处理,避免无效报警影响工作效率,同时保证数据一致性和系统稳定性。