1数据库架构
单库单表
单库单表是最常见的数据库设计,例如,有一张用户(user)表放在数据库db中,所有的用户都可以在db库中的user表中查到。
单库多表
随着用户数量的增加,user表的数据量会越来越大,当数据量达到一定程度的时候对user表的查询会渐渐的变慢,从而影响整个DB的性能。如果使用mysql,还有一个更严重的问题是,当需要添加一列的时候,mysql会锁表,期间所有的读写操作只能等待。
可以通过某种方式将user进行表水平的切分,产生两个表结构完全一样的user_0000,user_0001等表,user_0000+user_0001+…的数据刚好是一份完整的数据。
多库多表
随着数据量增加也许单台DB的存储空间不够,随着查询量的增加单台数据库服务器已经没办法支撑。这个时候可以再对数据库进行水平区分。
路由
通过分库分表规则查找到对应的表和库的过程。
如分库分表的规则是user_idmod4的方式,当用户新注册了一个账号,账号id的123,我们可以通过idmod4的方式确定此账号应该保存到User_0003表中。当用户123登录的时候,我们通过123mod4后确定记录在User_0003中。
1、一主多备
在实际的应用中,绝大部分情况都是读远大于写。Mysql提供了读写分离的机制,所有的写操作都必须对应到Master,读操作可以在Master和Slave机器上进行,Slave与Master的结构完全一样,一个Master可以有多个Slave,甚至Slave下还可以挂Slave,通过此方式可以有效的提高DB集群的QPS.
所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。
此外,可以看出Master是集群的瓶颈,当写操作过多,会严重影响到Master的稳定性,如果Master挂掉,整个集群都将不能正常工作。加一个Master是不能解决问题的, 因为数据要保存一致性,写操作需要2个master之间同步,相当于是重复了,而且更加复杂。
这时就需要用到分库分表(sharding),对写操作进行切分。
所以,
- 当读压力很大的时候,可以考虑添加Slave机器的分式解决,但是当Slave机器达到一定的数量就得考虑分库了。
- 当写压力很大的时候,就必须得进行分库操作。
MySQL的主从复制解决了数据库的读写分离,并很好的提升了读的性能,其图如下:

其主从复制的过程如下图所示:

但是,主从复制也带来其他一系列性能瓶颈问题:
- 写入无法扩展
- 写入无法缓存
- 复制延时
- 锁表率上升
- 表变大,缓存率下降
那问题产生总得解决的,这就产生下面的优化方案,一起来看看。
2分库分表的方式方法
2.1、什么是分库分表?
数据分片,指按照某个维度将存放在单一数据库中的数据分散地存放至多个数据库或表中以达到提升性能瓶颈以及可用性的效果。数据分片的有效手段是对关系型数据库进行分库和分表。
- 分库和分表均可以有效的避免由数据量超过可承受阈值而产生的查询瓶颈。除此之外,分库还能够用于有效的分散对数据库单点的访问量。
- 分表虽然无法缓解数据库压力,但却能够提供尽量将分布式事务转化为本地事务的可能,一旦涉及到跨库的更新操作,分布式事务往往会使问题变得复杂。
- 使用多主多从的分片方式,可以有效的避免数据单点,从而提升数据架构的可用性。
通过分库和分表进行数据的拆分来使得各个表的数据量保持在阈值以下,以及对流量进行疏导应对高访问量,是应对高并发和海量数据系统的有效手段。数据分片的拆分方式又分为垂直分片和水平分片。
一般就是垂直切分和水平切分,这是一种结果集描述的切分方式,是物理空间上的切分。 我们从面临的问题,开始解决,阐述:
首先是用户请求量太大,我们就堆机器搞定。
然后是单个库太大,这时我们要看是因为表多而导致数据多,还是因为单张表里面的数据多。 如果是因为表多而数据多,使用垂直切分,根据业务切分成不同的库。
如果是因为单张表的数据量太大,这时要用水平切分,即把表的数据按某种规则切分成多张表,甚至多个库上的多张表。
分库分表的顺序应该是先垂直分,后水平分。 因为垂直分更简单,更符合我们处理现实世界问题的方式。
2.2、垂直拆分
垂直分表
也就是“大表拆小表”,基于列字段进行的。一般是表中的字段较多,将不常用的, 数据较大,长度较长(比如text类型字段)的拆分到“扩展表“。 一般是针对那种几百列的大表,也避免查询时,数据量太大造成的“跨页”问题。
垂直分库
垂直分库针对的是一个系统中的不同业务进行拆分,比如用户User一个库,商品Producet一个库,订单Order一个库。 切分后,要放在多个服务器上,而不是一个服务器上。为什么? 我们想象一下,一个购物网站对外提供服务,会有用户,商品,订单等的CRUD。没拆分之前, 全部都是落到单一的库上的,这会让数据库的单库处理能力成为瓶颈。按垂直分库后,如果还是放在一个数据库服务器上, 随着用户量增大,这会让单个数据库的处理能力成为瓶颈,还有单个服务器的磁盘空间,内存,tps等非常吃紧。 所以我们要拆分到多个服务器上,这样上面的问题都解决了,以后也不会面对单机资源问题。
数据库业务层面的拆分,和服务的“治理”,“降级”机制类似,也能对不同业务的数据分别的进行管理,维护,监控,扩展等。 数据库往往最容易成为应用系统的瓶颈,而数据库本身属于“有状态”的,相对于Web和应用服务器来讲,是比较难实现“横向扩展”的。 数据库的连接资源比较宝贵且单机处理能力也有限,在高并发场景下,垂直分库一定程度上能够突破IO、连接数及单机硬件资源的瓶颈。
2.2.1、MySQL垂直分片
按照业务拆分的方式称为垂直分片,又称为纵向拆分,它的核心理念是专库专用,而且万一其中一个业务崩溃了也不会影响其他业务的正常进行,并且也起到了负载分流的作用,大大提升了数据库的吞吐能力。经过垂直分区后的数据库架构图如下:

