分享

干货!腾讯公司计费业务的 TDSQL

 万皇之皇 2018-01-19

作者介绍bluesea,腾讯金融云专家工程师,从事分布式数据库 TDSQL 研发工作。出版著作:《数据库查询优化器的艺术 原理解析与 SQL 性能优化》、《数据库事务处理的艺术 事务管理与并发控制》,广受好评。同时,bluesea 还是中国人民大学信息学院工程硕士企业导师。

TDSQL 是一个稳定运行了十年之久的分布式数据库,不仅支撑了腾讯公司的计费业务,而且还在微众银行等金融单位的核心业务系统稳定、高效地运行了四年之久。这几年,TDSQL 在技术层面不断进步,研发了很多新特性,诸如多级分区、热点更新、隐含主键、分布式事务等,不仅有力的支撑了事务型的数据库应用,而且在体系结构上也朝 Spanner 架构上迈进,是一个名副其实的 NewSQL 系统。

MySQL/TDSQL 的事务处理技术,主要包括四个方面的内容。其中,核心重点是并发控制技术。

第一,数据异常现象,这里不仅介绍有大家熟知的、SQL 标准规定的三种读数据异常,还有其他的八种异常,会极大扩展大家对数据异常的认识。

第二,MySQL 的事务处理技术,包括 ACID 的各个内容。

第三,MySQL 的并发访问控制技术。并发控制技术是数据库事务处理的核心技术。可以说,没有事务处理,数据库就不能算是数据库;没有并发控制技术,事务处理也只是一个名词而已。毫不夸张地说,并发控制技术是核心技术的核心。

第四,基于对 MySQL 的认识,可以理解主流的数据如 Oracle、Informix

数据异常

首先,我们谈第一个问题:数据异常现象有哪些?

这列出了大家都熟悉的三种读数据异常,分别是脏读、不可重复读、幻读。我们看其中一个,比如说脏读。第一步,T2 事务修改了数据行 row;第二步,T1 事务对同一个数据行 row 读取;第三步,T2 事务回滚。这对于事务 T1 而言,读到的数据是将被回滚的数据,这就是脏读。

有朋友会问,脏读,也没有什么大不了的。试想一下,一个骗子 T2 转帐 1000 元给事务 T1,事务 T1 检查自己的账户,入账了 1000 元,然后事务 T1 把一件衣服卖给了骗子 T2,之后骗子 T2 拿到衣服后回滚了转账 1000 元的操作,然后逃之夭夭了。事务 T1 既没有拿到钱还丢失了衣服,损失很大。所以要避免这样的异常发生。

这三个读异常现象,是大家熟知的,也是 SQL 标准所定义的数据异常现象。那么,除了读异常,还有其他的数据异常吗?

比如说脏写。第一步,事务 T1 修改数据行 row;第二步,事务 T2 也修改数据行 row 并提交,数据修改生效。事务 T2 认为自己的操作是成功的。但不幸的事情发生了,第三步,事务 T1 回滚了,用旧值替换了被事务 T2 写过的值。这意味着事务 T2 存入银行的钱,丢失了,因为帐本上只记着第一步事务 T1 读取的数据值。这就是写数据发生的数据不一致的现象。

那么,除了这些读和写异常,还有其他的数据异常吗?

接下来,我们继续介绍两种写偏序异常:两个事务写偏序和三个事务写偏序。

我们来看一下两个事务写偏序。首先,这里有个前提:医院向社会承诺,至少有一名医生对外提供电话咨询服务。但是,如果有多于两个医生在提供电话咨询,则需要某个正在进行电话咨询服务的医生停止服务。

可是,大家看这两个事务。事务 T1 发现,有两个以上的医生正在提供电话咨询,就请 Alice 停止电话服务;事务 T2 也发现有两个以上的医生正在提供电话咨询,就请 Bob 停止了电话服务。这样,如果执行前只有 Alice 和 Bob 正在提供电话服务,这两个事务执行完毕后,没有一个医生在对外提供电话咨询服务了。这就违背了“至少有一名医生对外提供电话咨询服务”的约束前提。这样的现象,也是一种数据异常现象。

到现在为止,我们介绍了七种数据异常现象了。

这里,还例举了四种数据异常,大家如果感兴趣,可以翻阅《数据库事务处理的艺术》一书。

我们一共提及了 11 种数据异常现象,有读操作造成的三种读异常,也有写操作造成的两种写异常,还有写操作涉及的两种写偏序异常等等。

