高并发系统中,分库分表是什么?什么场景需要实践?

最近看到一篇不错文章,能简单明了阐述清楚分库分表的原因和场景。这里结合自己的工作经历,记录些自己的理解,相信对大家平时的工作和架构概念有所帮助,后续应该会抽空推出具体分库分表方案的文章。

在大数据量和高并发系统当中,分库分表是必不可少的技术之一,同时也是BAT大厂面试过程中,经常问的问题。相信很多人听说过分库分表,但具体什么场景下是需要实践分库分表的?

这篇文章,我们将从两个方向:垂直方向 和 水平方向,来聊下这个问题。

1 垂直方向

垂直方向主要看业务,下面聊聊业务的发展跟分库分表的关系。

1.1 单库

在系统初期,业务功能相对来说比较简单,往往只有几个系统模块,我们通常会使用单库。

系统初期的单库架构:在这里插入图片描述

1.2 分表

系统上线之后,随着业务的不断迭代,往往不断地添加新功能。如此导致单表中的字段越来越多,开始变得越来越冗余,不太好维护,管理起来也会出现混乱。这时候我们可以考虑:分表,将用户表拆分为:用户基本信息表 和 用户扩展表,如下图:在这里插入图片描述

这些信息跟用户息息相关,查询的频次非常高。而用户扩展表中存的是用户的扩展信息,比如:所属单位、所在城市等非核心数据,这些信息只有在特定的业务场景才需要查询,而绝大多数业务场景是不需要的。

所以通过分表把核心数据和非核心数据(扩展数据)分开,让表的结构更清晰,职责更单一,更便于维护。

除了按实际业务分表之外,我们还有一个常用的分表原则是:把调用频次高的放在一张表,调用频次低的放在另一张表,比如:订单表和订单详情表。

1.3 分库

假设系统已经上线有漫长时间(一年多)。经历了N个迭代开发,系统功能完善,意味着系统各种关联关系,错综复杂。

此时,如果不赶快梳理业务逻辑,后面会带来很多隐藏问题,这就需要按业务功能,划分不同领域了。把相同领域的表放到同一个数据库,不同领域的表,放在另外的数据库。拆分过程如下:在这里插入图片描述

将用户、商品、物流、订单等相关的表,从原来一个数据库中,拆分成单独的用户库、商品库、物流库和订单库,一共四个数据库。在这里为了看起来更直观,每个库我只画了一张表,实际场景可能有多张表。

这样按业务拆分之后,每块业务只用关注自己相关的表,职责单一,会变得更好维护。

1.4 分库分表

有时候按业务,只分库或只分表是不够的。比如一些银行或券商的金融系统,可能需要按月份和年份汇总,所有用户的资金和流水情况,这里就需要考虑:分库分表,如下图:在这里插入图片描述

如此设计之后,就能很高效地查询出某个用户每个月或每年的资金流水概况了。

2 水平方向

水分方向主要看数据量,下面聊下数据跟分库分表的关系。

2.1 单库

在系统初期,由于用户非常少,所以系统并发量很小。并且表中的数据量也非常少。这时的数据库架构可能如下:在这里插入图片描述

用户读和写数据请求,都是连接同一个数据库,该方案比较适合于并发量低的业务场景。

2.2 主从读写分离

系统上线运行一段时间后,用户数量也会随着增加。理所当然用户的请求中,读数据的请求会占据大部分,写数据的请求占比相对而言很少。数据库连接是有限的,它是非常宝贵的资源。而每次数据库的读写请求,都需要占用至少一个数据库连接,如果读数据请求把连接占用完了,不就写不了数据了?为解决该问题就需要考虑:读写分离。在这里插入图片描述

如上图,所有的写数据的请求,都指向主库master。一旦主库写完数据之后,立马异步同步给slave从库(例如基于Mysql的binlog同步,这里推荐了解下阿里开源框架canal)。这样所有的读数据请求,就能及时从从库中获取到数据了(除非网络有延迟)。

读写分离方案可以很好的解决上面提到的单节点问题,相比单库的方案,能够更好地保证系统的稳定性。因为如果主库挂了,可以升级从库为主库,将所有读写请求都指向新主库,系统又能恢复正常运行。但这里有个问题就是:如果用户量确实有些大,如果master挂了,升级slave为master,将所有读写请求都指向新master。但此时,如果这个新master根本扛不住所有的读写请求,该怎么办?这就需要一主多从的架构,如下图:在这里插入图片描述

