浅谈分布式数据库该如何学习和实践 上篇
0 引言
现在分布式数据库的学习来说,最主要的困惑还是两个:
- 现在分布式数据库类型的产品太多
- 分布式数据库的许多概念,比如nosql,目前产品自身也未对概念有共识
而这篇文章将从几个角度来阐述,分布数数据库该如何学习以及实践,面对的人群,既可能是对分布式数据库有兴趣并且想要深入的初学者,也可能是一些实践在一线的技术工作人员,当然探讨为主,主要是还是理清脉络和思路。
1 数据库主要解决的问题
长话短说,数据库出现是有原因的,业务开发不擅长开发,需求有共性,且容易得出通用性解决方案,值得强调的是,这三个条件缺一不可,数据库的两大功能:
- 以各种姿势对数据做查询(Online analytical processing = OLAP)
- 保证多个操作要么一起完成,要么一起失败(Online transaction processing = OLTP)
- 其他比如结构化数据,列啊,表啊,sql语法,都是实现体系,但不是数据库功能的本质
这两个功能的本质需求来源,就在于计算机系统的三级存储架构:
- 磁盘写入慢但持久化存储(一旦写入不易丢失)
- 内存写入读取快但非持久化存储(掉电则丢失)
试想,如果没有内存和磁盘两级存储切内存可以持久化(掉电数据不丢失),我们还需要数据库吗(或许那时候我们的数据库就只是一个解析器+KV map)
而数据库解决两个问题的方式:
- 利用一套面向结果的SQL语法,来支持各种方式的查询,SQL的语法和标准,也不是浮沙上盖大楼,而是来源于数学中的关系代数(Relational algebra)
- 利用先在磁盘记录一条改动记录,以及回滚方式,来保证事务在掉电后仍然可以重启恢复之前的状态,概括为log write first, two phase commit
当然不同的数据库实现方式有一些差异,但是基本跳不出上面这两条的范畴。
2 分布式数据库 - 关系型数据库sharding
接着来说说分布式数据库中的关系型数据库sharding模型。
分布式数据库是为了解决单机数据库存储,IO或CPU的瓶颈而存在的
当出现单机瓶颈时,最简单的一种办法就是:将数据打散后存储在多个同样的关系型数据库中,这种方式被称为 shard nothing architecture ,这种模式一般来说,会有多个层次来实现:
- proxy sharding,就是做一层proxy,由proxy来决定在哪个DB来执行sqljdbc中间件sharding,用中间件实现,减少了服务和网络的损耗,其他和proxy几乎一致
- mysql的ndbcluster和fabric,这是mysql 引擎层面做的sharding
- 都可以部分支持OLTP,当sharding key一致时,事务没有任何问题,但是key不一致时,跨库的事务要么效率低,要么需要人工来拆锁,不可避免,这导致了sharding key必须是一个有意义的字段(否则连事务都没法做)
- 比如执行一句 update user set money = 100; 这样的全局sql,还是在一个大事务中,会跨库把所有的user都锁住。。
- 支持OLAP普遍不好,特别是需要跨库join,跨库子查询,目前这种方法也部分可解,就是自己来做一些小型的map reduce,或者把sql转换后降低中间结果数据量后继续执行,一些可行的做法可以看这份ppt:http://vitess.io/resources/percona-2016.pdf
- 还是OLAP的问题,OLAP都为单机执行,由于协议层执行sql的时候的假设就是sql下沉到DB层去执行,对于跨库sql,一般都只能支持到小表广播,或者是变换sql形式后下沉。
- 什么是小表广播,一个例子可以看这里:分布式关系型数据库 DRDS_最佳实践_SQL优化
- 变换sql后得以让sql实际执行下沉 (outsourced),可以参考:http://vitess.io/resources/percona-2016.pdf 这份ppt,或者是刚才的:分布式关系型数据库 DRDS_最佳实践_SQL优化
- 这些变更和小表广播是治标不治本,因为很显然,vitess和drds都仍然不支持 跨库join + 子查询
- 对动态扩容支持的不大好,但并不是完全无法支持
- 比如vitess的range hash方案,就可以自动扩容缩容
- 但是由于扩容和缩容的时候有数据基线追平后才能切换,导致一般需要中断服务一定时间(几ms)
- 这套玩意的部署和维护,需要消耗更多的开发和运维资源(相对直接用单纯的单机关系型数据库来说)
然后虽然有如此多的功能问题,但是这种sharding模式仍然受到很多大公司的欢迎,主要原因为:
- 相对来说,每个切片(partition or fragment)仍然是一个完整的库,看得见摸得着,这让很多用户较为放心。
- OLTP类问题,一般一个业务线可以拟定同样的sharding key,这对于业务较为成熟的大公司来说,sharding key不难确定,一旦sharding key确定,跨库事务是可以避免的。
- OLAP类问题,只需要同步到hbase再用hive或spark来做运算即可,同步可能会消耗一定时间(比如 T+1),但是不影响大数据业务来做离线分析。
- 少量的sql,如果是需要做分页,跨库join,也可以下沉到单库执行或是用小表广播解决。
- 部署和维护以及稳定的开发和运维资源,向来是一些大公司的优势而不是劣势。
3 分布式数据库 - nosql分析
接下来说说nosql的一些内容,先引入一张有人的总结图:
上放到了关系型数据库sharding的更高层次,这点我不是特别认可,我认为nosql和关系型sharding是两种需求的产物。
简单来说,nosql就是为了获得scale out 的目的,抛弃了事务和join。
mongo可以说是一个对这个需求贯彻的比较彻底的nosql db,最近传的比较多的 rethinkdb 挂掉事件,就可以很明显对比,我认为mongo的流行是一个为产品做减法获得的胜利,我觉得mongo至少在resharding,schemaless以及分布式map reduce这三个方向上走的很对,至少对于很多的小公司,这三个特性足够了。
- 事务可以依赖很多方式做到,不提供原生支持并不意味着做不到
- 特别是游戏公司,scale out 的特性和resharding的特性不但可以在火爆的时候迅速缓解压力,而且可以在不活跃时由回收很多机器
nosql的一个小节:
- nosql是一个典型的过渡性产物,舍弃了部分关系型数据库的特性,来达到scale out的特性,为了解决特定的需求所存在
- nosql对于关系型sharding的一个优势就是运维部署成本的降低,以及存储成本的降低(一般为两个副本到三个副本的存储,如果不容灾则为一个副本)
4 小结
简单介绍了关系型数据库sharding的分布式数据库方案以及nosql方案,简单来说,分布式数据库的三个难点:
- 事务(OLTP)
- 分析型sql(OLAP)
- 扩容能力(scale out)
这两个解决方案,都只能尽力解决两个:
- 关系型数据库sharding解决了半个OLTP,半个OLAP,半个scale out
- OLTP跨库支持不好
- OLAP只能通过同步数据到hadoop或其他工具来做到
- scale out在扩容和缩容方面面临大数据迁移,需要停服切换
- nosql解决了OLAP,以及scale out
- OLTP主动放弃,不赘述
- OLAP效率往往不如spark或是hadoop这样专用的平台
- scale out 则一般支持的超过关系型数据库sharding
经典的产品推荐:vitess,mongodb,都为开源产品,且代码质量不错
在下篇中将重点介绍下newSql 类产品,如google spanner等,敬请期待。