然而,尽管业务之间已经足够独立了,但是有些业务之间或多或少总会有点联系,如用户,基本上都会和每个业务相关联,况且这种分区方式,也不能解决单张表数据量暴涨的问题,因此为何不试试水平分割呢?
垂直拆分的优点:
- 库表职责单一,复杂度降低,易于维护。
- 单库或单表压力降低。 相互之间的影响也会降低。
垂直拆分的缺点:
- 部分表关联无法在数据库级别完成,需要在程序中完成。
- 单表大数据量仍然存在性能瓶颈。
- 单表或单库高热点访问依旧对 DB 压力非常大。
- 事务处理相对更为复杂,需要分布式事务的介入。
- 拆分达到一定程度之后,扩展性会遇到限制。
2.3、水平拆分
水平分表
针对数据量巨大的单张表(比如订单表),按照某种规则(RANGE,HASH取模等),切分到多张表里面去。 但是这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈。不建议采用。
水平分库分表
将单张表的数据切分到多个服务器上去,每个服务器具有相应的库与表,只是表中数据集合不同。 水平分库分表能够有效的缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件资源等的瓶颈。
水平分库分表切分规则
-
RANGE
从0到10000一个表,10001到20000一个表; -
HASH取模
一个商场系统,一般都是将用户,订单作为主表,然后将和它们相关的作为附表,这样不会造成跨库事务之类的问题。 取用户id,然后hash取模,分配到不同的数据库上。 -
地理区域
比如按照华东,华南,华北这样来区分业务,七牛云应该就是如此。 -
时间
按照时间切分,就是将6个月前,甚至一年前的数据切出去放到另外的一张表,因为随着时间流逝,这些表的数据 被查询的概率变小,所以没必要和“热数据”放在一起,这个也是“冷热数据分离”。
2.3.1、MySQL水平分片(Sharding)
水平分片又称为横向拆分。 相对于垂直分片,它不再将数据根据业务逻辑分类,而是通过某个字段(或某几个字段),根据某种规则将数据分散至多个库或表中,每个分片(shard)仅包含数据的一部分。这样随着用户数量的增加,只要简单地配置一台服务器即可,原理图如下:

