支付宝双11的功臣-分布式关系型数据库(oceanbase)
我们都知道阿里双11,除了创造了世界史上的交易奇迹之外,也创造了世界技术史上的奇迹。支付宝的峰值达到了每秒12万笔,这在技术界简直是一个奇迹。为什么说他是一个奇迹呢?简单的来解释一下:其实在日常开发中,打交道最多的就是数据库,好多开发都戏称只会增、删、改。但是千万不要小看增、删、改,因为假设你只有一个用户访问的你的数据库,你怎么写都可以,但是如果有几十万,上百万,上千万,乃至上亿用户呢?如果操作不当,那么你的数据库一定会down掉。所以看上去简单的东西其实一点都不简单,就好像风清扬一样,简单的剑招却蕴含着上千变化。
这里,我主要想揭秘下oceanbase,因为整个支付宝的交易的库都是依赖于它。oceanbase究竟是什么?用官方的话是这样的:OceanBase是一个支持海量数据的高性能分布式数据库系统,实现了数千亿条记录、数百TB数据上的跨行跨表事务,由淘宝核心系统研发部、运维、DBA、广告、应用研发等部门共同完成。那么以前在没有使用ob之前,支付宝都用的什么呢?mysql或者oracle。这两个一个是开源的数据库,一个是甲骨文公司的商业付费数据库。简单的来说都是人家老外搞得!其实这两个数据库已经很强大了,支付宝以前的框架都是基于这两种数据库的。但是随着业务的发展,这两种数据库也带来了弊端。
-------------------------------------------------------------华丽的分割线-------------------------------------------------------------
假设我们要撑起上千万的并发量,上百PB,乃至TB的数据量。如何设计?
方案一、单库(热备)
这个方案完全不行,原因不多说了。
方案二、数据拆分(分库分表)
按照业务特点将数据拆分:
垂直拆分以及水平拆分------比如说利用用户的user_id通过hash取模,然后路由到不同的分区。
这么做带来的问题有两个:1、当数据/负载增加时,需要人工介入,代价非常大。
2、select查询有时候需要便利所有的分区,速度非常慢。
3、每一台机器都要主从同步,管理起来太麻烦。
方案三、参考google的bigtable
主要是将一个bigtable拆分成几百万个子表(主键有序)。
好处:1、数据不会丢失(hdfs),故障迁移,可扩展。2、子表有序,查询快。
这样的话,方案就生成了,参考bigtable,在hbase的开源基础上自己开发一套。后来经过验证发现不行,因为,首先hbase的开源不彻底,每台单机支持的数据有限,然后是必须引入分布式事务2PC,一般时间在2~5s左右,因为对于hbase这种nosql只保证单行事务,如果要跨行跨表操作是支持不了的。并且分布式事务太耗时,所以这个方案只能抛弃!
在设计oceanbase的时候,目标是支持10w+tps,100w+qps,100TB+数据,难道没有方案了么?-------------------------------------------------------------华丽的分割线-------------------------------------------------------------
既要有非关系数据库的海量数据存储,还要有关系型数据库的事务,到底如何该解决呢?
经过数据分析,发现了隐藏在数据中的一个秘密:虽然业务线的数据量庞大,但是修改量实际很少。这个怎么理解。
我打个比喻:
1、人口基数实际上非常大,但是考虑到出生/死亡/失踪,这部分人口实际上在总人口中占比很小。
2、金融账务系统每天要记录很多的流水,但是考虑到一半在线上保存一年的流水,那么每天新增的几乎占比很小。
3、金融交易系统每天虽然要记录很多交易,但是考虑到一半都保存一年以上的交易记录,那么新增的占比很小的。
这就是隐藏在数据中的秘密!
其实大部分的数据,都是基数大,新增,删除,修改量占比不大。
那么可以这么解决。采用单台服务器记录最近一段时间的修改增量(内存中记录),而以前的数据不变(基线数据)。写事务只在单台服务器写,避免了2PC,高效的实现了跨行跨表事务。然后定期合并修改增量到基线数据服务器。
-------------------------------------------------------------华丽的分割线-------------------------------------------------------------
基于上面描述,OB整个系统架构:
整个ob集群包括:rootserver,updateserver,chunkserver,mergeserver这几个类服务器。
client:与mysql兼容,协议相同。
rootserver:管理集群,子表,数据分布,副本。分为主,副(主备数据同步)
updateserver:存储ob中的增量数据(内存)主备
chunkserver:存储基线数据
mergeserver:接受sql,解析,优化,转发给chunkserver或者updateserver,合并结果给客户端。
接下来我们来深入探讨一下:
首先ob部署在多个机房,每个机房一个ob集群。
客户端的请求过程:
1、请求rootserver获取ob集群中的mergeserver列表
2、按照一定策略选择mergeserver
3、请求失败后,重新选择一台mergeserver,如果某一台被请求失败超过一定次数,拉黑。
oceanbase集群会根据路由规则控制流量比,所以不用担心负载的问题。
ob中的基线数据按照主键排序(查询非常快)并划分为子表(每一个256M),并且都有副本。而在rootserver中记录了每个子表在chunkserver的位置。
mergeserver会缓存子表的分部信息,根据请求转发给该子表所在的chunkserver,如果写操作还会转发给updateserver。
在chunkserver中,一般存储子表,而一个子表由多个sstable过程,每个sstable的容量4k~64(主键有序)。
合并操作:
oceanbase定期触发合并/数据分发操作,chunkserver会从updateserver中获取一段时间更新的操作。(业务低谷时操作)
updateserver:
更新操作写入内存,当内存数据量超过一定值时,生成快照存储在SSD中。
定期合并/数据分发:把updateserver增量更新分发到chunkserver中。
1、updateserver冻结当前的活跃的内存表(Active Memory),生成冻结内存表,开启新的活跃内存表后,缓存更新操作写入新的活跃内存表。
2、updateserver通知rootserver数据版本变化,rootserver心跳通知chunkserver。
3、每台chunkserver启动定期合并或数据分发,从updateserver获取每个子表对应的增量更新数据。
为什么分为定期合并和数据分发?
定期合并:chunkserver讲本地sstable中的基线数据与冻结内存表中的增量更新数据归并,生成新的sstable。(因为合并操作对服务器性能影响非常大,需要在业务低估时进行)
数据分发:chunkserver将updateserver中的冻结内存表中的增量缓存到本地。(不受业务高峰限制)
以上就是我对ob的原理的总结,其中也看出一些问题,首先updateserver需要非常大的内存,第二为了避免单点,应该是主备切换,这里面用了zookeeper中的paxos算法,选举主机。整个ob还是非常复杂的,如果想深入探究还需要花费很大的功夫啊!