转 https://blog.csdn.net/sinat_23490433/article/details/89247526
互联网当下,数据库的拆分过程基本遵循的顺序是:垂直拆分、读写分离、水平拆分(也称之为分库分表)。
一、垂直拆分
1、什么是垂直拆分?
指的是将一个包含了很多表的数据库,根据表的功能的不同,拆分为多个小的数据库,每个库中包含部分表。
比如:电商系统采用的库为db_eshop,根据用户功能和产品功能,可以拆分为用户库db_user和产品库db_product。
2、什么时候使用垂直拆分?
刚开始,可能公司的技术团队规模比较小,所有的数据都存放在一个库中。
随着公司业务的发展,技术团队人员扩张,划分为不同的技术小组,不同的小组负责不同的业务模块。
如:A小组负责用户模块,B小组负责产品模块。此时可以将数据库进行垂直拆分。
3、垂直拆分的好处?
垂直拆分会使得单个用户请求的响应时间变长,但是会使得整个服务的吞吐量大大的增加。(服务吞吐量即系统在单位时间内处理请求的数量)
使得单个用户请求的响应时间变长的原因在于:在单体应用场景下,所有的业务都在一个节点内部完成,而垂直拆分后,通常会需要进行rpc调用,rpc的调用会加长单个用户请求的响应时间。
4、垂直拆分的另外2种用途?
1)、将一个包含了很多字段的大表拆分为多个小表,每个表中包含部分字段(基本很少遇到)
2)、进行服务化(SOA)的改造,除了业务上需要进行拆分,底层的存储也需要进行隔离
二、读写分离
1、什么是读写分离?
将数据库分为主库和从库,一个主库用于写数据,多个从库完成读数据的操作。
主从库通过某种机制进行数据的同步。
2、为什么需要使用读写分离?
随着业务的不断发展,用户数量和并发量不断上升,此时如果仅靠单个数据库实例来支撑所有的访问压力,数据库将难以支撑。
比如:产品库中,包含了几万种产品数据,并且每天新增几十条产品数据,而产品库每天的访问可能有几亿甚至几十亿次,数据库读的压力太大,单台mysql实例扛不住。此时可以将数据库进行读写分离,主库负责数据写的操作,多个从库负责数据读的操作。
注:说白了,读写分离是为了解决数据库读的操作。
3、数据库进行了读写分离配置后,开发人员需要做哪些事情?
DBA将mysql配置成主从复制,开发人员需要做如下事情:
1)、更新数据库数据时,应用将数据写入到master主库
2)、主库将数据同步给多个slave从库
3)、当查询数据时,应用选择某一个slave节点读取数据。
4、读写分离的优点?
通过配置多个从库,可以有效的避免过大的访问量对单个库造成的压力。
5、读写分离技术所面临的问题有哪些?
读写分离的基本操作,是对sql类型进行判断,如果是select等读的请求,就走从库.
如果是insert、update、delete等写的请求,就走主库。
1)、主从数据同步延迟的问题
因为数据是从主节点通过网络同步给多个从 节点的,因此必然存在延迟问题。
因此可能出现如下问题:我们在主节点中插入了数据,但是从节点却读取不到数据的问题。
对于一些强一致性的业务场景,要求插入数据后必须能读取到,对于这种情况,我们需要提供一种方式,让读的请求也可以走主库,而主库上的数据必然是最新的。
2)、事务问题
如果一个事务中同时包含了读的请求和写的请求,如果读的请求走从库,写的请求走主库。由于跨了多个库,那么本地事务已经无法控制。
而分布式事务非常复杂且效率较低,因此读写分离,目前主流的做法是:将事务中所有sql统一走主库,由于只涉及到一个库,本地事务可以解决。
综上所述:垂直拆分可以解决服务吞吐量即提高系统在单位时间内处理请求的数量
读写分离可以缓解单库的压力,增强用户并发访问量
即经过垂直拆分和主从同步的数据库完全可以承受住难以想象的高并发访问操作。
三、水平拆分
1、什么是水平拆分(分表分库)?
通过一种算法,将数据库进行分割的架构。每个分片中的数据没有重合,所有分片中的数据并集组成全部数据。
水平分表实际又可以分为如下三种:只分表、只分库、分库分表
1)、只分表:将db库中的user表拆分为2个分表,即uer_0和user_1
2)、只分库:将db库差费为db_0和db_1这2个库,同时在db_0和db_1库中各自新建一个user表,db_0.user表和db_1.user表中各自只存放原来的db.user表中的部分数据
3)分库分表:将db库拆分为db_0和db_1这2个库,db_0中包含user_0、user_1这2个分表,db_1中包含user_2、user_3这2个分表。
2、为什么需要进行分表分库?
一旦业务表中的数据量比较大,从维护和性能的角度来看,仍然无法掩盖因为数据量过大从而导致数据库性能下降的事实。因此,这个时候mysql DBA就该对数据库进行水平分区,经过水平分区设置后的业务表,必然能够将原本一张表维护的海量数据分配给N个子表进行存储和维护。
即:单库容量最容易成为性能瓶颈,当单库容量成为瓶颈,我们希望提高数据库的写的性能,降低单库容量的话,就可以使用水平切分。
3、分表分库的使用场景?
如果库中的多个表中只有某张表或者少量表数据量过大,那么只需要针对这些表进行拆分,其它表保持不变。
4、分库分表的好处?
如果说读写分离实现数据库读能力的水平提升
那么,分库分表是是实现数据库写能力的水平提升
1)、存储能力的水平扩展
在读写分离的情况下,每个集群中的主从库基本上数据时完全一致的,从存储能力上讲
在存储海量数据的情况下,可能由于磁盘空间的限制,无法存储所有的数据。
而分库分表的情况下,我们可以搭建多个mysql主从复制集群,每个集群只存储部分分片的额数据,实现了存储能力的水平扩展。
2)、写能力的水平扩展
在读写分离的情况下,由于每个集群只有一个master,所有的写操作的压力都集中在这一个节点上,在写入并发非常高的情况下,这将会成为整个系统的瓶颈。
而在分表分库的情况下,每个分片所属的集群都有一个master节点,都可以执行写入的操作,实现写能力的水平扩展,此外减小建立索引开销,降低写操作的锁操作耗时等,都会带来很多显著的好处。
5、分库分表的问题
主要体现在如下4个方面:基本数据的增删改功能、分布式id、分布式事务、动态扩容
1)、基本的数据库增删改功能
对于开发人员而言,虽然分库分表的,但是其还是希望能和单库单表那样去操作数据库。
如:我们要批量插入4条记录,并且希望根据用户的id字段,确定这条记录插入哪个库的那张表中。如:1号记录插入user1表….4号记录插入user4表
那么之前的单库作如下:
insert into user(id,name) values (1,”tianshouzhi”),(2,”huhuamin”), (3,”wanghanao”),(4,”luyang”)
这显然无法实现,因为我们已经对库和表进行了拆分,这种sql语法只能操作mysql的单个库和单个表,所以必须将sql改为4条,然后分表到每个库上去执行,如下:
insert into user0(id,name) values (4,”luyang”)
insert into user1(id,name) values (1,”tianshouzhi”)
insert into user2(id,name) values (2,”huhuamin”)
insert into user3(id,name) values (3,”wanghanao”)
2)、分布式id
在分库分表后,我们不能再使用mysql的自增主键。
因为在插入记录的时候,不同的库生成的记录的自增id可能会出现冲突
因此,需要一个全局的id生成器,目前分布式id有很多种方案,其中一个比较轻量级的方案是twitter的snowflake算法。
3)、分布式事务
分布式事务是分库分表的绕不过去的一个坎,因为涉及到了同时更新多个分片数据。
如:批量插入记录到四个不同的库,如何保证要么同时成功,要么同时失败。
关于分布式事务,mysql支持XA事务,但是效率较低。
柔性事务是目前比较主流的方案,柔性事务包括:最大努力通知型、可靠消息最终一致性方案以及TCC两个阶段提交。
但是无论XA事务还是柔性事务,实现起来都是非常复杂的。
4)、动态扩容
动态扩容是指只增加分库分表的数量
如:将原来user表拆分到2个库的四张表上。
现在我们希望将分库的数量变为4个,分表的数量变为8个。
这种情况一般要伴随着数据迁移,如在4张表的情况下,id为7的记录,7%4=3
因此这条记录位于user3这张表上,但是现在分表的数量变为8个,而7%8=0
而user0这张表根本没有id=7这条记录,因此如果不进行数据迁移的话,就会出现记录找不到的情况。