淘宝杨志丰:OceanBase–淘宝结构化大数据解决之道
-
时至今日,“Big data”(大数据)时代的来临已经毋庸置疑,尤其是在电信、金融等行业,几乎已经到了“数据就是业务本身”的地步。这种趋势已经让很多相信数据之力量的企业做出改变。恰逢此时,为了让更多的人了解和使用分析大数据,CSDN独家承办的大数据技术大会于今日在北京中旅大厦召开。本次大会汇集Hadoop、NoSQL、数据分析与挖掘、数据仓库、商业智能以及开源云计算架构等诸多热点话题。包括百度、淘宝、新浪等业界知名专家与参会者齐聚一堂,共同探讨大数据浪潮下的行业应对法则以及大数据时代的抉择。
淘宝核心系统存储系统研发专家杨志丰
杨志丰表示淘宝每天大约有6000万用户登录以及20亿PV量。淘宝数据库对于淘宝来说非常重要。几乎所有淘宝业务都依赖淘宝数据库。淘宝数据库具备数以千计的数据库服务器同时要应对单表几亿至几百亿条的记录以及每天几亿至几百亿次访问。
为了应对大数据的冲击,淘宝将以前的Oracle、小型机、高端存储模式转变到现今的MySQL、OceanBase、Hbase、MongoDB等数据库,并使用普通PC服务器。杨志丰表示OceanBase可扩展数千亿条记录、数百TB数据、数十万QPS以及数万TPS。同时具备实时容错、自动故障恢复和99.999%高可用性。
以下为文字实录
大家好,我叫杨志丰,其实我们QceanBase的总架构师是杨振坤老师,名字很想象。很高兴与大家分享一下我们淘宝的大数据解决之道,这个题目很大,我讲的东西很具体,我们思路首先看看淘宝数据有多大,然后在淘宝数据里面一大块是在线结构化的存储,这部分我们QceanBase这个系统就是解决其中的一个问题。这个问题一会我会着重落讲,最后重点是在QceanBase这个系统上,希望我今天讲完之后,大家能够记住几点,第一,淘宝数据有多大,第二,QceanBase的特点在什么地方。
这幅图上是淘宝网的年度交易额,淘宝成立于2003年,这是每年的交易额,基本上可以看到一年翻一番,有些年份略微不足一点,基本上是翻番的,就是指数增长。大家猜一下,淘宝现在每天的PV有多少,淘宝每天有6千万用户登录,每天PV大约20亿,这是alexa淘宝上流量,纵轴表示每天全球访问互联网的网民中有多少是访问了淘宝,之后这个边边就是刚刚结束双十一的促销,马上就上去了。淘宝有这么多PV,每次页面都要访问后面数据库几十次。
我们运营人员需要很多报表,每一个发表都要分析几T,甚至几百T的数据。淘宝数据大概可以分成三块,一个就是离线的数据,淘宝离线数据,其中一块,我们存在Hadoop机群里面,有2千多个集群,这里面存了39P以上的数据,每天要运行4万多个MapReduce,一方面产生各种运营报表,还有一些可能有利于我们卖家无法开展运营。举几个例子,淘宝上最畅销的手机价格区间,1千-2千块钱。01年的什么年货最畅销?糖果类,最后是什么地方的人最爱吃大闸蟹,广东,上海,这是一些离线数据。
另外一些在线数据,可以分成两类,第一类非结构化的数据。非结构化数据,主要是图片,以前的时候淘宝图片都是卖家找一些,这种网盘了,都是外列,在外面面向外面网站,极大地影响了用户体验,后来淘宝一些大的卖家都可以把图片存在淘宝里面,这个数据目前有2700TB,他们都是存到淘宝自主研发TFS文件系统成本。
TFS文件系统,结构比较简单,但是实时响应能力很好,实现同城热备和同城备份。在线结构化数据,这部分数据是淘宝最核心的数据,包括商品库,用户库,还有店铺库,还有一些评价库等等,每一个库可能就是一张大表,或者若干张表。举一个例子,淘宝的商品库,淘宝商品库现在有,因为我们商品库里面是分在线和已经下线商品,总共加起来有22亿商品,峰值QPS是78K,TPS是2.7K,这是一个商品库基本概况。
我们今天在具体一点讲的是一个淘宝的收藏夹,这是用户浏览商品,他如果喜欢这个宝贝就可以点击收藏,用户可以在自己收藏夹里面看到所有收藏宝贝,这个宝贝可以按照价格,或者是它的收藏时间进行排序。另外后面有一个收藏人气,这个宝贝被多少人收藏,这个信息对于卖家是非常重要的。收藏夹数据库模型基本上很简单,一个是宝贝的信息,包括每一个宝贝有一个唯一的ID,有它的价格,还有它的收藏人气等等,还有其他一些属性,这个我们叫做宝贝信息表。另外一个是收藏信息表,就是用户ID和宝贝之间的关系,这个信息表现有65亿记录。
收藏夹这个应用对于数据库是有非常大的挑战,挑战在什么地方呢?首先,收藏夹的里边,每一个用户可能会收藏上千条的宝贝,另外是一些热门的宝贝,可能被十几万人收藏,其中价格和收藏人气是随时变化的。所以,每一个人在收藏的时候要实时把最新价格,或者人气展现出来。另外还有一些其他应用要按照属性进行排序。收藏夹每天有1.2亿次人的访问,这是平均,响应时间必须要求在100ms之内。
现在给大家简单讲一下收藏夹数据模型,左边是一个收藏信息表,右边是收藏宝贝表,收藏信息表里面存了收藏宝贝,如果我们用关心数据库去实现的话,他是一个很糟糕的情况,你的收藏宝贝表只能按照一种方法去做排序,用户对于宝贝的收藏其实是一个随机的。如果你想展现一个用户所有收藏的宝贝,你是要去执行一个,对于收藏宝贝表是一个随机的独操作。刚才提到性能指标,我们在100mb之内必须把这个结果返回,有些用户可以收藏上千条宝贝,也就是说,你要在100ms之内完成上千次随机读,这个对于普通磁盘100ms,最好的磁盘只能做30次左右的随机读,1毫秒钟不会超过300次。
所以,在这个应用对数据库是一个非常大的挑战。大家有经验的就会想到,我能不能这么做,我把刚才左边这个表和右边的表转起来,存一个宽表,所谓宽表?就是说我们把宝贝的价格,人气这些属性都存到左边这个表里面去,这是一个很好的方案。但是,刚才提到一个问题,用户的收藏人气是随时会发生变化的,所以一旦你的宝贝属性发生变化的时候,你对于左边这个表来说要执行很多很多的修改操作,这个基本上很难实施完成。为了解决,这个问题是QceanBase这个系统设计的初衷。
下面我们就引出QceanBase海量数据库,刚才讲到淘宝数据库,淘宝数据库有一些特点,第一几乎所有的淘宝业务都依赖于数据库,因为淘宝其实是从做数据库开始的,最早的时候用MySQL,Oracle,这和其他很多互联网公司不一样。但是在电商这一块很多都是这样子的,淘宝的数据库是数以千计数据库服务器,他的数据量非常大,单表可能达到几亿到几百亿条数据,访问量都是几亿到几百亿次访问。
从最最懵懂的时候大家都是用MySQL开始,到最后就开始用Oracle,也许一个商业数据库本质上是一个单机的系统。所以,就要用就开始用很多昂贵硬件,比如IBM小型机,还有一些EMC高端存储,很大机柜,这一很贵。第二,这种数据库对运维人员来说是一个黑匣子,我们遇到问题只能求助于商业知识了。还有一个问题Oracle本身提供的默认分片,单个服务器承担的数据量是有一个上线的,他本身分片对性能会有很大影响。对于数据库的选型基本上是百花齐放,一个主要潮流,很多以前用Oracle的,如果你现在允许的话,尽量使用MySQL,还有QceanBase,还有Hbase,QceanBase是我们自主研发的系统,目前有很多应用在,最大系统就是我们刚才讲的收藏家。如果要用MySQL传统DPS去支持一个大的访问量,大家都知道分库和分表,你把数据库根据你的组件分成好多小表,存在MySQL里面,MySQL本身又提供备份,所以在换届访问量大的挑战方面,这是一个解决的办法。但是,这种一般分库分表都需要应用业务来介入,比如说,实际上对应用来说不需要关心你下面,如果你的业务增长了,本来对应用应该没有任何影响的,这种分库分表对他们可见的话,这种分库分表的逻辑都需要写在应用里面,业务逻辑要支持。
另外是扩展性的问题,我们说到分库分表一般是用原来的解决方案,你要考虑到扩容,就要除以20,想到以后要变成20台机器,就除以20。但是把它存到10台机器上面,我们扩容都是机器要翻倍的,QceanBase这样系统本身是单机系统,在做容错方面需要很多人工介入。纵轴表示数据规模,一般DPS数据规模是千万量级的,好的QceanBase数据库一般都是千亿到万亿量级的。但是,Hbase和Bigtable是支持单行,对于互联网一些应用是支持的,对于淘宝的很多应用是不够的。所以,他们两个优劣,其中一个优点就是另一个缺点。理论上你的数据规模上去了,或者性能要求上去了,你就只需要加机器就可以了。
当然还有一个解决分布式事务系统,在这个上面可以支持万亿事务,跨行跨表,因为是搭在QceanBase上面,并且本身解决是分布式事务的问题。所以,QceanBase我们希望找一个点,我们要提供跨行跨表的事务,在这方面像传统DBM使看齐。但在可扩展性方面,希望找到一个折中点,我们提供不了那么高的数据量,但是我们要比传统DBMS要支持的数据量更大。
刚才那个点,QceanBase的设计目标第一要提供千亿级,量级记录数,我们假设每条记录是1K的话就是数百TB数据,数十万QPS,数万TBS,要支持ACID完整的事务。因为我们内部有很多要求,所以我们支持的范围查询,我们提供实时容错,自动故障恢复,自动负载均衡,实现5个9的可用性,要实现普通PC服务器能做,不需要特别贵的硬件。
大家都说我们数据量很大,但是你每天更新的数据,其实没那么大。可能你说你有100T的数据,但是你更新的数据,每天能更新的数据不到1%。我们就没有必要为了这1%而去说,我们数据可以看作两部分组成,一个是基准数据,一个就是增量数据,1%就是增量数据,我们可以对于基准数据和增量数据采用不同做法,不同的体系结构去做。
基准的数据我们使用分布式的存储,把他向QceanBase系统一样分成很多片,分布到一个分布式存储里面去,他是一个静态B+树作用。增量数据,我们实现一个单点来实现,这是他设计最独到的地方。下面我就围绕这幅图来讲一下,最左边是一个客户端,然后我们系统里面有四个角色,第一个是叫RootServer,刚才说到静态数据,是要把整个大数据分成很多很多片的,这些分片的位置信息,我们叫做原数据,这个原数据其实是一个数的根接点,这个根接点是存在RootServer上,同时在这些机器上还有一个UpdateServer,增量数据。这个RootServer跟UpdateServer做了准备,逻辑上是一个点。
ChunkServer,是把静态数据划成片之后,每一个小块有若干个辅本存到这个上面去。所以,这上面UpdateServer是所有的写,所有读是通过这个MergeServer而,一个查询请求来了之后,他首先要从本地ChunkServer把基本数据读一下,把这个区间之内新增增量数据给我,提供进行读事务。这个前面也说了基准数据是一个静态的B+树,这个树的比价点是存在RootServer,他存在与若干台辅本,这个Tablet就是在其上面的一个辅本。
增量数据存储方式,不是存到硬盘上,是完全存在内存里的,这是逻辑上是完全存在内存里的。数据分成基准数据和增量数据之后,增量数据每天都在增加,你必须合到基准数据里面去,这个做法有总控的节点,通知这些ChunkServer,我们会选择一个低负载时段,淘宝数据很明显,因为我们用户都是在一个地域之内的,所以他有一个明显的高分和低谷,在低谷的时候我们用一些低优先级方式去进行合并操作,这个合并操作是这样做的?我们数据不管是基准数据,还是增量数据都有一个版本号。比如最开始的时候,这个基准数据版本是1,我对应于这个基准数据这个增量数据版本是2,要开始合并了,合并的时候就把这部分数据给RootServer发一个命令,冻结之后就不能改了,如果冻结这个点做完之后又有新的数据来了,这就是一个新的版本,这个点做完之后,就通知所有ChunkServer,我现在数据是1恩,我要所有版本等于2的数据,你把那部分数据给我,这个过程我们叫做基准数据更新,这个更新,所有ChunkServer,去RootServer去要增量数据,将整个过程做完之后,就可以把这部分的增量数据从内存中释放掉了。
所以,会存在一个时刻,一个很多副本,同一个版本数据必须是一模一样的。这样一个单点结构,肯定就会有质疑,你的性能是怎样的,UpdataServer是用一个内存实现,不考虑后面要写日志,我们使用Copy的技术,你在修改的时候先拷贝出来,这个B树有一个特点,你的一些读操作。基于内存实现,我们先不考虑为了数据持久性要写日志,光这个内存实现,他的性能是每秒钟10万次修改,每秒钟100万次读操作。但是这样肯定是不够的,你每次修改之后,都要给用户返回成功之前要保证这个数据实际上已经持久化了,我们实际上是写了一个操作做的事情先记到日志里面,然后去做修改操作,修改操作做完了,这个日志要同时传过去,那边也写到纸板上我们才说成功了。不需要每一个操作日志都写,因为磁盘有限,你等10毫米可以拒绝几十个,几百个请求了,打包成一个日志写进去,这个技术叫做Group commit,下面用的有RAID卡,RAID卡是带电池的,一旦写给他,从软件角度来看放心就可以了。
刚才说到所有读操作,每次读操作都要经过UpdateServer,即使你数据没有了,没有一个更新数据也要去问他,这对网络带宽是一个很大压力。我们现在UpdateServer用的是万兆网卡,所有修改都是放在内存里面,如果内存放不下怎么办,我们会转储到本地SSD里面去。我们磁盘有两种,存储有两种系统,一个是磁盘,一个是SSD,SSD是把内存整个结合进去,如果有了读操作落到这部分,因此宕不出去内容里面,就从SSD上去读,SSD可以提供很好的随机读的性能。
如果是单机部署的话,每一个数据是有三个辅本,我们实现了多机群部署,个集群可以提供位于不同机房,这两个机房有一个是同城,还有异地做灾备的,如果同城两个之间需要同步,每一个机房里面只需要保存两个副本就可以了,如果有远程的灾备就是2+2+2的模式。所有数据都是有校验,一个重要特性,因为我们系统初期可能会频繁有升级,我们现在已经可以做到升级,或者你要切换的时候不停机。如果一个应用他同时部署两个集群,那么他可以先把一个停掉,把另外一个变成主,然后你把那边升级好之后再接上来,这样倒一下就可以把整个系统升级了。
收藏夹应用在半年多前上线,我刚才给大家讲的收藏信息表,里面有65亿条记录,每天有1.2亿次访问,我们平均响应时间大约在80毫秒左右。在使用QceanBase之前,我们是有16台机器,现在已经降到,使用QceanBase之后只需要6台机器就可以支撑同样的访问量。这是我们实际运行的一个监控图,给大家一个直观的概念,这是每一天访问量,大概在晚上有一个高峰,在高峰的时候大概700,800左右。这是查询,这是平均响应时间,可以看到平均响应时间是在80毫秒左右。
刚刚结束的世纪光棍节,我们叫双十一网购狂欢节,就在那一天,我们整个收藏夹总库量是170亿条,一天有1.85亿次更新操作,查询有两种,scan是顺序读,get可以看成一个随机读,分别达到2.3亿和2.9亿次。峰值QPS是9000+5000,一共14000次。
下一步工作里面第一个是SSD,最新数据可以号称达到100万次随机读。ChunkServer有一个特点,没有随机写,对于SSD来说,表面上比较怕随机写,我们ChunkServer没有随机写,我们把这个也改成ChunkServer使用SSD单机QPS可以达到5万次,虽然你多花了一点钱,但是你的机器数降下来了。使用SSD之后,我们由14台机器变成6台。
另外一块是OLAP,从我们系统角度来看,刚才已经给大家说了,在收藏夹里面主要是UpdataServer,OLAP对于UpdateServer没有多大差别,但是有一些BI用的比较复杂的查询,实际上现在我们已经实现了,现在基于这么一个SQL的依据,SELECT,FROM,WHERE,还有GROUP BY聚合请求,还有一个符合链,都是已经支持的。这部分支持主要是刚才讲的那四个方面功能点,对于其他模块没有什么影响。
比如现在收藏夹里面都有很多数据,要从线上数据库里面导出,导出Hadoop机群里面做计算,结算完之后再倒回来,对于数据倒来倒去是非常耗带宽,可能会影响其他利用。我们希望能不能把MapReduce和我们本身QceanBase结合到一起。做法其实很简单,首先Hadoop机群本身和QceanBase处于一个机群,另外去定制MapReduce程序的输入输出,这个已经在开发中了。
QceanBase现在不足,主要是功能上的一些问题。比如不支持,只实现部分的join,没有实现一些高级特性。比如说一个缺陷,不支持辅助索引,这是很多问题。我们做QceanBase是一个非常开放的心态,我们所有代码都是开源的,包括设计文档,我们每次有一个新的版本,在内部升级完之后,都是把它立即更新到开源的网站上去。在淘蝌蚪上还有很多淘宝核心系统部做的很多系统,比如存储图片还有,还有一些其他服务。
我们总结一下,今天讲的两个问题,第一希望大家记住淘宝的离线数据有39T,图片有2700T,商品有14亿+8亿,下线的和在线的。QceanBase最大的特点是把基准数据和增量数据分开,把读事务和写事务分开,这是QceanBase最大的特点,谢谢大家。