面试总被问分库分表怎么办?你能够这样怼他

整理了一些Java方面的架构、面试资料(微服务、集群、分布式、中间件等),有须要的小伙伴能够关注公众号【程序员内点事】,无套路自行领取程序员

更多优选面试

引言

微服务、分布式大行其道的当下,中、高级Java工程师面试题中高并发、大数据量、分库分表等已经成算法

了面试的高频词汇,这些知识不了解面试经过率不会过高。你能够不会用,但你不能不知道,就是这么sql

一种现状。技术名词大多晦涩难懂,不要死记硬背理解最重要,当你捅破那层窗户纸,发现其实它也就数据库

那么回事。网络

1、为何要分库分表

关系型数据库以MySQL为例,单机的存储能力、链接数是有限的,它自身就很容易会成为系统的瓶数据结构

颈。当单表数据量在百万以里时,咱们还能够经过添加从库、优化索引提高性能。一旦数据量朝着千万架构

以上趋势增加,再怎么优化数据库,不少操做性能仍降低严重。为了减小数据库的负担,提高数据库响并发

应速度,缩短查询时间,这时候就须要进行分库分表框架

2、如何分库分表

分库分表就是要将大量数据分散到多个数据库中,使每一个数据库中数据量小响应速度快,以此来提高数

据库总体性能。核心理念就是对数据进行切分(Sharding),以及切分后如何对数据的快速定位与整合。

针对数据切分类型,大体能够分为:垂直(纵向)切分和水平(横向)切分两种。

一、垂直切分

垂直切分又细分为垂直分库垂直分表

垂直分库

垂直分库是基于业务分类的,和咱们常听到的微服务治理观念很类似,每个独立的服务都拥有本身的

数据库,须要不一样业务的数据需接口调用。而垂直分库也是按照业务分类进行划分,每一个业务有独立数

据库,这个比较好理解。

在这里插入图片描述

垂直分表

垂直分表是基于数据表的列为依据切分的,是一种大表拆小表的模式。

例如:一个order表有不少字段,把长度较大且访问不频繁的字段,拆分出来建立一个单独的扩展表work_extend进行存储。

order表:

id workNo price describe .....
int(12) int(2) int(15) varchar(2000)

拆分后

order核心表:

id workNo price .....
int(12) int(2) int(15)

work_extend表:

id workNo describe .....
int(12) int(2) varchar(2000)

数据库是以行为单位将数据加载到内存中,这样拆分之后核心表大可能是访问频率较高的字段,并且字段

长度也都较短,能够加载更多数据到内存中,增长查询的命中率,减小磁盘IO,以此来提高数据库性能。

优势:

  • 业务间解耦,不一样业务的数据进行独立的维护、监控、扩展
  • 在高并发场景下,必定程度上缓解了数据库的压力

缺点:

  • 提高了开发的复杂度,因为业务的隔离性,不少表没法直接访问,必须经过接口方式聚合数据,
  • 分布式事务管理难度增长
  • 数据库仍是存在单表数据量过大的问题,并未根本上解决,须要配合水平切分
二、水平切分

前边说了垂直切分仍是会存在单表数据量过大的问题,当咱们的应用已经没法在细粒度的垂直切分时,依旧存在单库读写、存储性能瓶颈,这时就要配合水平切分一块儿了。

水平切分将一张大数据量的表,切分红多个表结构相同,而每一个表只占原表一部分数据,而后按不一样的条件分散到多个数据库中。

假如一张order表有2000万数据,水平切分后出来四个表,order_1order_2order_3order_4,每张表数据500万,以此类推。

order_1表:

水平切分又分有库内分表分库分表

库内分表

库内分表虽然将表拆分,但子表都仍是在同一个数据库实例中,只是解决了单一表数据量过大的问题,并无将拆分后的表分布到不一样机器的库上,还在竞争同一个物理机的CPU、内存、网络IO。在这里插入图片描述

分库分表

分库分表则是将切分出来的子表,分散到不一样的数据库中,从而使得单个表的数据量变小,达到分布式的效果。

