大数据频道 频道

京东田琪:分布式KV数据库一致性挑战

  【IT168 专稿】本文根据【2016 第七届中国数据库技术大会】(微信搜索DTCC2014,关注关注中国数据库技术大会公众号)现场演讲嘉宾田琪老师分享内容整理而成。录音整理及文字编辑IT168@ZYY@老鱼

  讲师简介

京东田琪:分布式KV数据库一致性挑战
▲田琪

  京东数据库系统研发部负责人,目前负责京东分布式数据库系统研发及内部数据库系统支撑。曾分别就职于腾讯,新浪微博,搜狐等互联网公司,主要关注分布式系统,容器技术,数据库 内核,Linux内核等系统技术。

  正文

  大家好,我是来自京东的田琪,今天分享的主题是《Meet the challenge of building distributed kv with full ACID properties》,开始之前,我们先回顾一下数据库的发展历程:

京东田琪:分布式KV数据库一致性挑战

  数据库的发展分为三个阶段,最早的阶段是SQL/RDMS,在这个阶段,数据库本身的特点是使用范围广,现在也有很多公司或企业在使用该数据库,最糟糕的问题是水平扩展能力很差。随着业务的发展,数据量变得更多,访问量变得更大,我们进入了第二个阶段,该阶段对数据库的要求和单机数据库不同,这个阶段主要解决数据库的扩展性,不是单机数据库而是多个,需要解决数据的拆分和扩容。不论是NoSQL还是中间件都有一些缺陷,所以这个阶段迟早也会过去,虽然我们现在处于该阶段,但迟早会进入下一阶段。最后一个阶段是今天要讲的NewSQL,最终希望这个数据库能够做到像单机数据库一样支持所有特性,同时保证整个数据的可容性,扩展性和一致性,以及完整的事务性支持。

  谷歌数据库的发展轨迹,04年推出BigTable,当时国内最早的NoSQL相关产品,基本上也是在这个基础上衍生出来的,04年的国内数据库基本上是单机数据库阶段,通过写中间层的方式把这个事情完全屏蔽掉。

京东田琪:分布式KV数据库一致性挑战

  上图的JProxy节点对数据做水平拆分,把语句拆分成多张表,JProxy支持MySQL协议,数据过来之后会被自动拆分成很多分片,分片拆分完之后会对应不同的MySQL实例。这里涉及到数据拆分和实例的对应关系,我们把这个关系叫做路由,据此可以清楚反映出请求应该打到哪个实例上,在路由左侧的JManager中心结点上存储,通过两个阶段的比较协议来完成路由同步。

  这样做可以解决数据拆分问题,之后需要解决无缝迁移问题,因为在实际应用中,很可能今天数据拆了十份,明天业务量增长了,需要一百份。无缝迁移是怎么做的呢?比如shard要迁移,只需要将从哪个节点迁移到哪个节点的信息提交给transfer,到时间执行时把shard复制,做一个快照导到另一个事例里(MySQL支持快照),然后追踪shard 就可以得到增量,由于线上写入还在源源不断的进行,这时候会影响写入,先经过全量再做增量,对数据进行同步追踪。线下迁移做的差不多了要切换路由,首先使流量不再打到原来的分片上,这时线下把数据追上,之后比较两片增量是否一致。如果一致,原来的分片就跑到新的实例上,发起切换路由,通知把自己的路由切换过来,之后会通知所有的proxy,将所有路由整个迁移过来,这对线上访问是没有影响的。这样,整个系统就可以大规模落地使用了。

  纵观整个系统还是有很多局限,虽然解决了上述两个问题,但中间方案很难做,也很难支持事务,数据很容易不一致,这是经常会出现的问题。其实很多架构都会遇到相似的问题,比如NoSQL。

京东田琪:分布式KV数据库一致性挑战

  其实NoSQL也会遇到很多问题,比如primary挂掉之后如何保证secondary一致,这里无非涉及到被动复制和主动复制两种技术,MySQL是被动数据,可能会丢数据。当然,也可以把数据写多份来完成备份并发高可用相关的事,但写多份就会出现多结点不一致的问题,这肯定没法支持SQL相关的事情。

京东田琪:分布式KV数据库一致性挑战

  现阶段会遇到一些问题比如用户真实的需求是什么,或者如何解决高负担问题。本质上现在的数据库还没有做到这个层面,只是让业务牺牲。但这个时代早晚会过去,最终的数据库应该像单机数据库一样方便。

  最终的架构大致如上图所示,标绿的是我们自己添加的,其它的是现在的NoSQL或其他数据库具备的,最下面两层相当于单机存储。主要是把数据拆成很多分片,在分片之上构建集群或分布式系统的大而完整的动脉,这个区别于一般的普通KV。

  首先底层是Range或Consensus,二者都可以使用。往上是Node或Store,再往上是Monolithic Map,只有在在此基础上才支持Distributed KV,在KV上可以构建支持完整事务,最后是SQL,这个架构就是这样的。

京东田琪:分布式KV数据库一致性挑战

  首先至少要支持snapshot isolation,使用两个阶段的commit,两个阶段的锁或者解锁算法,并且单机数据库是有多版本的,单机数据库的版本就是简单的ID,分布式系统无法用单纯的ID访问,需要使用timestamp,这样最终所有的KV落下来都会分为两部分,一是实际的Key,一是timestamp,用timestamp代表Key,所有写入实际上都是对key的修改,最终的kv接口大抵如下图所示:

