什么情况下,需要使用分布式数据库?

转载于:https://www.zhihu.com/question/30934556

目前,服务器的磁盘和内存,cpu都相对较好,一台数据库服务器可以存储好几亿条的数据,在一个什么样的情况下,应该考虑分布式数据库的,百亿?千亿?

如果单机数据库,直接通过分布式数据库来访问,分布式数据库是否能够提高数据库的效率呢?
数据库分库后,一些复杂的sql场景,会比较难处理,而且分库之后,sql除了查询分库的数据外,还要进行数据合并操作,那是否是说不分库,比分库更好一些呢?

分别回答下,题主的三个问题:

1. 目前,服务器的磁盘和内存,cpu都相对较好,一台数据库服务器可以存储好几亿条的数据,在一个什么样的情况下,应该考虑分布式数据库的,百亿?千亿?

考虑用分布式数据库,肯定是容量或者性能方面,现有的单机数据库满足不了业务的需求。当然,遇到了容量或者性能的问题,也不一定要用分布式数据库,可以通过scale-up的方式,即升级数据库服务器的CPU、内存、磁盘,将SATA/SAS盘换SSD盘等方式解决。不过相对scale-up来说, 分布式数据库这种scale-out的方式,扩展性会更强一些,一般来说也更具性价比。

普通的X86服务器,一台数据库服务器存好几亿条数据,问题不大,但前提是需要分库或分表,单表几亿条数据,普通服务器基本支撑不了的,毕竟数据量一大,表对应的B树层次就高,写入时B树节点的分裂和调整,开销也大。同时,上亿规模下,单台数据库服务器的恐怕不能支持密集的读请求,性能可能会有问题。

2. “如果单机数据库,直接通过分布式数据库来访问,分布式数据库是否能够提高数据库的效率呢?”

题主这里所说的分布式数据库, 应该是指数据库中间件这样的软件吧。目前比较流行的一种做法,是DBA利用开源中间件,结合自己项目的mysql或pg数据库,来搭建出一套分布式数据库的解决方案。主要的方法有两种:

一种是水平拆分。当数据量大到单机数据库已存储不下时, 可以对数据进行拆分,化整为零,将数据均匀分布到多个数据库节点中。由于对数据进行了拆分,每个数据库节点上的数据量小了,自然读写性能就提高了。

另一种是读写分离。这种方法,主要用在数据量并不大,单机数据库能够hold得住,但读请求很高的情况下。此时,可以配置多个只读数据库节点,来分担主节点的读请求。通过数据复制机制,在主节点和只读节点之间进行数据的实时同步,保证主从节点的数据一致性。

两种方法很好地解决了数据库的容量和性能问题。当然,使用了中间件,相当于在sql的执行路径上,多了一个处理环节,因此单条sql的延时,相对于直连数据库节点,在非满负载的情况下,肯定是要高的。但在实际的业务访问中,sql的性能瓶颈,一般都出在数据库节点上,中间件只是做单纯的sql解析和路由,性能开销不会很大。因此,通过增加数据库节点,提升sql处理的短板,是能够提高系统效率的。

3.“数据库分库后,一些复杂的sql场景,会比较难处理,而且分库之后,sql除了查询分库的数据外,还要进行数据合并操作,那是否是说不分库,比分库更好一些呢?”

基于中间件来进行分库, 确实对 SQL 有阉割的情况,并不是所有sql都能够支持。主要原因是数据被拆分了。而数据一旦被拆分到多个节点,则:
1.复杂的join查询
2. 同时更新多个数据库节点的sql语句
这两类SQL的支持难度,就比较高。这也是目前市面上所有中间件都无法满足的两点。复杂的join查询之所以难以支持,是因为要跨节点join;同时更新多个节点的sql难以支持,是因为很难解决多个节点的并发一致性问题。但是除了这两点之外,其他的sql类型,一款中间件是能够努力做到的。

从中间件实现的角度,我们来对sql做一个分析,以说明这一点。

1. 按操作范围的维度,可以把所有的SQL,分为3类:
1.1 kv类的sql: 这种sql操作很简单,就是简单的set/put某个表的一条记录,大部分insert/delete/update语句,和指定primary key/key的select,都属于这种类型。
1.2 范围更新/查询:这种sql不局限于操作一条记录,但还是作用于一张表。比如update多行记录,或者select某个时间范围的记录等。
1.3 多表join查询:又包括两种:
1.3.1 分库分表键都是同一个的多表join:由于采用同一个划分键,因此join操作其实是发生在单节点
1.3.2 分库分表键不是同一个的多表join: 此时涉及到跨节点的join,实现复杂

2.按是否要在关系运算之后,还要对结果进行聚合,把select sql分为两类:
2.1 不需要进行结果聚合,即select sql中没有集函数、group by、order by、limit等需要在关系运算之后,再对结果进行处理和聚合;
2.2 包括上述结果聚合语法的select sql