优势:

  • 解决高并发时单库数据量过大的问题,提高系统稳定性和负载能力
  • 业务系统改造的工做量不是很大

缺点:

  • 跨分片的事务一致性难以保证
  • 跨库的join关联查询性能较差
  • 扩容的难度和维护量较大,(拆分红几千张子表想一想都恐怖)

3、数据该往哪一个库的表存?

分库分表之后会出现一个问题,一张表会出如今多个数据库里,到底该往哪一个库的表里存呢?

一、根据取值范围

按照时间区间ID区间来切分,举个栗子:假如咱们切分的是用户表,能够定义每一个库的User表里只存10000条数据,第一个库userId从1 ~ 9999,第二个库10000 ~ 20000,第三个库20001~ 30000......以此类推。

优势:

  • 单表数据量是可控的
  • 水平扩展简单只需增长节点便可,无需对其余分片的数据进行迁移
  • 能快速定位要查询的数据在哪一个库

缺点:

  • 因为连续分片可能存在数据热点,若是按时间字段分片,有些分片存储最近时间段内的数据,可能会被频繁的读写,而有些分片存储的历史数据,则不多被查询
二、hash取模

hash取模mod(对hash结果取余数 (hash() mod N))的切分方式比较常见,还拿User表举例,对数据库从0到N-1进行编号,对User表userId字段进行取模,获得余数ii=0存第一个库,i=1存第二个库,i=2存第三个库....以此类推。

这样同一个用户的数据都会存在同一个库里,用userId做为条件查询就很好定位了

优势:

  • 数据分片相对比较均匀,不易出现某个库并发访问的问题

缺点:

  • 但这种算法存在一些问题,当某一台机器宕机,本应该落在该数据库的请求就没法获得正确的处理,这时宕掉的实例会被踢出集群,此时算法变成hash(userId) mod N-1,用户信息可能就再也不在同一个库中。

4、分库分表后会有哪些坑?

一、事务一致性问题

因为表分布在不一样库中,不可避免会带来跨库事务问题。通常可以使用"XA协议"和"两阶段提交"处理,可是这种方式性能较差,代码开发量也比较大。

一般作法是作到最终一致性的方案,每每不苛求系统的实时一致性,只要在容许的时间段内达到最终一致性便可,可采用事务补偿的方式。

二、分页、排序的坑

平常开发中分页、排序是必备功能,而多库进行查询时limit分页、order by排序,着实让人比较头疼。

分页需按照指定字段进行排序,若是排序字段刚好是分片字段时,经过分片规则就很容易定位到分片的位置;一旦排序字段非分片字段时,就须要先在不一样的分片节点中将数据进行排序并返回,而后将不一样分片返回的结果集进行汇总和再次排序,最终返回给用户,过程比较复杂。

三、全局惟一主键问题

因为分库分表后,表中的数据同时存在于多个数据库,而某个分区数据库的自增主键已经没法知足全局

惟一,因此此时一个可以生成全局惟一ID的系统是很是必要的。那么这个全局惟一ID就叫分布式ID。可

以参考我以前写的这篇文章《一口气说出 9种 分布式ID生成方式,面试官有点懵了》

5、分库分表工具?

本身开发分库分表工具的工做量是巨大的,好在业界已经有了不少比较成熟的分库分表中间件,咱们可

以将更多的时间放在业务实现上

  • sharding-jdbc(当当)
  • TSharding(蘑菇街)
  • Atlas(奇虎360)
  • Cobar(阿里巴巴)
  • MyCAT(基于Cobar)
  • Oceanus(58同城) Vitess(谷歌)

----

今天就说这么多,若是本文对您有一点帮助,但愿能获得您一个点赞👍哦

您的承认才是我写做的动力!

整理了一些Java方面的架构、面试资料(微服务、集群、分布式、中间件等),有须要的小伙伴能够关注公众号【程序员内点事】,无套路自行领取

相关文章
相关标签/搜索