京东田琪:分布式KV数据库一致性挑战

  Get,Put,ConditionalPut,Scan很重要,通过scan可以实现select,最后是Del。

京东田琪:分布式KV数据库一致性挑战

  单一数据库更新访问数据,理念更细化,当两个事务同时更新相同的数据时,会造成第三个事务的卡顿,前两个结束以后,第三个才可以开始。但分布式系统不能加锁,如果加锁对性能的损失非常大。但要保证整个系统正常运转起来,需要用到锁,分布式系统的加锁方式与普通的不一样。为了避免死锁,如果需要修改abc三个key,正常情况下,先遇到先加锁先访问,两个事务分别加锁访问,比如T1事务对A加锁要换成B,T2对B加锁要换成A,这就会造成死锁。所以,加锁之前,先排序,按顺序成功添加A锁,再添加B和C,如果中间遇到某个环节失败会按顺序回馈,加锁有顺序可以有效避免死锁。

  时戳在分布式系统里非常困难。取一个准确的时戳很难,分布式系统里有多个节点,时戳都是不一定,不准确的。NTP也解决不了,延迟很不可控,谷歌可以将时戳误差控制在7毫秒,我们做开源的没有这类设备,但可以通过算法控制,毕竟对时戳不确定性的处理很关键。

  上图画了两个事务,对于同一个key,版本就是时戳。取数据时会带一个时戳,只要数据的版本比时戳小就是可见的,比时戳大就是不可见的。如果只能看到比版本小的,看不到比版本大的,说明这个事务是不可见的。

  如图所示,事务T1先开启,这时候会看到k1,T1开始之后T2开启,实际上可以看到T2是T1之后发生的,所以T2事务的版本或时戳比T1大,这样才是正确的。T1把key修改为1,之后T2访问拿到的值就是1,这时候你会发现T2破坏了整个体系,所以这是整个系统非常复杂的地方,也是时戳的关键体现,这里会用算法解决这个问题,首先必须保证T1绑定的时戳大于T2,换句话说key1的版本大于key2,这是时戳一个比较关键的错误,也是比较复杂的,接下来我举例说明分布式如何解决这个问题。

京东田琪:分布式KV数据库一致性挑战

  简单地说该例子的功能是从Bob账户转钱给Joe,所有的版本都在data里,lock放的是相关的锁,write和data配合给出当前版本。Bob这一行,data是10表示有10美元,lock是空的表示没有事务访问,write的data版本是5,指向data中的5也就是10美元。

京东田琪:分布式KV数据库一致性挑战

  接下来要执行分布式事务——转钱,首先第一步对Bob添加一个锁,如锁添加成功,会修改数据,实际上并不是直接修改数据,而是加一个新的版本,由10减去7变成3,并且有新的版本号7,我就把新的版本写进去,如果锁没加成功,之前也没加过,就会回退。添加成功后,因为事务还没提交,所以现在仍然是读到10。

  第二步对Joe加锁,如果失败了会回退,把primary锁释放掉。加成功了会修改Joe数据,加7变9,并且新版本也是7,锁是secondary,可以指出锁的primary是Bob.bal,多个修改串起来其实是一个事务。同时也可以看到这一列没什么变化,现在读仍然和之前一样,对其它读没有影响。如果修改成功,会产生新的数据版本,之后需要进行提交。

京东田琪:分布式KV数据库一致性挑战

  首先把版本释放,先把最新的版本标上,Bob里出现了data@7,这就相当于提交了。

  成功之后对下面做相同的操作,也指向7,把第二个元素释放,再读就会读到提交之后的数据,比如读到3和9,这样就完成了整个事务处理。

京东田琪:分布式KV数据库一致性挑战

  这里是两个提交加两个锁的事项,解决了分布式事务问题,下面解决一致性问题。三个节点的情况下,保证所有写入的三个点是一致的,把三个点分成不同的角色,加皇冠的是leader,下面是follower,所有写入都写到leader上,不能直接写,可能出现不一致。左侧的stata Machine是数据,右侧是log,它并不是直接修改数据,会先写一个log,log写成功并提交之后,数据就会发生变更,它会通知你数据写入成功,大概是这个流程。实际应用中,多个结点把数据拆成很多分片,每个分片都以raft的方式在跑。如果用了raft,所有操作都是串行的。

  这样做也会带来很多问题,比如大量的网络开销,花很多数据才能保证节点重启之后的状态,很难实现自迁移。迁移实际上就是对上把KV包装成数据库的普通支持。

京东田琪:分布式KV数据库一致性挑战

  比如说一个表是一个ID,每张表大概插入两个数据,后面是索引的值,它会通过两个key把一条数据写入,多列就会更多。

  如果表列非常多。就不太支持,加一个也非常困难,列非常多的话,最终的系统性能大概慢两个数量级。可以通过优化,把一些mysql语句抽象,到搜索引擎上执行,进而提高性能。

  总之,今天的分享主要涉及分布式系统各方面的问题,这个时代肯定终会过去,我们一定会进入到下一个时代。

  今天的分享到此结束,谢谢大家!

0
相关文章