对于数据库系统而言,如果允许上面所说的数据不一致异常发生,我们这个依靠数据库做交易的世界就会发生巨大混乱,数据库在,账面乱了。人活着,钱没了。

那么,数据异常现象,是怎么产生的呢?

刚才谈到的三种读异常,有个一个共同点,就是存在并发的事务,这是第一个原因。刚才所谈的四种读写组合,就是并发造成的。

第二,并发的事务,操作的是同一个数据对象。

第三,并发的事务对同一个数据对象,进行的总是读写或写读或写写这三种,没有读读。这就是上一个页面里用黄色标识的存在数据异常的三种情况。

第四,还有一种特殊情况,对于幻读而言,受谓词条件的影响,这时不是操作物理上的同一个已经存在的对象,而是操作谓词限定的同一个范围内的逻辑意义上的对象。我们把第四种情况概括为“谓词的语义”。

这些合起来,造成了三种读数据异常。

接下来,我们来分析一下写偏序异常。

第一,存在并发的事务。

第二,并发的事务,操作的不是同一个数据对象。这点和刚才的读异常不同。

第三,并发的事务对不同的数据对象,进行的总是读写或写读或写写这三种,没有读读并发。

第四, 操作结果,违反了“语义前提”。

请看第四点,操作数据时,需要遵守一个语义前提,即“至少有一名医生对外提供电话咨询服务”,但是并发操作打破了这个语义前提,出现了没有医生提供咨询的异常现象。

在数据库里,数据操作会被抽象为两种,就是读操作和写操作。

读写操作组合在一起,有四种情况,就是这幅图里面的,读读、读写、写读和写写。

在数据库里面,只有读读操作,不会引发数据异常,而其他三种,都会引发数据异常。这样的总结,算是一个数据异常发生的原因,但是还不是很准确。

接下来,我们谈第二个话题:MySQL 的事务处理技术。主要包括事务锁和系统锁,以及事务的 ACID 四大特性。

MySQL/TDSQL 数据库事务处理技术概述

系统锁是事务锁实现的物理基础,事务锁在系统锁的基础上,增加了事务相关的语义。

在事务锁中,又要分为两部分,一个是元数据锁,如 DDL 操作施加的事务锁。另外一个是我们在谈及数据库时,常常提及的锁,其实是用户数据上的事务锁。前者虽然在数据库引擎中存在,但常常被人忽略,因为多数用户关心的是用户数据部分。

这幅图用蓝线分为两部分,上面是元数据锁,下面是用户数据锁,他们都是事务锁。这幅图中画出了 MySQL 的重要的内部数据结构和他们之间的关系,大家可以按图索骥,据此深入了解 MySQL 内核实现事务锁的相关技术。

在事务锁中,所有技术的核心秘密,都在这张表里面。

例如,前面我们谈到脏读,我们看在 MySQL 中是怎么避免的。

Granted Mode,表示第一个事务中已经授予的锁,而 Requested Mode 表示并发的第二个事务,第二个事务请求授予新的锁如表所示。对于脏读,第一个事务已经授予 X 锁即写锁,此时第二个事务申请 S 锁即读锁,其对应的单元中是空的表示不能授予,这样第二个事务就被迟滞不能继续执行,于是就避免了脏读现象。

大家可以对应这张表,也许会考虑不可重复读的数据异常是怎么避免的?此时,很有可能会觉得下面这张表是错误的。

但是,MySQL 因为又使用了 MVCC 技术实现了 RR 即可重复读隔离级别,所以 RR 的处理方式又有所不同,但这不是表明下面这张表是错误的。这一点,后面会再提及。

数据库的事务处理技术,实现 ACID 四大特性,通常使用的技术,用下面这幅脑图可以很好的概括。

其中,一致性是目的,原子性和持久性是手段,而隔离性是在数据正确或部分正确的基础上为提高数据库性能而提出的特性。

MySQL 的并发访问控制技术

接下来,我们谈第三个话题:MySQL 的并发访问控制技术。并发访问控制技术是数据核心技术的核心,也是数据库中最难的技术。主要包括事务模型、ACID 四大特性之间的关系、C 和 I 特性的实现技术。

数据库的事务管理器,本质上就是一个有限状态自动机,MySQL 的事务处理模块也不另外,事务在各个状态之间进行流转和切换。

总结 MySQL 的事务处理技术,主要包括如下几个方面。

