当我们说Mysql单表适合存储最大数据量时,自然不是指可以存储的最大数据量。如果说可以存储的最大数量,那么,如果使用自增ID,最多可以存储2 ^ 32或2 ^ 64条记录,根据自增ID的数据类型int或bigint计算;如果不使用自增id,并且对最大id没有限制,比如使用长度足够的随机字符串,那么就只剩下disk 空来限制单个表的最大数据量。显然,我们不是在讨论这个问题。
影响Mysql单表最优最大数量的一个重要因素其实是索引。我们知道Mysql的主要存储引擎InnoDB使用的是B+树形结构索引。(至于Mysql为什么选择b+ tree而不是其他数据结构来组织索引,不是本文讨论的话题,后面的文章会涉及到。那么B+树索引是如何影响Mysql单表的数据量的呢?
Mysql在单个表中存储的数据量有限。存储大量数据的一个解决方案是将数据库分成多个表。说白了,一个数据库一个表容纳不了这么多数据,所以可以存放在多个数据库和表中。
拆分可以分为垂直拆分和水平拆分。
垂直拆分是根据不同的表(或模式)拆分到不同的数据库(主机)中,而水平拆分是根据表中数据的逻辑关系,将同一表中的数据按照一定的条件拆分到多个数据库(主机)或具有相同模式的不同表中。
垂直拆分最大的特点就是规则简单,实现更方便。特别适用于业务间耦合度非常低、相互影响很小、业务逻辑非常清晰的系统。在这个系统中,很容易将不同业务模块使用的表拆分到不同的数据库中。根据不同的表进行拆分,对应用的影响会更小,拆分规则会更简单明了。
水平拆分比垂直拆分稍微复杂一点因为同一个表中的不同数据要拆分到不同的数据库中,所以拆分规则本身对于应用来说比按照表名拆分更复杂,后期的数据维护也会更复杂。
垂直拆分最直接的方法就是按域拆分服务,隔离域数据库。这样就减轻了各个库承担的数据压力。
水平拆分就是将同一个模式的数据拆分到不同的库或者不同的表中,这样每个表中的数据量也会减少,查询效率也会更高效。水平拆分涉及到表碎片规则的问题。
门面模式——没有加个中间层解决不了的问题。
垂直拆分的一种方案是在应用层使用多个数据源,根据业务访问不同的数据源。另一个比较好的解决方案其实是微服。根据不同的业务领域拆分微服务,定义领域边界,隔离领域数据库。通过这种方式,对数据的访问被融合到独立的服务中,为外部世界提供了一个统一的接口。当我们需要同时依赖多个服务时,可以通过添加facade应用来组合底层服务的数据,提供更符合上层业务需求的接口,这些服务也更趋向于真实的业务。底层服务是更有凝聚力的资源服务。
分布式事务问题
什么是分布式事务?本地事务的定义是一系列相关的数据库操作完成后必须满足ACID的四个特性,而分布式事务是同一进程的操作放到不同的微服务进程中,即不同微服务应用进程的数据库操作满足事务需求,或者不同数据库的一系列操作需要满足事务需求。
这里有两个问题需要解决。一个是由于应用程序的分布,另一个是由于数据库本身的分布。一般数据库本身的分布式事务问题都是数据库自己解决的。大多数分布式数据库都能保证一定的数据一致性,比如HBase保证的强一致性,Cassandra保证的最终一致性。
我们也可以参考分布式数据库的实现原理来实现数据一致性事务方案。业内也有很多分布式交易的解决方案,比如:
XA 方案TCC 方案本地消息表可靠消息最终一致性方案最大努力通知方案
多表连接问题
通过分析Join sql,将sql拆分成独立的查询请求,然后分别执行,将结果合并计算后返回给调用者。这个地方会涉及到很多优化问题。
数据统计问题
当数据被碎片化到不同的数据库或者不同的表中,在做一些全局的统计或者涉及到大量数据的时候,就会出现一些问题。求最大、最小、求和等聚合问题。如果统计数据有一定的业务规则,比如只按用户维度统计,比如统计某个用户的订单数量,那么订单表其实可以按用户id切片,可以解决这类统计问题。但是这个方案并不通用。很多分片代理服务需要将sql分片到不同的节点上执行,然后合并结果返回。
ID问题
使用子库和子表后,不能使用Mysql的表自动增量作为id,因为不同库和表的自动增量会有id冲突。为了解决这个问题,我们需要引入分布式id生成技术。