如何来确定某个用户所在的shard呢,可以建一张用户和shard对应的数据表,每次请求先从这张表找用户的shard id,再从对应shard中查询相关数据,如下图所示:

水平拆分的优点:
- 解决单表单库大数据量和高热点访问性能遇到瓶颈的问题。
- 应用程序端整体架构改动相对较少。
- 事务处理相对简单。
- 只要切分规则能够定义好,基本上较难遇到扩展性限制。
水平拆分缺点:
- 拆分规则相对更复杂,很难抽象出一个能够满足整个数据库的切分规则。
- 后期数据的维护难度有所增加,人为手工定位数据更困难。
- 产品逻辑将变复杂。比如按年来进行历史数据归档拆分,这个时候在页面设计上就需要约束用户必须要先选择年,然后才能进行查询。
3分库分表产生的问题,及注意事项
1.分库分表维度的问题
假如用户购买了商品,需要将交易记录保存取来,如果按照用户的纬度分表,则每个用户的交易记录都保存在同一表中,所以很快很方便的查找到某用户的购买情况,但是某商品被购买的情况则很有可能分布在多张表中,查找起来比较麻烦。反之,按照商品维度分表,可以很方便的查找到此商品的购买情况,但要查找到买人的交易记录比较麻烦。
所以常见的解决方式有:
a.通过扫表的方式解决,此方法基本不可能,效率太低了。
b.记录两份数据,一份按照用户纬度分表,一份按照商品维度分表。
c.通过搜索引擎解决,但如果实时性要求很高,又得关系到实时搜索。
2.联合查询的问题
联合查询基本不可能,因为关联的表有可能不在同一数据库中。
3.避免跨库事务
避免在一个事务中修改db0中的表的时候同时修改db1中的表,一个是操作起来更复杂,效率也会有一定影响。
合理采用分表,可以在降低单表数据量的情况下,尽量使用本地事务,善于使用同库不同表可有效避免分布式事务带来的麻烦。
要达到这个效果,需要尽量把同一组数据放到同一组 DB 服务器上。
例如说,将同一个用户的订单主表,和订单明细表放到同一个库,那么在创建订单时,还是可以使用相同本地事务。
在不能避免跨库事务的场景,有些业务仍然需要保持事务的一致性。而基于 XA 的分布式事务由于在并发度高的场景中性能无法满足需要,并未被互联网巨头大规模使用,他们大多采用最终一致性的柔性事务代替强一致事务。
4.尽量把同一组数据放到同一DB服务器上
例如将卖家a的商品和交易信息都放到db0中,当db1挂了的时候,卖家a相关的东西可以正常使用。也就是说避免数据库中的数据依赖另一数据库中的数据。
MySQL使用为什么要分库分表
可以用说用到MySQL的地方,只要数据量一大,马上就会遇到一个问题,要分库分表.
这里引用一个问题为什么要分库分表呢?MySQL处理不了大的表吗?
其实是可以处理的大表的.
但这种方式可以说不是一个最佳方式.因为面临文件系统如Ext3文件系统对大于大文件处理上也有许多问题.
这个层面可以用xfs文件系统进行替换.但MySQL单表太大后有一个问题是不好解决:表结构调整相关的操作基
本不在可能.所以大项在使用中都会面监着分库分表的应用.
从Innodb本身来讲数据文件的Btree上只有两个锁,**叶子节点锁和子节点锁,**可以想而知道,当发生页拆分或是添加
新叶时都会造成表里不能写入数据.
所以分库分表还就是一个比较好的选择了.
那么分库分表多少合适
经测试在单表1000万条记录一下,写入读取性能是比较好的.这样在留点buffer,那么单表全是数据字型的保持在
800万条记录以下,有字符型的单表保持在500万以下.
如果按100库100表来规划,如用户业务:
500万100100=50000000万=5000亿记录.
本文围绕MySQL数据库展开,介绍了单库单表、单库多表、多库多表等数据库架构,阐述分库分表的方式,包括垂直拆分和水平拆分及其优缺点。同时指出分库分表会产生维度、联合查询、跨库事务等问题,并给出应对建议,还提及分库分表数量的参考标准。

6537

被折叠的 条评论
为什么被折叠?



