欢迎你们前往腾讯云技术社区,获取更多腾讯海量技术实践干货哦~
算法
近日,腾讯云发布了分布式数据库解决方案(DCDB),其最明显的特性之一就是提供了高于开源分布式事务XA的性能。大型业务系统有着用户多、并发高的特色,在这方面,集中式数据库(单机数据库)的性能很难支持,所以主流的互联网公司每每采用分布式(架构)数据库,物理上利用更多的低端设备,逻辑上对大表水平拆分支撑业务的须要。sql
虽然分布式数据库能解决性能难题,但事务一致性(Consistency)的问题,却很难在分布式数据库上获得解决。数据库
众所周知,一个事务所作的更新,分布式数据库系统内部多个独立的数据节点完成(每一个节点的本地事务是这个全局事务的一个事务分支),在这样一个全局事务提交期间,有可能某些事务分支没法成功提交。后端
针对这一问题,虽然业内早已存在理论解决方案——二阶段提交协议(简称2PC),并延伸出分布式事务(简称XA)的解决方案。但业内却少有工程化实现且大规模应用的案例。而腾讯云分布式数据库DCDB,却已在内部业务中应用多年。安全
(图:二阶段提交算法)bash
目前DCDB已应用在腾讯内部90%以上的交易、计费业务,而且三一重工(树根互联)、汇通天下(G7)、阅文集团(起点/创世中文网等)、微众银行、和泰人寿、威富通等都在该产品。网络
腾讯云分布式数据库DCDB,是基于腾讯金融级数据库(公司内部代号TDSQL)云化改造而来的兼容MySQL协议的分布式数据库。现现在,腾讯云DCDB已经正式在MySQL 5.7(percona分支)协议上支持分布式事务XA,并已在腾讯云公有云、金融云发布供开发者使用。开发者能够经过申请DCDB实例,并在初始化后,链接实例运行以下sql进行初始化:架构
MySQL> xa init;并发
Query OK, 0 rows affected (0.03 sec)
注意:初始化xa前,请开启强同步复制能力,另外该sql会建立xa.gtid_log_t,用户在后续使用中万勿对其进行任何操做。运维
为更好的支持分布式事务,DCDB还新增了SQL命令:
1)SELECT gtid(),获取当前分布式事务的gtid(事务的全局惟一性标识),若是该事务不是分布式事务则返回空;
gtid的格式:
‘网关id’-‘网关随机值’-‘序列号’-‘时间戳’-‘分区号’,例如 c46535fe-b6-dd-595db6b8-252)SELECT gtid_state(“gtid”),获取“gtid”的状态,可能的结果有:
a)“COMMIT”,标识该事务已经或者最终会被提交
b)“ABORT”,标识该事务最终会被回滚
c) 空,因为事务的状态会在一个小时以后清楚,所以有如下两种可能:
1) 一个小时以后查询,标识事务状态已经清除
2) 一个小时之内查询,标识事务最终会被回滚3) 运维命令:
xa recover:向后端SET发送xa recover命令,并进行汇总
xa lockwait:显示当前分布式事务的等待关系(可使用dot命令将输出转化为等待关系图)
xa show:当前网关上正在运行的分布式事务
以Python为例,能够对转帐业务进行以下编码:
db = pyMySQL.connect(host=testHost,
port=testPort, user=testUser, password=testPassword, database=testDatabase)
cursor = db.cursor()
try:
cursor.execute("begin")
#为一个帐户Bob的余额减1
query = "update t_user_balance SET balance = balance - 1 where user='Bob' and balance>1) affected = cursor.execute(query) if affected == 0: #余额不足,回滚事务 cursor.execute("rollback") return #为一个帐户John的余额加1 query = "update t_user_balance SET balance = balance + 1 where user='John')
cursor.execute(query)
#为了安全起见,建议在这里执行‘SELECT gtid()’获取当前事务的id值,便于后续跟踪事务的执行状况
#提交事务
cursor.execute("commit")
except pyMySQL.err.MySQLError as e:
#发生故障,回滚事务
cursor.execute("rollback")
复制代码
分布式事务的好处在于会大大下降应用开发难度,由于在某些不支持XA的数据库中,须要业务系统经过特殊而且巧妙的设计,而非利用数据库来解决事务中数据不一致等问题。这种对应用开发者的技术水平要求很高,越是复杂的业务系统,越会增长开发成本和技术门槛,这是业内大多数开发者面对分布式数据库时,只能望而却步的主要缘由。
一、DCDB架构介绍
腾讯云DCDB整个集群架构简图以下图,MySQL采用主从节点配置(也叫做主备)一套主从节点叫作SET,在每个SET外配置网关(TProxy),造成一个物理分片(Shard)。
DCDB后端是MySQL(或其分支版本)数据库,目前腾讯云公有云发布支持XA的版本是基于MySQL 5.7.17(percona分支)。
二、网关(TProxy)与XA
网关是用于接收请求并与后端MySQL创建链接的网络模块。网关能够用两种模式工做,一种称为noshard,此模式下网关不处理/不解析SQL语句,透明转发请求和应答。另外一种模式称为shard(分布式,即支持自动水平分表)模式下,TProxy会解析SQL并转发到不一样的数据分片。
在实现XA以前,网关不容许在一个事务中向多个SET发送DML语句。由于未实现二阶段提交(2PC)时,事务采用一阶段提交,若是分布式中某一个SET提交失败了或回滚了,那么这个分布式事务就处于不一致的状态。
(网关的工做方式)
二阶段提交中须要的事务管理器(TM)。为了解决容灾、简化架构,腾讯云DCDB将TM实如今TProxy中,而DCDB的网关是一个无状态的模块,经过这一架构,DCDB XA能够支持:
(1)、分布式事务对业务透明,兼容单机事务语法(start transaction/commit/rollback/savepoint);
(2)、每一个网关均可以独立接受和处理事务请求,且无需与其余网关进行协调节点故障不丢失事务;
(3)、容许显式事务中多条语句分别发给多个分片;
(4)、网关无需持久状态,无需容灾,能够随时经由调度集群退出或加入集群,且性能能够扩展;
(5)、支持autocommit下单条语句写访问多个分片等。
DCDB网关还容许以流式处理方式运行group by、order by,流式处理让这类操做变得很是方式很是高效;网关还支持两个Shard使用shardkey(分表键)作等值链接,以及使用shardkey的子查询。
将来,腾讯云还计划支持分布式JOIN、Sparksql、二级分区等高级功能,兼容更多MySQL高级语法。
三、强同步与XA
因为腾讯云DCDB默认采用强同步复制,即主从节点数据彻底一致,所以XA事务也遵循强同步的逻辑,即需等待从机确认数据同步后,才给业务以应答(commit)。基于强同步,在如下两种异常状况下,DCDB XA可轻松应对。
(1)、主节点故障时,已确认事务数据不会丢失:主节点故障那么拥有最新数据和binlog的从机就被选为主节点,这其中的数据也包括全部已经向用户确认完成提交的事务的数据。
(2)、原主节点恢复后从新加入集群,未确认事务自动闪回:原主节点恢复从新接入集群,它将做为从机运行,此时他可能存留多余的已提交事务(此时事务并未获得强同步同步确认,即原备机并无相关数据),那么这些事务会被闪回。虽然这些事务可能已经在原主节点的MySQL内部完成提交,但因为强同步机制,他并不会向客户端返回commit语句,这意味着仍被视为一个未完成的事务。所以,这些事务的闪回了也并无破坏数据库的ACID属性。这里值得说的是,闪回flashback是基于binlog生成作逆操做,它与数据库回滚并不一样rollback,闪回能够作DDL操做。
腾讯云DCDB的强同步为腾讯金融级数据库自研的一项能力,性能比官方半同步大幅提升,几乎等于异步复制性能,腾讯云DCDB在腾讯内部应用多年,未发生过一块儿由于主从切换、故障带来的数据偏差。并且,从性能上,也撑住了腾讯公司各种大型运营活动如红包、各种游戏大型推广等海量并发,其主要缘由是强同步采用异步提交/等待方式,且不占用数据库工做线程。
四、并发控制与隔离级别
为了达到数据一致性和性能的平衡,分布式事务的关键是数据库隔离控制。XA的隔离级别最高能够达到serializable(彻底串行化),该级别将不存在幻读的问题,serializable级别能够经过设置SET global tx_isolation='serializable'来对DCDB全部物理分片(和其上承载的MySQL数据库)进行设置。固然,也能够经过调整隔离级别以调整数据库实例性能,理论上,Read Uncommitted性能最高,但可能存在脏读、幻读的状况。
ANSI/ISO定义的SQL-92
标准定义的四种隔离级别
五、分布式事务处理算法
前面讲到,腾讯云DCDB的网关在shard模式下已经可以解析SQL语句,腾讯云在网关上实现TM以使得XA最具效率。为此,咱们在网关中实现TM中的协调器(coordinator),并在网关中维护每一个XA的状态,记录好每一个XA写入的SET,而后在提交阶段作两阶段提交便可,大体流程以下:
(1)、网关在执行一个事务的insert/update/delete语句时,会记录这个语句修改了哪一个SET;
(2)、SET时会发送一个XA START在这个SET上面启动事务分支;(注:XA事务开始时,并不确认事务将以哪一种提交方式执行,所以老是以xa start来开启一个事务);
(3)、检测是否影响SET个数≤1,如果,则直接作一阶段提交(xa commit one phase)。
(4)、影响SET个数≥2,则改成作两阶段提交:
1)网关首先发送xa prepare‘gtid’ 给参与的SET(大于等于2个SET);
2)SET接受到xa prepare应答ok(表示成功确认);
3)收到成功确认后,写入XA对应的commit log,再发送xa commit‘gtid’参与SET;
4)若是有SET返回了错误,或者写入commit log失败,那么网关发送 xa rollback‘gtid’给相关SET,这样这个全局事务就实现了回滚。
腾讯云DCDB的commit log是在SET中存储,这个步骤是批量完成的——网关后台线程会聚集正在提交的分布式事务而后在独立的链接和事务中完成对每一个SET的写入,而且每一个事务的commit log只写入一个SET中,于是这个开销并无显著增长事务的提交耗时或者下降TPS。并且,依赖腾讯云DCDB已有的强同步和容灾特性,只要XA成功写入了commit log,就意味着数据已经写入从机。
虽然绝大多数的XA事务能够正常执行。但极少数的异常状况仍是会影响整个集群稳定性,所以,腾讯云设计了agent(监控模块),在故障后继续协助完成本地MySQL上面prepared事务的提交,即agent会解析commit log,并根据异常处理本地仍然处于prepared的事务数据;若是commit log上面没有事务的提交决定的话,agent也会回滚超时未被提交的prepared本地事务。
虽然在MySQL 5.五、5.6等版本早已实现XA,但这两个版本相对于5.7仍然有性能不足,所以腾讯云目前只在公有云上基于5.7.17支持XA版本。现在,腾讯云在MySQL 、percona、MariaDB等分支中作了大量优化和相关bug修复(部分已经提交到社区修复patch或开源),将来腾讯云还将继续致力于新特性的开发和相关Bug的修复,为众多有须要的企业,提供更好的分布式数据库支持。
此文已由做者受权腾讯云技术社区发布,转载请注明文章出处
原文连接:cloud.tencent.com/community/a…
获取更多腾讯海量技术实践干货,欢迎你们前往腾讯云技术社区