专栏首页JavaEdge突破Java面试(46)-分库分表
原创

突破Java面试(46)-分库分表

0 Github

1 面试题

为什么要分库分表(设计高并发系统的时候,数据库层面该如何设计)?用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?你们具体是如何对数据库如何进行垂直拆分或水平拆分的?

2 分析

其实这块肯定是扯到高并发了,因为分库分表一定是为了支撑高并发、数据量大两个问题的。而且现在说实话,尤其是互联网类的公司面试,基本上都会来这么一下,分库分表如此普遍的技术问题,不问实在是不行,而如果你不知道那也实在是说不过去!

3 业务分析

说白了,分库分表是两回事儿,大家可别搞混了,可能是光分库不分表,也可能是光分表不分库,都有可能。我先给大家抛出来一个场景。

业务发展迅猛,注册用户数达到了2000万!每天活跃用户数100万!每天单表数据量10万条!高峰期每秒最大请求达到1000!感觉压力已经有点大了,为啥呢?因为每天多10万条数据,一个月就多300万条数据,现在咱们单表已经几百万数据了,马上就破千万了。但是勉强还能撑着。高峰期请求现在是1000,咱们线上部署了几台机器,负载均衡搞了一下,数据库撑1000 QPS也还凑合。但是大家现在开始感觉有点担心了,接下来咋整呢。。。。。。

此时每天活跃用户数上千万,每天单表新增数据多达50万,目前一个表总数据量都已经达到了两三千万了!扛不住啊!数据库磁盘容量不断消耗掉!高峰期并发达到惊人的5000~8000!别开玩笑了,哥。我跟你保证,你的系统支撑不到现在,已经挂掉了!

看到你这里你差不多就理解分库分表是怎么回事儿了,实际上这是跟着公司业务发展走的,你公司业务发展越好,用户就越多,数据量越大,请求量越大,那你单个数据库一定扛不住。

比如你单表都几千万数据了,你确定你能抗住么?

绝对不行,单表数据量太大,会极大影响你的sql执行的性能,到了后面你的sql可能就跑的很慢了。一般来说,以经验来看,单表到几百万的时候,性能就会相对差一些了,你就得分表了。

4 分表

把一个表的数据放到多个表中,然后查询的时候你就查一个表

比如按照用户id来分表,将一个用户的数据就放在一个表中。然后操作的时候你对一个用户就操作那个表就好了。这样可以控制每个表的数据量在可控的范围内,比如每个表就固定在200万以内。

5 分库

一个库一般我们经验而言,最多支撑到并发2000,一定要扩容了,而且一个健康的单库并发值你最好保持在每秒1000左右,不要太大。那么你可以将一个库的数据拆分到多个库中,访问的时候就访问一个库好了。

这就是所谓的分库分表,为啥要分库分表?你明白了吧

  • 分库分表的由来

6 分库分表中间件

不同的分库分表中间件都有什么优点和缺点?

比较常见的包括:cobar、TDDL、atlas、sharding-jdbc、mycat

6.1 cobar

阿里b2b团队开发和开源的,属于proxy层方案

早些年还可以用,但是最近几年都没更新了

基本没啥人用了,差不多算是被抛弃的状态吧。而且不支持读写分离、存储过程、跨库join和分页等操作。

6.2 TDDL

淘宝团队开发的,属于client层方案

不支持join、多表查询等语法,就是基本的crud语法是ok,但是支持读写分离。

目前使用的也不多,因为还依赖淘宝的diamond配置管理系统,而且已被商用,不再开源

6.3 atlas

360开源的,属于proxy层方案,以前是有一些公司在用的,但是确实有一个很大的问题就是社区最新的维护都在6年前了。所以,现在用的公司基本也很少了。

6.4 sharding-jdbc

当初由当当开源的,属于client层方案。确实之前用的还比较多一些,因为SQL语法支持也比较多,没有太多限制,而且目前推出到了2.0版本,支持分库分表、读写分离、分布式id生成、柔性事务(最大努力送达型事务、TCC事务)。而且确实之前使用的公司会比较多一些(这个在官网有登记使用的公司,可以看到从2017年一直到现在,是不少公司在用的),目前社区也还一直在开发和维护,还算是比较活跃,算是一个现在也可以选择的方案。现在已经升级为Apache组织的项目

sharding-jdbc这种client层方案的优点在于不用部署,运维成本低,不需要代理层的二次转发请求,性能很高,但是如果遇到升级啥的需要各个系统都重新升级版本再发布,各个系统都需要耦合sharding-jdbc的依赖;

6.5 mycat

基于cobar改造的,属于proxy层方案,支持的功能非常完善,而且目前应该是非常火的而且不断流行的数据库中间件,社区很活跃,也有一些公司开始在用了。但是确实相比于sharding jdbc来说,年轻一些,经历的锤炼少一些。

mycat这种proxy层方案的缺点在于需要部署,自己及运维一套中间件,运维成本高,但是好处在于对于各个项目是透明的,如果遇到升级之类的都是自己中间件那里搞就行了。

6.6 小结

所以综上所述,现在其实建议考量的,就是sharding-jdbc和mycat,这两个都可以去考虑使用。

