热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

同时打包多个场景_“热点”场景你真的能驾驭吗?从事电商的朋友必看!

作者:阿里云数据库P9资深技术专家胡炜做电商业务的朋友一定不会对“热点”这个数据库的使用场景感到陌生,大卖家、热点商品、热点库存等等都会遇到࿰
913e6e947cc8b8d5c08d9c516a1f9f2f.png

作者:阿里云数据库P9资深技术专家胡炜

做电商业务的朋友一定不会对“热点” 这个数据库的使用场景感到陌生,大卖家、热点商品、热点库存等等都会遇到,即使在阿里这样电商业务相对非常成熟的体系中“热点”也困扰了业务非常久, 原因就在于“热点”是一个对于数据库业务不太友好的场景, 粗放的利用数据库来存取“热点”业务一定会遇到问题。

1、前言

在标准的关系型数据库中,由于需要确保事务的ACID, 因此不同的事务在并发更新同一行记录的时候需要完全的串行化。在乐观并发控制的实现中, 并发的多个更新事务只有一个能成功,其他的全部回滚;在悲观并发控制的实现中,每一个更新要等待前一个持有该行的事务提交或者回滚释放了行锁之后才可以进行更新。

常用的开源MySQL就是悲观的加锁并发控制实现。下图是一个典型的热点事务, 一共包含5条事务,其中Q3即是对热点行的更新。

88e2814dcb497e954cb038f775b97973.png

经典热点事务场景

在加锁这样的悲观并发控制实现下,数据库理论上只要每时每刻都有一个事务处于更新这一行的过程,那么总的吞吐量能达到最优,吞吐量为:

541a443bf897411c6e1e298b84dc3b95.png

但是随着并发请求的数量上升, 线程的上下文切换开销以及锁等待、唤醒的开销都会非常明显,因此在大并发下整体吞吐呈明显的下降趋势:

下面是简单的热点更新测试性能表现,即所有事务对同一行进行更新:

23b2564859d1dfd60114137ad7273866.png

第一个朴素的想法是消灭锁等待, 因此在过往的AliSQL 以及 官方MySQL-8.0 中都提供了no_wait的功能, 这相当于将热点场景变成了乐观的并发控制, 当事务发现需要等锁的时候直接回滚。

另一个很朴素的优化思路是控制事务的并发请求量,首先可以通过线程池来限制住数据库内部的并发线程数,假设线程池内部总共有128个工作线程, 那么性能基本就能够稳定图2的128并发的吞吐量上。 再其次, 通过对同一行更新的事务进行排队,也可以减少InnoDB锁等待唤醒的开销。 这种优化可以让吞吐无限接近于1s/trxrt。

RDS三节点企业版提供了另一种思路的解决方案,也就是提供新的思路来达到增加“热点”场景吞吐的目的。

RDS企业三节点的针对热点的主要手段包括:

  • 缩短事务持有锁的时间
  • 组提交

2、缩短事务持有锁的时间

事务的持续时间包括数据库内核中各条SQL执行的时间以及客户端与数据库之间的网络交互时间,根据图1的经典热点事务场景模型, 一个热点事务包括5条SQL语句,以及9次客户端以及数据库之间的网络通信(最后commit 返回客户端前事务已经结束)。

3、select from update

Oracle 有returning语法来通过一条DML完成修改数据和返回数据的目的。三节点企业版支持select from update的语法, 支持将某条记录更新,同时返回查询结果, 具体用法如下:

684cf262f6637a11a8fdb60f5570e4bf.png

有了这个特性, 我们很容易将图1中经典热点模型的Q3 和 Q4 进行合并,节约一次数据库内部执行Query的时间,并且节约两次客户端和数据库的网络通信开销。

4、Commit On Success / Rollback On Fail /Target Affect Row

一个非auto commit的连接如果需要提交一个事务,在通常情况下需要客户端额外给数据库发送一个commit请求, 为了减少这一次客户端和数据库的网络开销,RDS企业三节点提供了Commit On Success / Rollback On Fail / Target Affect Row 的hint 语法。

Commit on success / Rollback on fail 非常容易理解, 即热点行更新操作成功即自动commit事务, 如果更新失败则rollback整个事务。

这里如何定义成功/失败是一个需要理解的概念, 这里引入Target Affect Row的概念,即更新语句实际更新了几条数据, 如果Target Affect Row为1,则更新到了一条数据我们认为更新是成功, 如果更新的where条件没有命中任何记录则认为是失败,这样配合Commit on success / Rollback on fail就能够方便的实现业务的逻辑。需要注意的是这几个hint必须是伴随着热点update 语句使用的。

