在互联网系统中,随着业务的增长,数据量也随着同步增长。
这会带来新的大表问题。
例如,一张订单表,很有可能到了几亿甚至几十亿的级别,由此带来的写入和读取性能的下降,会成为业务不容忽视的因素。
那么,如何对这种大表进行拆分呢?
首先能想到的策略就是分库分表。
分库分表又分为垂直拆分和水平拆分两种。
垂直拆分,还是水平拆分?
垂直拆分
如果业务之间的数据可以相互隔离,互不影响,那么垂直拆分是一个很简单的方案。
例如,对于一个订阅通知的服务而言,可能有不同的业务在使用,每个业务有不同的页面,各个业务之间的数据毫无关系,那么,对于每个业务而言,数据量就有限了,很多时候垂直拆分就可以解决问题。
垂直拆分的优点:
1、数据天然隔离,没有全表查询问题
2、改造方案简单
垂直拆分的缺点:
1、数据不均匀,可能不能完美解决大表问题
水平拆分
另一种分库分表的方式是水平拆分。
水平拆分的原理,就是从业务字段中选择一个拆分的字段,在写的时候根据这个字段生成分表的编号,读的时候也根据这个查询条件决定去哪个表查询。
水平拆分也是业务常用的处理大表的方式,但水平拆分并不是毫无缺点的,需要使用水平分库分表,业务方必须要考虑以下问题:
1、分表字段应该如何选择?
分表字段的选择应该满足以下要求:
a)各个表中的数据分布应该尽量均匀,且读写流量比较相近,避免出现热点数据问题
例如,对于C端的表可以采用用户id进行分表
b)尽量避免以不带分表字段为查询条件的查询,因为这种查询比较麻烦,后面会详细介绍
2、分片数应该怎样选择?
一般需要满足业务3~5年发展的需要,且分片数要是2的倍数,便于未来可能再次拆分。
3、历史数据应该怎样迁移?
如果是全新的数据,能预期是个大表,可以提前进行拆分,减少分库分表的迁移成本。
否则需要对历史数据进行处理,一般会采用先双写再切读的方式,先将写同时写分库分表后的表一份,验证没有问题后再切换读流量,最后将原有的写流量下线。
查询条件没有分表字段怎么办?
当查询条件没有分表字段时,查询无法直接定位到分表,此时一般有如下几种解决方式。
1、直接全表扫描
如果查询的请求量比较少,且对响应时间的要求不是很苛刻,可以直接采用扫描全部分表的方式,将数据聚合并返回
2、采用多个分表字段分表
对于其它查询的维度再次进行分表(称为辅表),并通过databus等方式将主表的数据同步到辅表中,这样就可以再次进行在分表上查询
这样做的优势是查询性能比较好,缺点是数据冗余存储,成本比较高。
3、建立一个索引表
索引表只存储分表字段和查询字段的映射关系,当使用其它字段查询时,先根据其它字段查到对应的分表字段,再去相应的分表查询具体的信息。
这样做的好处是无需冗余存储字段,缺点在于查询性能会受到一定的影响。
水平拆分的优点:
1、对数据的业务场景没有要求,只要能找到合适的分表字段即可
2、拆分的越多,能承载的数据量越多
垂直拆分的缺点:
1、对查询条件有要求,有可能遇到全表查询的问题
2、改造成本比较高
分库还是分表?
分库的好处在于将流量进一步隔离到不同的库中,适合流量比较大,单独的数据库无法承载的场景。
如果单独的库可以承载流量,可以采用分表的方式。
还有其它方式么?
除了分库分表之外,我们还有其它方式解决大表的问题。
比如冷热分离。
冷热分离的方案是将数据拆分为热数据和冷数据,热数据是变更较为频繁的数据,保存在热库中,而冷数据是全量的数据,保存在冷库中。
冷热分离一个非常适合的场景是订单场景,在订单场景中,最近几个月的订单状态变化是非常平凡的,这是可以存储在热库中,而之后,订单一般已结束,变化就很少了,这时可以迁移到冷库中。
而如何读取冷库的数据,可以不拘泥于mysql,根据预期响应时间和维护成本,可以选择hive表,es索引或者newsql等方式。
冷热分离的优点:
1、方案灵活,改造成本低
冷热分离的缺点:
1、适合于冷数据和热数据区别比较明显的场景,业务限制比较大