电商:MySQL存储海量数据的最后一招---分库分表

电商:MySQL存储海量数据的最后⼀招---分库分表
解决海量数据的问题,必须要⽤到分布式的存储集,因为MySQL本质上是⼀个单机数据库,所以很多场景下不是太适合TB级别以上的数据库。
但是,绝⼤多数电商⼤⼚,它的在线交易这部分的业务,⽐如说,订单、⽀付相关的系统,还是舍弃不了MySQL,原因是,只有MySQL这类关系型数据库,才能提供⾦融级别的事务保证(分布式事务是“残⾎版”)
伸缩装置那既然MySQL⽀持不了这么⼤的数据量,这么⾼的并发,但是必须要⽤它,该怎么解决这个问题呢?答案是分⽚,也就是拆分数据。1TB 的数据,⼀个库撑不住,把它拆成100个库,每个库就只有100G的数据了,不就可以了吗?这种拆分就是所谓的MySQL分库分表。
思路是这样没有错,但是实践起来有很多问题需要去解决
如何规划分库分表
中央排水系统分库就是把数据拆分到不同的 MySQL 库中去
分表就是把数据拆分到同⼀个库的多张表⾥⾯。
那我们是先分库还是先分表呢?
在考虑到底是分库还是分表之前,我们需要先明确⼀个原则,那就是能不拆就不拆,能少拆就少拆。原因也很简单,你把数据拆分得越散,开发和维护起来就越⿇烦,系统出问题的概率就越⼤。
基于这个原则我们想⼀下,什么情况下适合分表,什么情况下不得不分库?
我们分库分表的⽬的是为了解决两个问题:
第⼀,是数据量太⼤查询慢的问题。
红外线烤箱
这⾥的“查询”主要是事务中的查询和更新操作,因为只读的查询可以通过缓存和主从分离来解决
解决查询慢,只要减少每次查询的数据总量就可以了,也就是说,分表就可以解决问题
牌坊制作第⼆,是为了应对⾼并发的问题
应对⾼并发的思想是⼀个数据库实例撑不住,就把并发请求分散到多个实例中去
所以,解决⾼并发的问题是需要分库的
也就是说,数据量⼤,就分表;并发⾼,就分库。
但是⼀般情况下,我们的⽅案都需要同时做分库分表,这时候分多少库,多少张表,分别⽤预估的并发量和数据量来计算就可以了。
另外,不建议在⽅案中考虑⼆次扩容的问题,也就是考虑未来的并发量,把这次分库分表设计的容量都填满了之后,数据如何再次分裂的问题。现在技术和业务变化这么快,等真正到了那个时候,业务早就变了,可能新的技术也出来了,之前设计的⼆次扩容⽅案⼤概率是⽤不上的,所以没必要为了这个⽽增加⽅案的复杂程度。还是那句话,越简单的设计可靠性越⾼。
如何选择sharding key
分库分表还有⼀个重要的问题是,选择⼀个合适的列或者说是属性,作为分表的依据,这个属性⼀般叫做sharding key。像是归档历史订单的shading key就是订单完成时间,每次查询的时候,查询条件中必须带上这个时间,我们的程序就知道,三个⽉以前的数据查订单历史表,三个⽉内的数据查订单表,这就是⼀个简单的按照时间范围来分⽚的算法
选择合适的sharding key和分⽚算法⾮常重要,直接影响了分库分表的效果。那应该如何选择sharding key呢?
选择这个sharding key最重要的参考因素是,我们的业务是如何访问数据的
⽐如我们把订单ID作为sharding key来拆分订单表,那拆分之后,如果我们按照订单ID来查订单,就需要先根据订单ID和分⽚算法计算出,我要查的这个订单它在哪个分⽚上,也就是在哪个库那张表中,然后再去那个分⽚执⾏查询就可以了。
但是,当打开“我的订单”这个页⾯时,它的查询条件是⽤户ID,这⾥没有订单ID,那就没法知道我们要查的订单在哪个分⽚上,就没法查了。当然你要强⾏查的话,那就只能把所有分⽚查⼀遍,再合并查询结果,这个就很⿇烦,⽽且性能很差,还不能分页。
那要是把⽤户ID作为sharding key呢?也会⾯临同样的问题,使⽤订单 ID 作为查询条件来查订单的时候,就没办法到订单在哪个分⽚了。这个问题的解决⽅法是,在⽣成订单ID的时候,把⽤户ID的后⼏位作为订单ID的⼀部分,⽐如说,可以规定,18位的订单号,第 10-14 位是⽤户 ID 的后四位,这样按订单 ID 查询的时候,就可以根据订单 ID 中的⽤户 ID 到分⽚
那我们系统对订单的查询⽅式,肯定不只是按订单 ID 或者按⽤户 ID 这两种啊。⽐如说,商家希望看到的是⾃⼰店铺的订单,还有各种和订单相关的报表。对于这些查询需求,我们⼀旦对订单做了分库分表,就没法解决了。该怎么办呢?
⼀般的做法是,把订单数据同步到其他的存储系统中去,在其他的存储系统中⾥⾯解决问题。⽐如说,我们可以再构建⼀个以店铺ID为sharding key作为只读订单库,专门供商家来使⽤。或者说,把
订单数据同步到HDFS中,然后⽤⼀些⼤数据技术来⽣成订单相关的报表。
从上⾯可以看出,⼀旦做了分库分表,就会极⼤的限制数据库的查询能⼒,之前很简单的查询,分库分表之后,可能就没法实现了。分库分表⼀定是,数据量和并发⼤到所有招数都不好使了,我们才拿出来的最后⼀招。
如何选择分⽚算法
能不能⽤订单完成时间作为sharding key呢?⽐如说,我分12个分⽚,每个⽉⼀个分⽚,这样对查询的兼容要好很多,毕竟查询条件中带上时间范围,让查询只落到某⼀个分⽚上,还是⽐较容易的,我在查询界⾯上强制⽤户必须指定时间范围就⾏了。
对路网
这种做法有⼀个很⼤的问题,⽐如现在是3⽉份,那基本上所有的查询都集中在3⽉份这个分⽚上,其他11个分⽚都闲着,这样不仅浪费资源,很可能你3⽉那个分⽚根本扛不住⼏乎全部的并发请求,这就是热点问题
也就是说,我们希望并发请求和数据能够均匀的分布在每⼀个分⽚上,尽量避免出现热点。这是选择分配算法时需要考虑的⼀个重要因素。⼀般常⽤的分⽚算法就那么⼏种,刚刚讲到的按照时间范围分⽚的⽅法就是其中⼀种。
基于范围分配很容易产⽣热点问题,不适合作为订单的分⽚⽅法,但是这种分⽚⽅法的优点也很突出,那就是对查询⾮常友好,基本上只要加上⼀个时间范围的查询条件,原来该怎么查,分⽚后可以怎么查。范围分配特别适合于那种数据量特别⼤,但是并发访问量不⾼的ToB系统。⽐如说,电信运营商的监控系统,它可能要采集所有⼈⼿机的信号质量,然后做⼀些分析,这个数据量⾮常⼤,但是这个系统的使⽤者是运营商的⼯作⼈员,并发量很少。这种情况下就很适合范围分⽚。
大理石清洗剂⼀般来说,订单表都采⽤更均匀的哈希分⽚算法。⽐如说,我们要分 24 个分⽚,选定了Sharding Key 是⽤户 ID,那我们决定某个⽤户的订单应该落到那个分⽚上的算法是,拿⽤户 ID 除以 24,得到的余数就是分⽚号。这是最简单的取模算法,⼀般就可以满⾜⼤部分要求了。当然也有⼀些更复杂的哈希算法,像⼀致性哈希之类的,特殊情况下也可以使⽤。
需要注意的⼀点是,哈希分配能够分得⾜够均匀的前提条件是,⽤户ID后⼏位数据必须是均匀分布的。⽐如说,你在⽣成⽤户 ID 的时候,⾃定义了⼀个⽤户 ID 的规则,最后⼀位 0 是男性,1 是⼥性,这样的⽤户 ID 哈希出来可能就没那么均匀,可能会出现热点。
还有⼀种分⽚的⽅法,查表法。查表法其实是没有分⽚算法,决定某个sharding key落在哪个分⽚上,全靠⼈为来分配,分配的结果记录在⼀张表⾥⾯。每次查询的时候,先去表⾥查⼀下要的数据在哪个分⽚中。
查表法的好处就是灵活,怎么分都可以,你⽤上⾯两种分⽚算法都没法分均匀的情况下,就可以⽤查表法,⼈为地来把数据分均匀了。查表法还有⼀个特好的地⽅是,它的分⽚是可以随时改变的。⽐如我发现某个分⽚已经是热点了,那我可以把这个分⽚再拆成⼏个分⽚,或者把这个分⽚的数据移到其他分⽚中去,然后修改⼀下分⽚映射表,就可以在线完成数据拆分了。
但你需要注意的是,分⽚映射表本⾝的数据不能太多,否则这个表反⽽成为热点和性能瓶颈了。查表法相对其他两种分⽚算法来说,缺点是需要⼆次查询,实现起来更复杂,性能上也稍微慢⼀些。但是,分⽚映射表可以通过缓存来加速查询,实际性能并不会慢很多。
⼩结
对MySQL这样的单机数据库来说,分库分表是应对海量数据和⾼并发的最后⼀招,分库分表之后,将会对数据查询有⾮常⼤的限制。
分库分表使⽤的场景是不⼀样的,分表是因为数据量⽐较⼤查询较慢才进⾏的,分库是因为单库的性能⽆法满⾜要求才进⾏的
分多少个库需要⽤并发量来预估,分多少表需要⽤数据量来预估。选择sharding key时,⼀定要能够兼容业务最常⽤的查询条件,让查询尽量落在⼀个分⽚中,分⽚之后⽆法兼容的查询,可以把数据同步到其他存储中去,来解决这个问题
我们常⽤的三种分⽚算法,范围分⽚容易产⽣热点问题,但对查询友好,适合并发量不⼤的场景;哈希分配⽐较容易把数据和查询均匀分布到所有分⽚中;查表法更灵活,但性能稍差。
对于订单表进⾏分库分表,⼀般按照⽤户ID作为sharding key,采⽤哈希分⽚算法来均匀分布⽤户订单数据。为了能够⽀持按照订单号查询的需求,需要把⽤户ID的后⼏位放到订单中去。

本文发布于:2024-09-22 01:42:24,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/2/133367.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:查询   订单   分表
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议