目录
1、为什么分库分表?
当数据量太大,业务太复杂,单表数据非常大超过硬件成本极限的时候,需要考虑分库分表。
2、什么是分库,什么是分表?
分库理解成将原来的一个库分成多个库,这往往需要应用侧做对应的改造和支撑。 分表是将一个大表分成多个表。
3、分库分表的策略有哪些?
分库分表根据数据不同、场景不同有不同的策略。
- 分库有两种分法:
3.1 垂直分库
垂直分库往往都是和微服务架构相辅相成,一般情况下是按照业务属性将某一类业务相关的表都放到一个库。通过这种方式,对复杂业务的进行解耦,将一个大库分成多个业务独立的小库。 这种方案对于热点表的单表数据巨大无法解决,可以配合分表。 例如:通常一个知识库平台,都会包含知识管理与搜索、考试中心、课程培训等。可以按照业务规则不同,分成单个库,分别是知识库、考试库、课程培训库。
3.2 水平分库
水平分库可以理解成水平将库进行扩充,每个库的表结构都是一样的,但是库不同。也可以简单理解成根据数据的属性不同,将数据分不到的不同的库里。 每个库的表结构相同,数据不同。 一般情况可以根据数据的属性进行分库。 比如:构建一个针对全国各个省份的知识库系统,每个省分的数据都是独立的,通过省份id进行隔离。此时我们就可以通过省份id分库,将不同省份的数据分别放到不同的库里。
- 分表也有两种方法:
3.3 垂直分表
所谓垂直分表可以简单理解成将宽表分解成多个小的表。这么做的主要原因在于,当单表的数据量上去之后,单条记录的数据数量也非常大,这就会造成额外的系统开销,影响查询下效率。为什么呢?Mysql的底层是通过数据页存储的,如果一条记录的空间过大,就会导致跨页,如果跨页了,在数据加载和获取的时候就会有额外的性能开销。 为什么要垂直分表呢?假设在业务需求上就是有一张表有非常多的属性和列,但是往往实际使用的时候,只会有那么固定的一些列属于热点数据,会经常被查询、更新。通过垂直分表,可以将这些热点列拿出来,从而减小mysql的内存使用率,降低可能的磁盘加载,提高效率。
3.4 水平分表
水平分表是另外一种思路,将单表的大量数据分不到多个结构相同的表中,解决单表大量数据的问题。 一般情况下这种分表规则都是按照数据规则来的,比如可以按照时间分表,每个月一张表或者每周一张表。也可以根据业务属性分表,比如按照某个业务id进行分表,例如;考试中心的考生考试记录表,可以根据省份id进行分表,后者根据部门id进行分表。 这种分表方式要求分表的业务属性尽量有特点,按照表分开的数据,在应用侧的业务需求上尽量没有关联关系。否则,应用侧在处理join查询、分页查询、统计的时候会比较麻烦。 比如:我们按照时间进行分表,没三个月做一次分表,那么在应用侧的功能上,只提供最近三个月的历史查询,三个月以前的查询放到单独的历史查询功能中去,从而避免出现联合分页查询的复杂处理。
所以,当出现分布分表的架构时候,单纯的产品经理或者需求人员已经不足以应付整个产品的设计,更多的需要架构人员参与功能的交互设计和需求的分解细化。
4、分库分表之后有哪些问题和挑战?
分库分表之后,主要还是应用侧研发时候的复杂度增加了,主要体现在以下几个方面:
4.1 数据库事务问题
事务问题主要体现在分库的时候,分库必定会涉及分布式事务的问题,这在微服务架构中也是一个难题,从解决方案上来说,比较直观的方案是所有涉及多库提交的时候,需要手动进行事务的处理。不能完全以来框架的事务处理机制了。增大的研发难度。 对于分布事务的处理,可以使用TX-LCN一个分布式事务框架,参考这里。 这个分布式事务框架有几种处理模式,可以参考我写的这篇博客。
4.2 join联合查询、分页及排序
当出现需要跨节点的联合查询的时候,应用层面的实现就比较复杂。比如:还是以前面提到的知识库系统为例,现在新增了一个角色,需要以全国的维度去将各个省份的考试情况统计出来,不是分省统计,而是需要将所有数据都拿过来。比如统计最近一个月最热试卷排行榜,查询条件就是这个试卷最近一个月都使用进行考试的次数。这时候在实现层面就需要先对各个省份的试卷进行统计排行,然后通过编码的方式将每个省份的数据汇聚再进行排序和统计,最终返回回去,如果还涉及分页的话,就更麻烦了。这些都需要通过编码的方式去处理,而无法使用数据的引擎。会增加编码的复杂度。
5、什么是读写分离?
读写分离一般情况下可以通过数据的主备来做,和分库分表不同。但是可以配合使用。我个人理解两者是平行的。互补干涉。在应用层面可以通过对接多个数据源的方式,将主库、备库接入应用,在开发的时候对所有涉及读库的操作都使用备库的数据库连接进行查询,所有写库的操作使用主库的数据库连接。通过这种读写分离的方式,降低数据库的压力在,增大系统吞吐量。
6、其他记录
当单表数据量达到多少的时候才需要分表呢?200w?1000w?这其实取决于你的硬件成本,如果你的内存是100T,那么你的单表设置为1亿行也没关系。 因为
MySQL 为了提高性能,会将表的索引装载到内存中。InnoDB buffer size 足够的情况下,其能完成全加载进内存,查询不会有问题。但是,当单表数据库到达某个量级的上限时,导致内存无法存储其索引,使得之后的 SQL 查询会产生磁盘 IO,从而导致性能下降。当然,这个还有具体的表结构的设计有关,最终导致的问题都是内存限制。这里,增加硬件配置,可能会带来立竿见影的性能提升哈。
参考这篇博客,写的很好。
7、参考文献