海量数据写入——万级并发的订单系统如何分库?( 二 )


相对来说,订单里的商品售卖方(即卖家)所使用的功能并不是优先级最高的 。因为当我们要对卖家和买家的功能做取舍时,卖家是愿意降低优先级的,毕竟卖家是买卖的受益方 。
按购买用户划分后,用户的使用场景都可以直接通过分库支持,而不需要通过异构数据(存在数据延迟)等手段解决,对用户来说体验较好 。其次,在同一个分库中,便于修改同一用户的多条数据,因此也不存在分布式事务问题 。
我们可以通过上述订单案例抽象出一个分库准则:在确定分库字段时应该以直接满足最重要的业务场景为准 。
很多其他的业务都参考了这一准则,比如——

  • 对于微博和知乎等用户生产内容(UGC)的业务,均会按用户进行分库 。因为用户新发布文章后就会去查看列表 。
  • 支付系统里,也会按用户的支付记录进行分库 。
  • 在技术上,比如一个微服务下的监控数据,同样会按微服务进行划分 。同一个微服务的监控数据均存储在一个分库里,你可以直接在一个分库里查看微服务下的所有监控数据 。
上述划分方法虽然直接满足了最重要的场景,但可能会出现数据倾斜的问题,比如出现一个超级客户(如企业客户),购买的订单量非常大,导致某一个分库数据量巨多,就会重现分库前的场景 。这属于最极端的情况之一 。
最细粒度随机分对于倾斜的问题,可以采用最细粒度的拆分,即按数据的唯一标示进行拆分 。
对于订单来说唯一标示即为订单号 。采用订单号进行分库之后,用户的订单会按 Hash 随机均匀地分散到某一个分库里 。这样就解决了某一个分库数据不均匀的问题 。
比如:
  • 按用户的每一条微博随机分库;
  • 按用户的每一笔支付记录随机分库;
  • 同一个微服务里的每一个监控点的数据随机分库 。
采用最细粒度分库后,虽然解决了数据均衡的问题,但又带来了其他问题 。
  • 首先,除了对细粒度查询外,对其他任何维度的查询均不支持 。这就需要通过异构等方式解决,但异构有延迟、对业务是有损的 。
  • 其次,防重逻辑在数据库层面无法支持 。比如用户对同一个订单在业务上只能支付一次这一诉求,在支付系统按支付号进行分库后便不能直接满足了 。因为上述分库方式会导致不同支付单分散在不同的分库里,此时,期望在数据库中通过订单号的唯一索引进行支付防重就不可实施了 。
总之,这两种分库的方式,在解决问题的同时又带来了一些新的问题 。在架构中,没有一种方案是可以解决所有问题的,更多的是根据场景去选择更适合自己的方案 。
作者:你勾哥还是你勾哥
链接:https://juejin.cn/post/6934678641204789285
来源:掘金




推荐阅读