1. 什么是分库分表
分库:就是一个数据库分红多个数据库,部署到不同机器。
分表:就是一个数据库表分红多个表。
2. 咱们为什么须要分库分表
在分库分表之前,就须要思考为什么须要拆分。咱们无法能无缘无端就做分库分表的。咱们做一件事,必需是有充沛理由的。你可以好好跟面试官说一下你们分库分表的理由哈。我如今就从两个维度去回答,为什么要分库?为什么要分表?
2.1 为什么要分库
假设业务量剧增,数据库或许会产生性能瓶颈,这时刻咱们就须要思考拆分数据库。从这两方面来看:
业务量剧增,MySQL单机磁盘容量会撑爆,拆成多个数据库,磁盘经常使用率大大降低。
咱们知道数据库衔接数是有限的。在高并发的场景下,少量恳求访问数据库,MySQL单机是扛不住的!高并发场景下,会产生too many connections报错。
十分火的微服务架构产生,就是为了应答高并发。它把订单、用户、商品等不同模块,拆分红多个运行,并且把单个数据库也拆分红多个不同性能模块的数据库(订单库、用户库、商品库),以分担读写压力。
2.2 为什么要分表
假设你的单表数据量十分大,存储和查问的性能就会遇到瓶颈了,假设你做了很多优化之后还是无法优化效率的时刻,就须要思考做分表了。普通千万级别数据量,就须要分表。
这是由于即使SQL命中了索引,假设表的数据量超越一千万的话,查问也是会显著变慢的。这是由于索引普通是B+树结构,数据千万级别的话,B+树的高度会增高,查问就变慢啦。MySQL的B+树的高度怎样计算的呢?跟大家温习一下:
InnoDB存储引擎最小贮存单元是页,一页大小就是16k。B+树叶子存的是数据,外部节点存的是键值+指针。索引组织表经过非叶子节点的二分查找法以及指针确定数据在哪个页中,进而再去数据页中找到须要的数据,B+树结构图如下:
假定B+树的高度为2的话,即有一个根结点和若干个叶子结点。这棵B+树的寄存总记载数为=根结点指针数*单个叶子节点记载行数。
假设一行记载的数据大小为1k,那么单个叶子节点可以存的记载数 =16k/1k =16.非叶子节点内寄存多少指针呢?咱们假定主键ID为bigint类型,长度为8字节(面试官问你int类型,一个int就是32位,4字节),而指针大小在InnoDB源码中设置为6字节,所以就是 8+6=14 字节,16k/14B =16*1024B/14B = 1170
因此,一棵高度为2的B+树,能寄存1170 * 16=18720条这样的数据记载。同理一棵高度为3的B+树,能寄存1170 *1170 *16 =21902,大略可以寄存两千万左右的记载。B+树高度普通为1-3层,假设B+到了4层,查问的时刻会多查磁盘的次数,SQL就会变慢。
因此单表数据量太大,SQL查问会变慢,所以就须要思考分表啦。
3. 什么时刻思考分库分表?
关于MySQL,InnoDB存储引擎的话,单表最多可以存储10亿级数据。但假设真的单表存储这么多,性能就会十分差。普通数据量千万级别,B+树索引高度就会到3层以上了,查问的时刻会多查磁盘的次数,SQL就会变慢。
实践上,阿里巴巴的《Java开发手册》提出:
单表行数超越500万行或许单表容量超越2GB,才介绍启动分库分表。
那咱们是不是等到数据量抵达五百万,才开局分库分表呢?
实践上,不能酱紫,咱们应该提早布局分库分表,假设预算3年后,你的表都不会抵达这个五百万,则不须要分库分表。也就是说不用庸人自扰。
MySQL主机假设性能更好,是不是可以超越这个500万这个量级,才思考分库分表?
只管性能更好,或许数据量大之后,性能还是不错,然而假设继续开展的话,还是要思考分库分表
普通什么类型业务表须要才分库分表?
通用是一些流水表、用户表等才思考分库分表,假设是一些性能类的表,则齐全不用思考,由于不太或许抵达这个量级。
4.如何选用分表键
分表键,即用来分库/分表的字段,换种说法就是,你以哪个维度来分库分表的。比如你按用户ID分表、按时期分表、按地域分表,这些用户ID、时期、地域就是分表键。
普通数据库表拆分的准则,须要先找到业务的主题。比如你的数据库表是一张企业客户信息表,就可以思考用了客户号做为分表键。
为什么思考用客户号做分表键呢?
5.非分表键如何查问
分库分表后,有时刻无法防止一些业务场景查问,比如须要经过非分表键来查问某些信息。
假定一张用户表,用userId做分表键,用它来分库分表。然而用户登录时,须要依据用户手机号来登陆。这时刻,就须要经过手机号查问用户信息。而手机号是非分表键。。。
非分表键查问,普通有这几种计划:
其实还有基因法:比如非分表键可以解析出分表键出来,比如经常出现的,订单号生成时,可以蕴含客户号出来,经过订单号查问,就可以解析出客户号。然而这个场景有点不凡,手机号仿佛不适宜冗余userId,大家感觉呢,欢迎评论区留言探讨哈~~
6. 分表战略如何选用
6.1 range范围
range,即范围战略划分表。比如咱们可以将表的主键order_id,依照从0~300万的划分为一个表,300万~600万划分到另外一个表。如下图:
有时刻咱们也可以按时期范围来划分,如不同年月的订单放到不同的表,它也是一种range的划分战略。
6.2 hash取模
hash取模战略:
指定的路由key(普通是user_id、order_id、customer_no作为key)对分表总数启动取模,把数据扩散到各个表中。
比如原始订单表信息,咱们把它分红4张分表:
普通,咱们会取哈希值,再做取余:
MathabsorderIdhashCode table_number
6.3 分歧性Hash
假设用hash模式分表,前期布局不好,须要扩容二次分表,表的数量须要参与,所以hash值须要从新计算,这时刻须要迁徙数据了。
为了处置这个扩容迁徙疑问,可以经常使用分歧性hash思维来处置。
7. 如何防止热点疑问数据歪斜(热点数据)
假设咱们依据时期范围分片,某电商公司11月搞营销优惠,那么大局部的数据都落在11月份的表外面了,其他分片表或许很少被查问,即数据歪斜了,有热点数据疑问了。
咱们可以经常使用range范围+ hash哈希取模联合的分表战略,便捷的做法就是:
8.分库后,事务疑问如何处置
分库分表后,假定两个表在不同的数据库,那么本地事务曾经有效啦,须要经常使用散布式事务了。
罕用的散布式事务处置计划有:
大家可以看下这几篇文章:
9. 跨节点Join关联疑问
在单库未拆分表之前,咱们假设要经常使用join关联多张表操作的话,简直so easy啦。然而分库分表之后,两张表或许都不在同一个数据库中了,那么如何跨库join操作呢?
跨库Join的几种处置思绪:
10. order by,group by等聚合函数疑问
跨节点的count,order by,group by以及聚合函数等疑问,都是一类的疑问,它们普通都须要基于所有数据集合启动计算。可以区分在各个节点上失掉结果后,再在运行程序端启动兼并。
也经常使用支持分库分表的数据库两边件(如MyCAT、ShardingSphere等),这些两边件通常提供了对跨分片查问的支持,可以在肯定水平上简化聚合操作的处置。
还可以经常使用专门的聚合服务或大数据处置平台(如Apache Flink、Apache Spark等)来启动全局聚合。这种方法可以处置大数据量,但须要额外的系统资源。
11. 分库分表后的分页疑问
比如分库分表前,你是依据创立时期排序,而后失掉第2页数据。假设你是分了两个库,那你就可以每个库都依据时期排序,而后都前往2页数据,而后把两个数据库查问回来的数据汇总,再依据创立时期启动内存排序,最后再取第2页的数据。
12. 散布式ID
数据库被切分后,不能再依赖数据库自身的主键生成机制啦,最便捷可以思考UUID,或许经常使用雪花算法生成散布式ID。
一个Snowflake ID有64位。
然而雪花算法存在时钟回拨疑问,大家知道如何处置嘛,欢迎评论区探讨,嘻嘻~
13. 分库分表选用哪种两边件
目前盛行的分库分表两边件比拟多:
咱们名目就是经常使用Sharding-JDBC成功的分库分表。
14.如何评价分库数量
15.垂直分库、水平分库、垂直分表、水平分表的区别
16.分表要停服嘛?不停服怎样做?
不用停服。不停服的时刻,应该怎样做呢,关键分五个步骤: