最近在看一些MyCAT相关的资料,写写分库分表的知识吧。
对MySQL分库分表的一些理解
MySQL的数据量到达一定的限度之后,它的查询性能会下降,这不是调整几个参数就可以解决的,如果我们想要自己的数据库继续保证一个比较高的性能,那么分库分表在所难免。
MySQL原生的分区表本身是为分库分表设计的,分区表的概念如下:
分区表本身是一个独立的逻辑表,它的特点是所有的数据还在一张表中,但是物理存储根据一定的规则放在不同的文件中。对于应用来说,它感知不到分区表的存在,MySQL在创建分区表的时候使用partition by子句定义每个分区存放的数据,在执行查询的时候,优化器会根据分区定义将原本需要遍历全表的过程转化为只需要遍历表里某一个或者某一些分区的工作,这样降低了查询对服务器的压力,提升了查询的效率。
然而,这样的分区行为存在一定的弊端:
首先,在使用分区表的时候,SQL需要遵循一定的规则,否则容易造成全表锁,导致分区的性能比较低下;
其次,如果数据量越来越多,在分区表上执行一个关联查询,那么性能会相当低下;
再者,分区的结果收到MySQL实例的数据文件无法分布式存储的限制,无论如何分区,所有的数据还是都在一个服务器上,没有办法通过水平扩展的方式将压力分摊出去,所以,分区表现在基本上被互联网公司废弃了。
在实际线上的大库大表进行分库分表的时候,一般分为水平拆分和垂直拆分两种方法:
01
垂直拆分
一般情况下,在进行拆分表的时候,优先考虑垂直拆分,垂直拆分理解起来就像业务层面的拆分一样:
1、在数据库层面,将没有关联的业务放在不同的库里面,例如用户信息放在user_info库中,金币信息放在money_info库中,积分信息放在score_info库中
2、表层面,将不同的用户信息放在不同的表里面,例如用户的个人信息,放在user_info的person表里面,用户的登录信息,放在user_info的login表里面...
3、数据库实例层面,如果一个服务器上有多个MySQL实例,从分摊压力的角度,可以将多个数据库分别放置在不同的实例上
4、服务器层面,如果一个游戏包含有多个MySQL实例,则可以讲这些实例放置在不同的服务器上。
5、字段层面,这个不是很常用,就是把表里面的字段单独的拆分出来作为一个表,这一般用于前期设计失误的情况下。
02
水平拆分
水平拆分是相对于一张表来说的,在经过垂直拆分之后,可能还有一些表的数据量很大,例如用户数字,这个时候需要利用某种算法对表进行水平拆分,也就是说,每张表里面保存的是一部分数据,说白了,就是对表数据的路由规则。例如月表拆分,按照月份将表拆分为12个,这样就可以按照时间去将数据分别记在不同的表里面。 例如一些log库,我们可以按照一定的基数去拆,比如logid对100取模,然后将结果均匀的分配在100张表里面。
进行水平拆分的目的是,通过这样的做法,降低MySQL的负载,将原本不支持分布式的MySQL实例转换为基于MySQL的分布式集群,如果水平拆分之后,表还是比较大,还可以将水平拆分之后的表进行垂直拆分。
03
分库分表的原则
关于分库分表的原则,我大概总结了下:
1、能不分就不分。
如果不是为了解决问题,谁愿意去主动的分表?这不是闲的没事儿干么。所以能用一个表就用一个表,分表多了,维护起来那个成本,用过的人都知道。一张表的维护成本还是比较小的。
2、如果数据量过大,已经开始影响业务的正常访问。
在这种情况下,如果数据量过大,对数据库的备份的时候,往往会占用很多的磁盘IO资源和网络IO资源,其次,过大数据量的表在进行DDL操作的时候,可能会导致锁全表,这个时间很长,业务一般不能接受。当然我们可以使用PT-ONLINE-SCHEMA-CHANGE等工具区帮我们实现,但是也是需要额外的时间代价的。
3、安全性和可用性的考虑
分库分表的时候,如果其中一台机器出了故障,那么我们可以保证至少不影响全局,如果将所有的库表都保存在一台服务器上,因为某些不可抗拒的因素导致了服务器崩溃,这是很可怕的。分库分表能够在一定的程度上提高业务的可用性。
4、业务的耦合性过高的时候,需要分库分表。
例如有两个业务a和b,a的访问量比较高,对服务器的压力很大,那么很有可能造成服务器崩溃的时候殃及b业务,那么在这种情况下,还是建议分库分表,确保业务之间不会互相干扰。