我们说Mysql单表能存的最大数据量自然不是能存的最大数据量。如果是最大可以存储的量,那么如果使用自增ID,最多可以存储2^32或2^64条记录,根据自增的数据类型int或bigint计算ID;如果不使用自增id,并且id的最大值没有限制,比如使用足够长度的随机字符串,那么唯一能限制单表最大数据量的就是磁盘空间。显然我们不是在讨论这个问题。影响Mysql单表最优和最大个数的一个重要因素其实就是索引。我们知道,Mysql的主要存储引擎InnoDB采用的是B+树结构索引。(至于为什么Mysql选择b+树而不是其他数据结构来组织索引,不是本文讨论的话题,后面的文章会讲)那么B+树索引是如何影响Mysql单表数据量的?B+树是一棵B+树,如下所示:Mysql的B+树索引存储在磁盘上,Mysql从磁盘中读取的每页大小为16KB。为了保证每次查询的效率,需要保证每次查询访问磁盘的次数,一般设计为2-3次磁盘访问,再多了性能会严重不足。MysqlB+树索引的每个节点都需要存储一个指针(8Byte)和一个键值(8Byte)。因此计算16KB/(8B+8B)=1K16KB可以存储1K个节点,3次磁盘访问(即B+树深度3)可以存储1K_1K_1K即10亿条数据。如果查询依赖于非主键索引,则还涉及二级索引。这样数据量会更小。分裂分而治之——没有分裂一次解决不了的问题,也没有分裂多次解决不了的问题。单个Mysql表存储的数据量是有限的。存储大量数据的一种解决方案是分库分表。说白了就是一个库一张表装不了那么多数据,所以分多库多表存储。拆分可分为垂直拆分和水平拆分。垂直拆分是根据不同的表(或模式)将数据拆分到不同的数据库(主机),水平拆分是根据表中数据的逻辑关系,将同一张表中的数据按一定条件拆分。拆分为多个数据库(主机)或拆分为同一架构的不同表。垂直拆分最大的特点就是规则简单,实现起来也比较方便。特别适用于业务之间耦合度很低,相互影响很小,业务逻辑非常清晰的系统。在本系统中,很容易将不同业务模块使用的表拆分到不同的数据库中。按照不同的表拆分对应用的影响更小,拆分规则也会更简单明了。水平拆分比垂直拆分稍微复杂一些。因为需要将同一张表的不同数据拆分到不同的数据库中,对于应用来说,拆分规则本身比根据表名拆分要复杂,后期的数据维护也会更加复杂。垂直拆分最直接的方式就是按域拆分服务,隔离域数据库。这样一来,减轻了各个图书馆的数据压力。水平拆分就是将同一个schema的数据拆分到不同的库或者不同的表中,这样每个表的数据量也会减少,查询效率会更高。水平拆分涉及分表规则。几种典型的分片规则包括:根据用户ID取模,将数据分布到不同的数据库中,将具有相同数据的用户的数据全部分布到一个数据库中。根据日期,将不同月份甚至不同日期的数据分散到不同的库中。按照特定的领域进行检索,或者按照特定的范围分散到不同的库中。实现Facade模式——没有什么问题是加个中间层解决不了的。垂直拆分的一种解决方案是在应用层使用多个数据源,并根据业务访问不同的数据源。另一个更好的解决方案其实是微服务。根据不同的业务领域拆分微服务,明确领域边界,隔离领域数据库。通过这种方式,将数据的访问内聚集成到独立的服务中,对外提供统一的接口。当我们需要同时依赖多个服务时,可以通过增加门面应用的方式,将底层服务的数据结合起来,提供一个更好满足上层业务需求的接口。这些服务通常更贴近实际业务。底层服务是更具凝聚力的资源服务。ProxyPattern——没有什么问题是加个中间层解决不了的。对于水平拆分,尽量屏蔽拆分带来的数据访问麻烦,让上层业务无需关心下层数据组织。水平拆分通常通过添加代理层来完成这些事情。代理层在上层提供虚拟表。这些虚拟表就像我们在单个数据库上设计的单个表一样;代理层对下层进行sql解析拆分,然后根据相应的规则在不同的库和表中执行相应的sql请求,然后合并数据,并将合并后的结果返回给上层调用者。一般的代理方式分为以下两种:进程内代理进程内代理将代理层嵌入到业务服务中,拦截SQL请求并进行相应的处理。这样做的好处是简单,但是有侵入性,不够灵活。进程外代理进程外代理就是把代理分离成一个服务,代理真正的业务服务和数据库之间的请求。这个比较复杂,需要高可用的代理服务架构。但这对业务的侵入性较小,易于升级和扩展。Question分布式事务问题什么是分布式事务?本地事务的定义是在一个分布式事务完成后,一系列相关的数据库操作必须满足ACID的四个特性。同一个进程的操作放在不同的微服务进程中。即不同微服务应用进程的数据库操作满足事务需求,或者对不同数据库的一系列操作需要满足事务需求。这里有两个问题需要解决。一个是分布式应用造成的,一个是分布式数据库本身造成的。数据库本身的分布式事务问题,一般由数据库自己解决。大多数分布式数据库都能保证一定的数据一致性,比如HBase保证的强一致性,Cassandra保证的最终一致性。我们也可以参考分布式数据库的实现原理来实现应用数据的一致性事务方案。业界对于分布式事务的解决方案也有很多,比如:XA方案TCC方案本地消息表可靠消息最终一致性方案besteffort通知方案多表join问题通过分析joinsql,将sql拆分成独立的查询请求,然后执行,将合并后的计算结果返回给调用方。这个地方会涉及到很多执行优化的问题。数据统计问题当数据被分片到不同的数据库或者不同的表中,在对数据做一些全局的统计或者涉及到大量的数据时会遇到一些问题。比如求Max、Min、Sum等聚合问题。如果统计数据有一定的业务规则,比如只按照用户维度统计,比如统计某个用户的订单量,那么订单表的分片实际上可以按照用户id分片,这样可以解决问题这样的统计问题。但这个解决方案并不通用。很多shardingproxy服务需要将sql分片到不同的节点执行,然后再将结果合并回来。ID问题分库分表后,Mysql表自增不能作为id使用,因为不同库分表的自增会出现id冲突。要解决这个问题,就需要引入分布式id生成技术。
