zoukankan      html  css  js  c++  java
  • 关于电商订单系统分库分表

    一.需求

    一般业界,对订单数据的分库分表,有两类思路:按照订单号来切分、按照用户id来切分。

    二.按照订单号来做 hash分散订单数据  

    把订单号看作是一个字符串,做 hash,分散到多个服务器去。

    具体到哪个库、哪个表存储数据呢?订单号里面的数字来记录着。

    如果要查询某用户的所有订单呢?

    由于是根据订单号来分散数据的。他的订单分散在了多个库、多个表中。

    总不能去所有的库,所有的表扫描吧。这样效率很低。

    解决:

    维护uid和oid的关系表, 此表可以作为缓存,当数据量增大时此关系表也要进行分表。

    一般使用方案二的比较多,一个用户的所有订单,都在一张表里面,那么做分页展示的时候,就容易。

    三.按照用户 id 打散订单数据

    以uid来切分数据,有两种思路:

    1、第一种

    某个范围的uid订单到哪些库。0到2千万uid,对应的订单数据到a库、a表。2千万到4千万对应的订单到b库。

    为什么这种方案用得比较少呢?容易出现瓶颈。

    某个范围内的用户,下单量比较多,那么造成这个库的压力特别大。其他库却没什么压力。


    2、第二种

    使用uid取模运算。这种方案业界用得比较多。

    一方面、处理简单,程序上做取模运算就好了。

    另一方面、使用取模的方式,数据比较均匀分散到多个库去了。不容易出现单个库性能瓶颈。

    但是不好处也有:即要扩容的时候,比较麻烦。就需要迁移数据了。

    要扩容的时候,为了减少迁移的数据量,一般扩容是以倍数的形式增加。比如原来是8个库,扩容的时候,就要增加到16个库,再次扩容,就增加到32个库。

    这样迁移的数据量,就小很多了。这个问题不算很大问题,毕竟一次扩容,可以保证比较长的时间,而且使用倍数增加的方式,已经减少了数据迁移量。


    下面分析一下按照用户id取模的方式分库分表。按照用户id作为key来切分订单数据,

    具体如下:

    (1)库名称定位:

    用户id末尾4位 Mod 32。

    Mod表示除以一个数后,取余下的数。比如除以32后,余下8,余数就是8。代码符号是用%表示:15%4=3。

    (2)表名称定位:

    (用户id末尾4位 Dev 32) Mod 32。

    Dev表示除以一个数,取结果的整数。比如得到结果是25.6,取整就是25。

    代码用/来表示:$get_int = floor(15/4)。15除以4,是一个小数3.75,向下取整就是3。一定是向下取整,向上取整就变成了4了。

    按照上面的规则:总共可以表示多少张表呢?32个库*每个库32个表=1024张表。如果想表的数量小,就把32改小一些。

    库ID = userId % 库数量4

    表ID = userId / 库数量4 % 表数量8

    或者

    库ID = userId / 表数量4 % 库数量4

    表ID = userId % 表数量8


    上面是用计算机术语来表示, 下面用通俗的话描述。

    (1)库名称计算

    用户id的后4位数,取32的模(取模就是除以这个数后,余多少)。余下的数,是0-31之间。

    这样可以表示从0-31之间,总共32个数字。用这个32个数字代表着32个库名称:order_db_0、order_db_2.........................order_db_31

    (2)表名称计算

    最后要存储定到哪个表名里面去呢?

    用户id的最后4位数,除以32,取整数。将整数除以32,得到余数,能够表示从0-31之间32个数字,表示表名称。

    表名称类似这样:order_tb_1、order_tb_2..........................order_tb_31。一个库里面,总共32个表名称。

    比如用户id:19408064,用最后4位数字8064除以32,得到是251.9,取它的整数是251。

    接着将251除以32,取余数,余数为27。

    为了保持性能,每张表的数据量要控制。单表可以维持在一千万-5千万行的数据。1024*一千万。哇,可以表示很多数据了。

    四.总结

    1、优点

    订单水平分库分表,为什么要按照用户id来切分呢?

    好处:查询指定用户的所有订单,避免了跨库跨表查询。

    因为,根据一个用户的id来计算节点,用户的id是规定不变的,那么计算出的值永远是固定的(x库的x表)。

    那么保存订单的时候,a用户的所有订单,都是在x库x表里面。需要查询a用户所有订单时,就不用进行跨库、跨表去查询了。

    2、缺点

    缺点在于:数据分散不均匀,某些表的数据量特别大,某些表的数据量很小。因为某些用户下单量多,打个比方,1000-2000这个范围内的用户,下单特别多,

    而他们的id根据计算规则,都是分到了x库x表。造成这个表的数据量大,单表的数据量撑到极限后,咋办呢?

    总结一下:每种分库分表方案也不是十全十美,都是有利有弊的。目前来说,这种使用用户id来切分订单数据的方案,还是被大部分公司给使用。

    实际效果还不错。程序员省事,至于数据量暴涨,以后再说呢。毕竟公司业务发展到什么程度,不知道的,项目存活期多久,未来不确定。先扛住再说。

    3、问题

    b2b平台的订单分卖家和买家的时候,选择什么字段来分库分表呢?

    上面讨论的情况是,b2c平台。订单的卖家就一个,就是平台自己。

    b2b平台,上面支持开店,买家和卖家都要能够登陆看到自己的订单。

    先来看看,分表使用买家id分库分表和根据卖家id分库分表,两种办法出现的问题。

    如果按买家id来分库分表。有卖家的商品,会有n个用户购买,他所有的订单,会分散到多个库多个表中去了,卖家查询自己的所有订单,跨库、跨表扫描,性能低下。

    如果按卖家id分库分表。买家会在n个店铺下单。订单就会分散在多个库、多个表中。买家查询自己所有订单,同样要去所有的库、所有的表搜索,性能低下。

    所以,无论是按照买家id切分订单表,还是按照卖家id切分订单表。两边都不讨好。

    淘宝的做法是拆分买家库和卖家库,也就是两个库:买家库、卖家库。

    买家库,按照用户的id来分库分表。卖家库,按照卖家的id来分库分表。

    实际上是通过数据冗余解决的:一个订单,在买家库里面有,在卖家库里面也存储了一份。

    下订单的时候,要写两份数据。先把订单写入买家库里面去,然后通过消息中间件来同步订单数据到卖家库里面去。

  • 相关阅读:
    解决 搭建Jekins过程中 启动Tomcat的java.net.UnknownHostException异常
    射手和农场主
    java 和 JS(javaScript)中的反斜杠正则转义
    分享修改密码的SharePoint Web part: ITaCS Change Password web part
    分享微软官方Demo用的SharePoint 2010, Exchange 2010, Lync 2010虚拟机
    Office 365 的公共网站的一些限制及解决的办法
    SharePoint 2013 关闭 customErrors
    安装 KB2844286 导致SharePoint 2010 XSLT web part 显示出现错误
    安装Office Web Apps Server 2013 – KB2592525安装失败
    如何将hyper-v虚拟机转换成vmware的虚拟机- 转换SharePoint 2010 Information Worker Demonstration and Evaluation Virtual Machine (SP1)
  • 原文地址:https://www.cnblogs.com/ZJOE80/p/12238373.html
Copyright © 2011-2022 走看看