本文将介绍热点行性能优化功能。

前提条件

PolarDB集群版本需为PolarDB MySQL 5.6且内核小版本需为20200616或以上。

说明 关于如何升级内核小版本请参见Revision version升级

使用限制

在如下情况下,热点行性能优化将不会被使用:

  • 热点行所属的数据表是分区表。
  • 热点行所属的数据表被定义为Trigger。

注意事项

目前热点行优化功能正在灰度中,如需使用,请提交工单联系客服帮助设置。

背景信息

在数据库系统中,某些数据会被频繁地进行增删改查操作,这些数据行称为热点行。当一个事务对一行数据进行更新时,需要对目标数据行加锁,直到事务提交或回滚时才释放。所以,在同一时段内,对于同一个数据行,只有一个事务能够进行更新,其它事务需要等待。可见,对单一热点行的更新请求其实是串行执行的,传统的分库分表策略在性能提升方面并不会有太大帮助。

在电商平台业务中,限购、秒杀是常用的促销手段。在这些场景下,大量对热点行的更新请求在极短时间间隔内到达后台数据库系统,必然造成严重的行锁竞争和等待,影响系统性能。如果一个更新请求等待执行的时间变长,将会对业务层面产生显著负面影响。

在这种情况下,单纯提高计算机硬件配置已经无法满足这样的低延迟需求。为了更好地解决这个问题,PolarDB在数据库内核层进行一些创新性的优化,不但能够自动识别热点行更新请求,而且将一定时间间隔内对同一数据行的更新操作进行分组,不同分组采用流水线的方式并行处理,通过这些优化,极大地提升了系统的性能。

性能优化介绍

  • 串行处理变流水线处理

    为了提升数据库系统的性能,最直接的方法是使用并行处理,但是对同一热点行的更新操作很难做到完全并行,PolarDB创新性地使用了流水线处理方式,最大限度地将热点行更新操作并行化。

    1

    热点行更新操作所使用的SQL语句会用autocommit或者commit_on_success进行标记,优化后的MySQL内核层会自动识别带此类标记的更新操作,在一定的时间间隔内,将收集到的更新操作按照主键或者唯一键进行Hash,对于Hash到同一个桶中的更新操作,会将它们按照到达的先后顺序分组分批地进行处理和提交。

    为了使用流水线方式处理这些更新操作,需要使用两个执行单元对它们进行分组。当第一个分组收集完毕准备提交时,第二个分组立即开始收集更新操作;当第二个分组收集完毕准备提交时,第一个分组已经提交完毕并开始收集新一批的更新操作,两个分组不断切换,并行执行。

    现如今多核心CPU的使用已经非常普遍。这样的流水线式的处理方式能够充分利用硬件资源,提升CPU的使用率,提高数据库系统的并行处理能力,从而最大限度地提升数据库系统的吞吐量。

  • 消除申请行锁时的等待

    为了保证数据的逻辑一致性,对一个数据行进行更新时,首先会对该数据行加锁。如果加锁请求无法立刻满足,则进入等待状态,这样一来,不但增加了处理延迟,而且还会触发死锁检测,导致额外的资源消耗。

    前面提到,我们会按照时间顺序将对同一数据行的更新操作进行分组,组内第一个更新操作为Leader,其读取目标数据行并且加锁,后续更新操作为Follower,对目标数据行加锁时,如果发现Leader已经持有行锁,不需要等待,直接获得行锁。

    通过这个优化,能够减少行锁的加锁次数和时间开销,整个数据库系统的性能有了显著的提升。

  • 减少B-tree索引的遍历

    MySQL是以B-tree索引的方式管理数据的,每次执行查询时,都需要遍历索引才能定位到目标数据行,数据表越大,索引层级越多,遍历时间就越长。

    在前面提到的对更新操作进行分组的机制中,只有每组的Leader遍历索引定位数据行,之后把更新后的数据行缓存(row cache)在内存中,同组的Follower加锁成功后,直接从内存中读取目标数据行,而不需要再次遍历索引。

    这样一来,从整体上减少了索引遍历的次数和时间开销。

使用方法

  • 使用热点行性能优化功能前,您需要对如下参数进行配置:
    参数 说明
    hotspot 热点行性能优化总开关,取值为ON或OFF,默认值为OFF。
    hotspot_for_autocommit Auto-commit模式下的UPDATE语句能否使用热点行性能优化,取值为ON或OFF,默认值为OFF。
    说明 只有当hotspot为ON时,才支持配置该参数。
    hotspot_update_max_wait_time 行数据分组批量更新(即Group update)过程中Leader等待Follow加入该分组的等待时间,单位为微秒(us),默认值为100us。
    hotspot_lock_type 行数据分组批量更新过程中是否使用新类型的行锁,取值为ON或OFF,默认值为OFF。
    说明 该参数打开时,对相同热点行的更新操作申请行锁时不需要等待,从而提升性能。
    说明
    • 热点行性能优化需要依赖bin logging,所以,当bin logging功能处于关闭状态时,试图打开参数hotspot时会失败并报错。
      当bin logging处于关闭状态时,试图使用MySQL [(none)]> set global hotspot=ON;命令打开参数hotspot时会失败,并出现如下报错:
      ERROR 3042 (HY000):
      Variable 'hotspot' cannot be enabled because 'bin logging' is enabled/disabled
    • 当全局bin logging开启,但是会话级别的bin logging关闭时,可以打开参数hotspot,但是执行UPDATE语句时并不会使用热点行性能优化。
    • 当参数rds_ic_reduce_hint_enable处于打开状态时,试图使用MySQL [(none)]> set global hotspot=ON;命令打开参数hotspot时会失败并,出现如下报错:
      ERROR 3042 (HY000): Variable 'hotspot' cannot be enabled because 'rds_ic_reduce_hint_enable' is enabled/disabled
  • 您可以使用如下命令查看参数配置:
    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 QUEUE_ON_PK 1 TARGET_AFFECT_ROW 1 sbtest SET c=c+1 WHERE id = 1
  • 测试使用的工具是Sysbench,测试覆盖了如下场景:
    • 测试场景1:单个热点行加8内核CPU。

      在单热点行加8内核CPU的场景下,引入热点行优化后,库存热点性能在高并发时提升近64倍。

      2
    • 测试场景2:单个热点行加32内核CPU

      在单热点行加32核CPU的场景下,引入热点行优化后,峰值QPS提升了63倍;高并发为8000时,性能提升达46倍。

      2
    • 测试场景3:8个热点行加32核CPU

      在多热点行(8个)加32核CPU的场景下,引入热点行优化后,峰值QPS提升20倍。

      且当高并发达到16000时,在未使用热点行优化功能的情况下,更新操作会导致数据库出现故障无法返回更新操作结果;但使用热点行优化后,更新操作可以正常返回,且QPS维持稳定。

      4