热点行是指在数据库中那些会被频繁执行修改操作的数据行。高并发场景下对热点行的更新会造成严重的行锁竞争与等待,影响系统性能。因此PolarDB针对此场景在数据库内核层进行了创新性的优化,极大地提升了系统性能。
背景信息
热点行面临以下问题:
当一个事务对一行数据进行更新时,会对目标数据行加锁,直到事务提交或回滚时才释放。在同一时段内,针对同一数据行,只有一个事务能够进行更新,而其他事务则需要等待。由此可见,对于单一热点行的更新请求实际上是串行执行的,传统的分库分表策略在性能提升方面并不会有太大帮助。
在电商平台业务中,限购、秒杀是常用的促销手段。在这些场景下,大量对热点行的更新请求在极短时间间隔内到达后台数据库系统,必然造成严重的行锁竞争和等待,影响系统性能。如果一个更新请求等待执行的时间变长,将会对业务层面产生显著负面影响。
针对上述问题,单纯提高计算机硬件配置已经无法满足这样的低延迟需求。因此PolarDB在数据库内核层进行了创新性的优化,不但能够自动识别热点行更新请求,而且将一定时间间隔内对同一数据行的更新操作进行分组,不同分组采用流水线的方式并行处理,通过这些优化,极大地提升了系统的性能。
技术方案
串行处理变流水线处理
为了提升数据库系统的性能,最直接的方法是使用并行处理,但是对同一热点行的更新操作很难做到完全并行。PolarDB创新性地使用了流水线处理方式,最大限度地将热点行更新操作并行化。
热点行更新操作所使用的SQL语句会用
autocommit
或者COMMIT_ON_SUCCESS进行标记。优化后的MySQL内核层会自动识别带此类标记的更新操作,在一定的时间间隔内,将收集到的更新操作按照主键或者唯一键进行Hash
,对于Hash
到同一个桶中的更新操作,会将它们按照到达的先后顺序分组分批地进行处理和提交。为了使用流水线方式处理这些更新操作,需要使用两个执行单元对它们进行分组。当第一个分组收集完毕准备提交时,第二个分组立即开始收集更新操作。当第二个分组收集完毕准备提交时,第一个分组已经提交完毕并开始收集新一批的更新操作,两个分组不断切换,并行执行。
现如今多核CPU的使用已经非常普遍。这样的流水线式的处理方式能够充分利用硬件资源,提升CPU的使用率和数据库系统的并行处理能力,从而最大限度地提升数据库系统的吞吐量。
消除申请行锁时的等待
为了保证数据的逻辑一致性,对一个数据行进行更新时,首先会对该数据行加锁。如果加锁请求无法立刻满足,则进入等待状态。这样一来,不但增加了处理延迟,还会触发死锁检测,导致额外的资源消耗。
前面提到,我们会按照时间顺序将对同一数据行的更新操作进行分组。组内第一个更新操作为Leader,其读取目标数据行并且加锁。后续更新操作为Follower,其对目标数据行加锁时,如果发现Leader已经持有行锁,无需等待,直接获得行锁。
通过这个优化,能够减少行锁的加锁次数和时间开销,整个数据库系统的性能显著提升。
减少B-tree索引的遍历
MySQL是以B-tree索引的方式管理数据的。每次执行查询时,都需要遍历索引才能定位到目标数据行,数据表越大,索引层级越多,遍历时间就越长。
在前面提到的对更新操作进行分组的机制中,只有每组的Leader遍历索引定位数据行,之后把更新后的数据行缓存(Row Cache)在内存中。同组的Follower加锁成功后,直接从内存中读取目标数据行,不需要再次遍历索引。
这样一来,从整体上减少了索引遍历的次数和时间开销。
前提条件
PolarDB集群数据库引擎需为以下版本之一:
MySQL 5.6,且内核小版本需为20200601及以上版本。
MySQL 5.7,且内核小版本需为5.7.1.0.17及以上版本。
MySQL 8.0,且内核小版本需为8.0.1.1.10及以上版本。
PolarDB MySQL版集群已开启Binlog。
集群参数rds_ic_reduce_hint_enable处于关闭状态。
关于如何升级内核小版本,请参见版本管理。
如何修改集群参数,请参见设置集群参数和节点参数。
集群参数在PolarDB控制台上都已加上MySQL配置文件的兼容性前缀loose_。如果您需要在PolarDB控制台修改rds_ic_reduce_hint_enable参数,请选择带loose_前缀的参数(即loose_rds_ic_reduce_hint_enable)进行修改。
使用限制
在以下场景中,热点行性能优化将不会被使用:
热点行所属的数据表是分区表。
热点行所属的数据表上定义了触发器(Trigger)。
热点行使用了Statement Queue机制。
在全局Binlog开启的情况下,若会话级别的Binlog关闭,执行
UPDATE
语句将不会使用热点行性能优化。
使用说明
开启热点行性能优化功能。
您可以在PolarDB控制台上修改以下参数,以开启或关闭热点行性能优化功能。
参数
说明
hotspot
热点行性能优化功能总开关。取值范围如下:
ON:开启。
OFF(默认):关闭。
说明如何修改集群参数,请参见设置集群参数和节点参数。
集群参数在PolarDB控制台上都已加上MySQL配置文件的兼容性前缀loose_。如果您需要在PolarDB控制台修改hotspot参数,请选择带loose_前缀的参数(即loose_hotspot)进行修改。
使用Hint语法来使用热点行性能优化功能。
Hint
是否必选
说明
必选
更新成功时提交。
可选
更新失败时回滚。
可选
显式指定该请求只会更新一行,若不符合则更新失败。
说明由于Hint语法生效会自动提交事务,因此Hint需要位于事务的最后一条SQL语句。
示例:更新
sbtest
表中c
列的数值。UPDATE /*+ COMMIT_ON_SUCCESS ROLLBACK_ON_FAIL TARGET_AFFECT_ROW(1) */ sbtest SET c = c + 1 WHERE id = 1;
相关操作
自定义参数配置
PolarDB控制台不支持对以下参数进行修改。如果您需要进行修改,请前往配额中心,在配额名称为PolarDB热点行参数调整的操作列,单击申请。
参数 | 说明 |
hotspot_for_autocommit |
|
hotspot_update_max_wait_time | 行数据分组批量更新(Group Update)过程中Leader等待Follower加入该分组的等待时间。
|
hotspot_lock_type | 行数据分组批量更新(Group Update)过程中是否使用新类型的行锁。取值范围如下:
说明
|
查看参数配置
您可以使用如下命令查看热点行性能优化功能的参数配置。
SHOW variables LIKE "hotspot%";
返回结果示例:
+------------------------------+-------+
|Variable_name | Value |
+------------------------------+-------+
|hotspot | OFF |
|hotspot_for_autocommit | OFF |
|hotspot_lock_type | OFF |
|hotspot_update_max_wait_time | 100 |
+------------------------------+-------+
查看使用情况
您可以使用如下命令查看热点行性能优化功能的使用情况。
SHOW GLOBAL status LIKE 'Group_update%';
性能测试
测试所需的数据表定义和测试语句如下:
数据表定义
CREATE TABLE sbtest (id INT UNSIGNED NOT NULL, c BIGINT UNSIGNED NOT NULL, PRIMARY KEY (id));
测试语句
UPDATE /*+ COMMIT_ON_SUCCESS ROLLBACK_ON_FAIL TARGET_AFFECT_ROW(1) */ sbtest SET c = c + 1 WHERE id = 1;
测试工具:Sysbench。
测试场景和测试结果。
测试场景1:单个热点行加8核CPU。
测试结果:在单热点行加8核CPU的场景下,引入热点行性能优化后,库存热点性能在高并发时提升近64倍。
测试场景2:单个热点行加32核CPU。
测试结果:在单热点行加32核CPU的场景下,引入热点行性能优化后,峰值QPS提升了63倍。高并发为8000时,性能提升了46倍。
测试场景3:8个热点行加32核CPU 。
测试结果:在多热点行(8个)加32核CPU的场景下,引入热点行性能优化后,峰值QPS提升了20倍。
且当高并发达到16000时,在未使用热点行性能优化功能的情况下,更新操作会导致数据库出现故障无法返回更新操作结果。但使用热点行性能优化后,更新操作可以正常返回,且QPS维持稳定。