上图中我列的是一主两从,如果master挂了,可以选择从库1或从库2中的一个,升级为新master。假如我们在这里升级从库1为新master,则原来的从库2就变成了新master的的slave了。调整之后的架构图如下:在这里插入图片描述

如此就能解决上面的问题了。除此之外,如果查询请求量再增大,我们还可以将架构升级为一主三从、一主四从…等等。

2.3 分库

上面的读写分离方案确实可以解决读请求量大,但写请求很少时,主库master节点扛不住的问题。但假设某个业务,比如:订单库,若下单的请求非常多,即wirte写请求请求量很大,一个master库可能无法承受住这么大的压力。这时就可以考虑:建立多个订单库。订单库的拆分过程如下:在这里插入图片描述

2.4 分表

客户端请求量上来了,带来的势必是数据量的成本上升。即使做了分库,但有可能是单个库,比如:订单库,出现了3000万的数据。

假设使用的是Mysql数据库,单表的数据量最好不要超过500万行。如果有几千万级的数据量,仍然单表来存,性能会变得很差,而数据量太大了,需要建立的索引也会很大,从小到大检索一次数据,会非常耗时和消耗资源。这时候就需要考虑:分表,这样可以控制每张表的数据量,和索引大小。表的拆分过程如下:在这里插入图片描述

2.5 分库分表

当系统运行发展到一定规模,用户并发量大,而且需要存储的数据量也非常多。这时就可以考虑做:分库分表。如下图所示:在这里插入图片描述

如果有订单请求过来,先根据订单id路由到其中一个订单库,然后再定位到某张订单表。

这边简单罗列如下路由算法:

  • 一致性hash算法
  • 根据id取模,比如:id=9,有4张表,则9%4=1,模为1,路由到用户表1;
  • 给id指定一个区间范围,比如:id的值是0-5万,则数据存在表0,id的值是5-10万,则数据存在表1,以此类推;

3 真实案例

结合真实场景,体验下分库分表项目经历,给有需要的朋友一个参考。

3.1 分库

目前所在的公司,负责过一个平台项目,公司的运营团队通过此平台来处理日常的线上销售订单。但这个平台对接的订单来源分好几个渠道:如天猫旗舰店、京东自营店、公司自己的商城等。

由于各个渠道的各种类型的订单错综复杂,即考虑按来源,划分不同渠道订单,把某渠道的表放到同一个数据库,这里采用了方案:按渠道来源分库,数据库中的表结构允许存在差异。在这里插入图片描述

3.2 分表

我们公司自己的商城的会员体系中,有一块业务:积分,相信没有商城没有积分这功能模块吧。

用户的积分来源非常多,如:签到、转盘抽奖、分享、阅读文章;使用场景也很多:如参与抽奖、积分商城兑换。

如此,产生的用户积分流水随着时间的推移,将越来越大。当时就考虑:水平方向的数据量可能会很大,但是并发量并不大,不像搞活动时下订单接口那样。所以采用方案:分表。
在这里插入图片描述
一个积分数据库,分了32张表。然后根据用户id,进行hash除以32取模。

3.3 分库分表

随着线上每天生产的订单量越来越大,特别是订单的操作日志表记录数更是订单表的几倍,这时候即需要考虑对订单表和订单记录表进行数据分库分表。

经过调研之后,决定使用了开源的基于jdbc的中间件框架:sharding-jdbc。

当时分了3个库,每个库有30张表。
在这里插入图片描述

4 总结

上面主要从:垂直和水平两个方向介绍了具体在哪些场景下,咱们在设计软件项目架构时应该如何分库分表,以解决现实中的业务问题。

  • 分库:是为解决高并发量场景中,数据库连接不够和磁盘IO的性能瓶颈问题;
  • 分表:是为解决单表数据量过大,数据库在执行sql语句查询时,即便用到索引也非常耗时,响应很慢的问题。
  • 分库分表:可以解决高并发数据库连接不够、磁盘IO的性能瓶颈、检索查询耗时和资源消耗等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值