热点行更新
数据库中频繁被增删改查的记录被称为热点行。热点行出现的场景包括秒杀抢购、演唱会门票预订、热门路线火车票预定等等。由于事务对数据更新时,需要持有行锁,同一时刻内只能有一个事务更新热点行,其他事务只能等待行锁释放后继续执行,热点行更新的性能存在瓶颈,并且传统的分库分表策略在性能提升方面并不会有太大帮助。
云数据库 GaussDB(for MySQL)支持热点行更新优化,您可以通过手动指定或者自动识别的方式开启热点行更新。热点行更新开启后可以大幅度提升热点行的更新性能。
原理介绍
GaussDB(for MySQL)热点行更新的架构如下图所示:分为Counter_hash,Group_hash两部分。其中Counter_hash主要用于实现热点行的自动判断。Group_hash是热点行的实际实现部分,由多个Hotspot group组成。每个Hotspot group对应一个热点行,每个Hotspot group由多个batch组成,交替为热点行提供批量提交服务。
约束与限制
- GaussDB(for MySQL)实例的内核版本为2.0.54.240600及以上时支持使用该功能。
- 功能使用约束如下:
- where条件中只能使用主键或唯一索引的等值匹配,并且只能更新单条记录。否则将绕过优化正常更新。
- 不允许修改索引列,否则将绕过优化正常更新。
- 只对修改列为整数的更新生效,否则将绕过优化正常更新。
- 只允许对热点行记录进行两个元素的加减操作,且第一个元素与等号左侧相等并满足唯一索引等约束,不允许赋值操作。假设c列为待修改列,d为记录的普通列,那么只允许进行类似c=c+1,或者c=c-1的操作,不允许进行c=d+1,c=1+c,c=c+1+1,c=1+c+1等操作。否则将绕过优化正常更新。
- 只允许对隐式事务生效。即要求AUTOCOMMIT为ON,并且不在BEGIN,COMMIT显示开启的事务中使用。否则将绕过优化正常更新。
- 需要使用HOTSPOT显式标记热点行更新事务,或者将rds_hotspot_auto_detection_threshold设置为非0,开启热点行更新自动识别功能。否则将绕过优化正常更新。rds_hotspot_auto_detection_threshold的详细用法请见参数说明。
- 只对RC级别生效。数据库处于其他隔离级别时将绕过优化正常更新。
- 无法在stored function, trigger以及event中使用,否则将对客户端报如下错误:
HOTSPOT hints can not be used in stored function, trigger or event
- 行为变更: 一个hotspot事务组内,除了执行失败或者在更新阶段killed的事务外,其他事务被按批次集中提交,集中记录redo log和undo log,只能集中提交或者回滚,无法单独回滚。每个批次提交的事务个数为几十到几百个不等。
参数说明
参数名称 |
参数说明 |
---|---|
rds_hotspot |
热点行更新优化开关。将其设置为ON将启用热点行更新优化。 |
rds_hotspot_follower_wait_commit_interval |
热点行更新follower事务等待leader事务日志持久化时,进入阻塞前的睡眠时间。单位:微秒。对日志持久化速度慢的实例,建议调大。对于持久化快速的实例,建议设置为0,不休眠直接阻塞。 |
rds_hotspot_leader_wait_follower_interval |
热点行更新leader事务等待follower更新记录的时间单位。单位:微秒。低并发适当调低可以避免性能下降。高并发适当调高可以提升性能。当QPS超过20w时,建议将该值设置为100或者更大。 |
rds_hotspot_auto_detection_threshold |
热点行更新的自动识别功能开关。设置为0表示不启用自动识别功能。设置为非0表示热点行更新的识别阈值。当某个符合热点行要求的行每秒更新次数超过阈值时将启动热点行更新功能。 |
rds_hotspot_batch_size_lower_limit |
每批热点事务大小的建议最小值。每个batch尽可能达到该大小。但是,这并不是严格保证的。当leader发现所有需要等待的follower都已经到达时,batch就进入提交状态。 |
rds_hotspot_max_memory_size |
热点行更新中group和counter占用的内存上限。当group占用的内存超过限制时,将清空group所占用的内存。当counter占用的内存超过限制时,将清空counter所占用的内存。申请新的内存时才会尝试清空旧内存。 |
rds_hotspot_enable_time_statistics |
是否开启热点行更新的时间相关的状态统计功能。将其设置为ON以启用该功能。 |
状态说明
状态 |
说明 |
---|---|
Hotspot_total_trx |
使用hotspot总事务数 |
Hotspot_update_errors |
更新阶段出错的热点行更新事务,这些出错的事务只会自己更新失败,不会影响其他热点行更新事务的提交。 |
Hotspot_trx_rollbacked |
更新成功,但是由于最终回滚的热点行更新事务数量。当队长(leader)决定回滚时,所有组员(follower)跟着一起回滚。 |
Hotspot_trx_committed |
提交成功的热点行更新事务数量。 |
Hotspot_batch_size |
热点行更新事务分批次提交。该值表示当前批次热点行更新事务的数量。 |
Hotspot_batch_wait_time |
热点行更新按批次持有锁和提交事务。此时间为当前热点行更新批次等待上一批次释放锁的时间,单位微秒。 |
Hotspot_leader_wait_follower_time |
在一个批次中leader需要等待follower完成记录更新,此时间为当前批次leader等待follower的时间,单位微秒。 |
Hotspot_leader_total_time |
当前批次leader的热点行更新事务总时间,单位微秒。 |
Hotspot_follower_total_time |
当前批次某一个follower的热点行更新事务总时间,单位微秒。 |
Hotspot_follower_wait_commit_time |
在一个批次中follower需要等待leader持久化日志,此时间为当前批次某一个follower等待leader持久化日志的时间,单位微秒。 |
Hotspot_group_counts |
每个热点行更新对应一个组,组内事务分批次提交。该值为使用热点行更新的组数。 |
Hotspot_counter_counts |
counter用于自动判断热点行更新。当counter中的统计值满足要求时,将会创建group使用热点行更新。该值为counter的总数。 |
新增关键字
新增标记语句的关键字如下:
关键字 |
描述 |
---|---|
HOTSPOT |
表示开启热点更新功能。 |
NOT_MORE_THAN |
可选项。表示目标值不大于某值。 |
NOT_LESS_THAN |
可选项。表示目标值不小于某值。 |
上述关键字放置在SQL语句末尾。HOTSPOT必须在最前面,NOT_MORE_THAN和NOT_LESS_THAN没有位置前后的要求。
例如:假设id是主键列,c是int类型列,那么支持以下语法:
UPDATE c=c+1 where id=10 HOTSPOT; UPDATE c=c+1 where id=10 HOTSPOT NOT_MORE_THAN 100; // c值不大于100 UPDATE c=c-1 where id=10 HOTSPOT NOT_LESS_THAN 0; // c值不小于0 UPDATE c=c+1 where id=10 HOTSPOT NOT_MORE_THAN 100 NOT_LESS_THAN 0; // c值不大于100,不小于0 UPDATE c=c+1 where id=10 HOTSPOT NOT_LESS_THAN 0 NOT_MORE_THAN 100; // c值不大于100,不小于0
当超过NOT_MORE_THAN或者NOT_LESS_THAN的限制时,会向客户端报如下错误:
HOTSPOT field value exceeds limit
使用示例
- 创建表,准备数据。
CREATE TABLE test.hotspot1 ( `id` int NOT NULL primary key, `c` int NOT NULL DEFAULT '0' ) ENGINE=InnoDB; INSERT INTO test.hotspot1 VALUES (1, 1);
- 打开热点行更新开关。
SET GLOBAL rds_hotspot = ON;
- 修改隔离级别,AUTOCOMMIT。
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; SET SESSION AUTOCOMMIT = ON;
- 发起带HOTSPOT关键字的更新。
UPDATE test.hotspot1 SET c=c+1 WHERE id=1 HOTSPOT;
- 检查热点行更新状态。
SHOW STATUS like "%hotspot%";
性能测试
- 测试环境
ECS规格:32U64GB
测试环境:华北-北京四
测试工具:sysbench-1.0.18
数据模型:
- 1张表,1条数据。
- 8张表,每张表1条数据。
- 参数配置
transaction_isolation=READ-COMMITTED
max_prepared_stmt_count=1048576
rds_global_sql_log_bin=OFF
- 测试方法
CREATE TABLE sbtest (id int NOT NULL AUTO_INCREMENT,k int NOT NULL DEFAULT '0',PRIMARY KEY (id));
测试语句:
UPDATE sbtest%u SET k=k+1 WHERE id=1 hotspot;
- 测试场景和测试结果
测试结果:所有并发均有不同程度提升,64并发及以下并发提升不明显,128并发及以上并发提升明显,最高提升9.26倍。
测试场景2:32U128GB实例单个热点行更新
测试结果:128并发及以上并发提升明显,最高提升639倍。
测试场景3:32U 128GB实例8个热点行更新
测试结果:256及以下并发无提升,512及以上并发提升效果明显,最高提升78倍。