3.从是否对分布式事务有要求的角度,可以把SQL分为两类:
3.1 只读写一个节点的sql,无分布式事务要求
3.2 跨多个节点读写的sql,有分布式事务要求

根据之前所述, 目前的业内的中间件,都不能支持1.3.2 和3.2(mycat对分布式事务的支持,只支持最终一致性,还是一个伪支持;阿里DRDS号称内测版本支持分布式事务,但一直未见公测),而除去这两点,对于类型(1.1, 1.2, 1.3.1) × (2.1,2.2)得到的6种sql类型,理论上讲,中间件都是可以做到支持的。
对于OLTP应用来讲,这6种类型能够覆盖绝大部分的业务场景,这也是中间件技术这几年这么流行的原因。遗憾的是,目前业内的各大中间件, 对这6种类型的sql,支持程度往往都有一定的折扣。比如对于这样一条操作单表的sql:

select distinct id, avg(price) from t1 where id>=1 group by concat(id,name) order by avg(price) limit 10;

目前主流的几款中间件,似乎就不能支持。

目前,UCloud 的 UDB 团队,也在打造一款基于中间件和 UDB 的,分布式数据库产品 UDDB,协议和SQL语法,全面兼容MYSQL。我们从零开始,但目标远大。正如 UCloud 一直强调的,用户的需求是我们下一款产品。我们的第一个目标,是做一款业内最好用的分布式数据库,解决用户在使用mysql中间件构建分布式解决方案时的痛点:学习成本高,配置复杂,运维麻烦,扩容不方便。

在系统管理上,UDDB将做到一步创建,开箱即用,无需额外的管理和配置操作,并提供全自动化,无需停服的水平扩展/缩容操作;SQL支持上,我们将对类型(1.1, 1.2, 1.3.1) × (2.1,2.2)这6种sql,进行全面的支持,让用户在遇到带avg集函数、group by,order dy的select sql时, 无需担忧系统是否支持,即可放心使用。

预计在今年9月底,UDDB将开放内测,敬请大家关注。

长期来看,打造这样一款分布式数据库服务,是我们和客户交流,探索未来的一种方式。诚然,相对于 Google F1,Oceanbase 等全新设计的分布式数据库产品, 基于中间件的分布式数据库,在技术上并非最前沿,但是我们相信,这是广大客户目前正需要的。我们相信只有先服务好用户,深入到用户的需求当中,根据用户需求不断迭代,同时团队自身不断成长,才能真正理解公有云环境下,用户对分布式数据库的需求,才能做出接地气和广受欢迎的产品。
  • 几亿跳记录根本不算什么,几年前的个人电脑,mysql标准版本单机优化好设置,几十亿的数据库能玩很好。如果是你说的kv类的数据和查询,几亿数据基本是我们开发中的单机测试用例规模,是不需要个人电脑的,目前旗舰手机运行一个可以的系统就能玩。
  个人电脑单表几十亿条记录? 请问当时读写qps是多少?
  • 知乎用户回复robert (作者)3 年前
  你是ucolud ?
  • 亿的记录,单列的index是10GBytes数量级,单表index放内存里完全没有问题。mysql和postgresql标准非修改版,都没有问题的。我的观点是,你提到的一个数据库数亿记录,这是小规模项目常见的,多数情况下,不需要什么分库分表。
  • robert (作者) 回复我做分布式系统3 年前
    老兄说的数亿记录的小项目,应该是指olap类型的项目吧?oltp场景,一个表数亿条记录,普通服务器,你敢不分表直接开搞?
  • 您的原文我引用如下”普通的X86服务器,一台数据库服务器存好几亿条数据,问题不大,但前提是需要分库或分表“,一个数据库几亿,和一个表几亿,咱们先区分一下。单表单列一个索引,家用台式机就能跑。KV类型访问的数据,转到一个NoSQL系统,比如lmdb,2016旗舰手机就能跑。
  •  robert (作者) 回复我做分布式系统3 年前
    好吧,是的,我这里措辞不够严谨。但是一般来说,提到分布式数据库,分库分表场景,潜台词肯定是指一张表,而不是一个数据库的多张表。只有大表才有划分的需求,否则一个数据库里面都是几百万的小表,总和几个亿,又何来分库分表的的需求? 另外,从上下文来看,我们这边探讨的,肯定是基于实际项目,关系型数据库,而且是oltp场景,所以qps和延时是必须考虑进去的。 至于老兄提到的单表单列,和Nosql系统,未免又有点发散啦。
  • 题主没有提OLTP/OLAP,大数据时代,OLAP不是二等公民。 :)

什么情况下,需要使用分布式数据库?

上一篇:使用宝塔面板配置webhook,自动拉取码云代码


下一篇:mysql binlog数据恢复