22e5065b1fdb289f84d22e1526971b3a.png

5、组提交热点事务

通过上一节的缩短事务持有锁的时间,我们能够缩短每个事务的运行时长,从而使得1s/trxrt 尽量增大, 同过这样的方式,我们能将单线程的吞吐增加到接近10000TPS/s的量级, 想让吞吐更进一步则非常困难。RDS企业三节点提供了另外一种组提交的方式,即对并发更新同一行的不同事务打包成一个group, 这个group对这行热点记录做一次合并更新, 这样就能让系统的吞吐再提升好几倍。

为了方便理解这个概念, 举个例子,假设现在同时有10个事务想要更新t1表上id = 3 的记录,这里假设每个事务的更新语句都是:

7f4d6379a1f33b76342dff26bf603051.png

通过组提交的技术,RDS三节点企业版内核可以把这样的更新语句进行内部逻辑合并打包,实际上是将id为3这一行的b值更新为b-10.这样实际上对数据库的存储引擎就进行了一次更新就达到了顺序执行10个事务一样的效果,持有锁的时间可以大大缩短,并且对客户端的用户是透明的。产生的binlog也是和原来十个事务串行是一样的效果。启用组更新需要设置系统的变量:

3d6466d1ac4125a308503e8c98fbe5df.png

组更新的效果可以通过全局的status来观测:

4e39587b8cffe2b5de05ee264e1cf650.png

这里的Group_update_leader_count 代表着热点更新组的数量, Group_update_follower_count代表的是组里的事务数目, 两个值相除就能得到平均每组中事务的数目。这个值越大则组更新合并的效果越好。

6、总结

RDS企业三节点提供的热点更新功能能够将关系数据库在热点记录更新这一个场景的吞吐得到大规模提升, 也是在阿里巴巴内部的场景中有着非常广泛应用的特性。它能缩短每个事务持有锁的时间,也能打包一批事务做合并更新。

675b5b1a97cebae559d3b831580a0428.png

当然组更新有启用的限制, 即需要在更新语句中带上commit_on_success的 hint, 也要确定在where语句中带有主键的等值条件,这样的更新语句数据库才会识别为走热点组更新的语句,并按照组提交的逻辑进行处理,一个组的事务或者全部成功,或者全部回滚, 即如果组中有一个事务的用户发起断开连接回滚事务的操作, 那么这个组中的所有事务都会回滚。

总而言之如果用户对热点场景有诉求,并且需要数据库提供高成功率的吞吐保障,可以对SQL稍微加以设计使用RDS企业三节点的高级热点功能。



推荐阅读
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • Oracle Database 10g许可授予信息及高级功能详解
    本文介绍了Oracle Database 10g许可授予信息及其中的高级功能,包括数据库优化数据包、SQL访问指导、SQL优化指导、SQL优化集和重组对象。同时提供了详细说明,指导用户在Oracle Database 10g中如何使用这些功能。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文由编程笔记小编整理,介绍了PHP中的MySQL函数库及其常用函数,包括mysql_connect、mysql_error、mysql_select_db、mysql_query、mysql_affected_row、mysql_close等。希望对读者有一定的参考价值。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文讨论了在数据库打开和关闭状态下,重新命名或移动数据文件和日志文件的情况。针对性能和维护原因,需要将数据库文件移动到不同的磁盘上或重新分配到新的磁盘上的情况,以及在操作系统级别移动或重命名数据文件但未在数据库层进行重命名导致报错的情况。通过三个方面进行讨论。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 如何在php中将mysql查询结果赋值给变量
    本文介绍了在php中将mysql查询结果赋值给变量的方法,包括从mysql表中查询count(学号)并赋值给一个变量,以及如何将sql中查询单条结果赋值给php页面的一个变量。同时还讨论了php调用mysql查询结果到变量的方法,并提供了示例代码。 ... [详细]
  • Python SQLAlchemy库的使用方法详解
    本文详细介绍了Python中使用SQLAlchemy库的方法。首先对SQLAlchemy进行了简介,包括其定义、适用的数据库类型等。然后讨论了SQLAlchemy提供的两种主要使用模式,即SQL表达式语言和ORM。针对不同的需求,给出了选择哪种模式的建议。最后,介绍了连接数据库的方法,包括创建SQLAlchemy引擎和执行SQL语句的接口。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • 本文介绍了Oracle存储过程的基本语法和写法示例,同时还介绍了已命名的系统异常的产生原因。 ... [详细]
author-avatar
小阳
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有