通常来说,这两个方案其实都可以选用,但是我个人建议中小型公司选用sharding-jdbc,client层方案轻便,而且维护成本低,不需要额外增派人手,而且中小型公司系统复杂度会低一些,项目也没那么多;

但是中大型公司最好还是选用mycat这类proxy层方案,因为可能大公司系统和项目非常多,团队很大,人员充足,那么最好是专门弄个人来研究和维护mycat,然后大量项目直接透明使用即可。

7 数据库的垂直拆分或水平拆分

  • 数据库如何拆分

7.1 水平拆分

把一个表的数据给弄到多个库的多个表里,但每个库的表结构都一样,只不过每个库中表放的数据是不同的,所有库表的数据加起来就是全部数据

水平拆分的意义

将数据均匀放更多的库里,然后用多个库来抗更高的并发,还有就是用多个库的存储容量来进行扩容。

7.2 垂直拆分

把一个有很多字段的表给拆分成多个表,或者是多个库

每个库表的结构都不一样,每个库表都包含部分字段。一般来说,会将较少的访问频率很高的字段放到一个表里去,然后将较多的访问频率很低的字段放到另外一个表里去

因为数据库是有缓存的,访问频率高的行字段越少,就可以在缓存里缓存更多的行,性能就越好。这个一般在表层面做的较多一些。

这个其实挺常见的,很多同学可能自己都做过,把一个大表拆开,订单表、订单支付表、订单商品表。

还有表层面的拆分,就是分表,将一个表变成N个表,就是让每个表的数据量控制在一定范围内,保证SQL的性能

否则单表数据量越大,SQL性能就越差。一般是200万行左右,不要太多,但是也得看具体你怎么操作,也可能是500万,或者是100万。你的SQL越复杂,就最好让单表行数越少

无论是分库还是分表,上面说的那些数据库中间件都是可以支持的。就是基本上那些中间件可以做到你分库分表之后,中间件可以根据你指定的某个字段值,比如说userid,自动路由到对应的库上去,然后再自动路由到对应的表里去。

你就得考虑一下,你的项目里该如何分库分表?一般来说

  • 垂直拆分,你可以在表层面来做,对一些字段特别多的表做一下拆分
  • 水平拆分,你可以说是并发承载不了,或者是数据量太大,容量承载不了,你给拆了,按什么字段来拆,你自己想好
  • 分表,你考虑一下,你如果哪怕是拆到每个库里去,并发和容量都ok了,但是每个库的表还是太大了,那么你就分表,将这个表分开,保证每个表的数据量并不是很大

8 分库分表的方式

8.1 按照range分

就是每个库一段连续的数据,一般按比如时间范围来的,但是这种一般较少用,因为很容易产生热点问题,大量的流量都打在最新的数据上了

好处

后面扩容的时候,就很容易,因为你只要预备好,给每个月都准备一个库就可以了,到了一个新的月份的时候,自然而然,就会写新的库了

缺点

但是大部分的请求,都是访问最新的数据。实际生产用range,要看场景,你的用户不是仅仅访问最新的数据,而是均匀的访问现在的数据以及历史的数据

8.2 按照某个字段hash

一下均匀分散,较为常用。

好处

可以平均分配没给库的数据量和请求压力

坏处

扩容起来比较麻烦,会有一个数据迁移的过程

参考

  • 《Java工程师面试突击第1季-中华石杉老师》

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 接口优化概述

    JavaEdge
  • JVM的StackMapTable的前世今生

    在Java 6版本之后JVM在class文件中引入了栈图(StackMapTable)。

    JavaEdge
  • Java支付系统(三) - SpringBoot 应用程序搭建

    JavaEdge
  • 分库分表的正确姿势,你GET到了么?

    以支付宝用户为例,8亿;微信用户更是10亿。订单表更夸张,比如美团外卖,每天都是几千万的订单。淘宝的历史订单总量应该百亿,甚至千亿级别,这些海量数据远不是一张表...

    kirito-moe
  • 透过源码学习设计模式7-适配器模式与HandlerApapter

    适配器模式把一个类的接口,变换成客户端所期待的另一种接口,使原本因接口不匹配的两个类能够在一起工作。

    java达人
  • Django之中间件

    django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件...

    超蛋lhy
  • Java Web学习总结(八)——HttpServletResponse对象(二)

    请求重定向指:一个web资源收到客户端请求后,通知客户端去访问另外一个web资源,这称之为请求重定向。

    Java团长
  • Springsecurity之AuthenticationEntryPoint

        org.springframework.security.web.AuthenticationEntryPoint在spring-security-we...

    克虏伯
  • 面试官问我:你们的数据库是怎么架构的?

    1、高可用分析:高可用,主库挂了,keepalive(只是一种工具)会自动切换到备库。这个过程对业务层是透明的,无需修改代码或配置。

    黄泽杰
  • 数据库之互联网常用架构方案

    1.高可用分析: 高可用,主库挂了,keepalive(只是一种工具)会自动切换到备库。这个过程对业务层是透明的,无需修改代码或配置。

    小东啊

扫码关注云+社区

领取腾讯云代金券