SS2PL 和 MVCC 都是并发访问控制技术。对于并发访问控制技术,可以依据下图理解,在数据库引擎内部,需要先在保证正确性的基础上,再来提供高的性能。

前面,介绍过通过封锁并发访问控制技术怎么避免脏读,现在,再分析一下 MySQL、InnoDB 是怎么解决幻象数据异常的。示例如图:

MySQL 对于其他隔离级别的实现,也就是怎么避免其他数据异常现象,可以参考如下图和图中所附的链接,详情在链接中供深入阅读参考。

p 序列化隔离级别:http_://blog.163.com/lihx/blog/static/1839914132017398565727/

p 可重复读:_http://blog.163.com/lihx/blog/static/1839914132017224904641/?suggestedreading&wumii

p 读已提交:_http://blog.163.com/lihx/blog/static/18399141320172198225727/?suggestedreading&wumii

p 读未提交:_http://blog.163.com/lihx/blog/static/18399141320172113321444/?_suggestedreading&wumii_

主流数据库事务处理技术

接下来我们谈第四个话题:主流数据库的事务处理技术。

可以看这张对比表格,概括了 Informix、Oracle、PostgreSQL 和 MySQL 这四个数据库的并发控制技术。

主流的数据库,几乎都使用了封锁技术和 MVCC 技术。只有 Infomix 单纯地使用了封锁技术。

Oracle 尽管语法上提供了序列化隔离级别的设置,但没有提供真正的序列化隔离级别。这是因为 Oracle 经常会清理掉商在活跃的事务所需要的旧数据(以多版本形式存在的旧数据)。

反倒是开源的两个数据库系统,PostgreSQL 和 MySQL 实现了序列化。只是 MySQL 是在读数据时加锁结合 SS2PL 技术实现了序列化,这种方式的并发度很低,性能不好。而 PostgreSQL 则使用 SSI 技术实现了序列化,性能相对较好。

在第一个问题中我们提出了两种写偏序的数据异常,PostgreSQL 使用 SSI 技术,解决了写偏序异常。

如果从正确性和性能这两个角度来衡量数据库的并发控制技术,显然,PostgreSQL 在理论上优于 MySQL,PostgreSQL 采用的 SSI 技术复杂但高效。

这幅图详细对比 PostgreSQL 和 MySQL 的并发控制技术。

我们从系统锁、事务锁、事务锁的元数据锁和记录元组锁的角度进行对比,然后再从隔离级别的角度来看这两个数据库的并发控制技术。

首先,PostgreSQL 和 MySQL 都提供了系统锁,也都尽量利用了底层的硬件指令如 TAS 指令实现最基本的 spinlock。使用操作系统提供的 mutex 来控制共享资源的并发操作。

其次,在事务锁方面,PostgreSQL 统一管理元数据和用户数据,而 MySQL 则明显把元数据和用户数据分开用元数据锁和记录锁进行管理,并各自进行了死锁检测。

PostgreSQL 对于元组上的并发操作,加元组锁到元组上,把事务 ID 记录在元组头上,用快照技术判断元组的可见性,操作结束则释放锁。而 MySQL 则是用内存锁表记录元组锁,等到事务结束后才释放。从这点上看,SS2PL 技术的实现,在 PostgreSQL 和 MySQL 中是不同的。

从隔离级别的角度看,PostgreSQL 和 MySQL 都采用了 MVCC 技术来实现可重复读和读已提交。

PostgreSQL 和 MySQL 在并发控制技术方面最大的差别,在于对确保数据一致性的序列化的实现上,采取的技术不同,理论上性能不同。这就是两者在并发控制技术方面的最大不同之处。

TEG 计费平台部研发的 TDSQL,是基于 MySQL 的分布式数据库,但 TDSQL 的做了大量的研发工作,TDSQL 的技术一直在进步,分布式事务作为数据库里最难的问题,正在被 TDSQL 逐步攻克。过去的一年多,TDSQL 实现了分布式事务的写数据强一致,其原理如下:

在一个全局的事务调度器上,对于多个 SET 即跨 SET 的分布式事务,TDSQL 实现了 SS2PL 技术确保了数据的强一致性,实现 2PC 技术保证了分布式环境下事务的提交的原子性和一致性,把 2PC 嵌入到 SS2PL 整体架构中,实现了分布式数据库事务模型。Spanner 等主流分布式数据库在分布式事务处理机制上与 TDSQL 相似。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多