分库分表带来的挑战

上一节介绍了分库分表的的产生背景,以及遇到的一些问题,本节对上节遇到问题进行一个总结并给出一些解决方案。

问题列表

引入分布式事务的问题
跨节点join的问题
跨节点排序分页的问题
高并发下原子性的问题

以上是对分库分表遇到一些问题进行了汇总,下面对这些问题以及对应的解决方案一一讲解。

引入分布式事务的问题

同一应用系统-引入分布式事务的问题

image

如图所示,这是一个注册操作步骤,注册服务由两个原子服务组成,分别为:

  1. 登录标识原子服务
  2. 认证信息原子服务。

其中登录标识对应的登录标识表对应分片键为登录标识,因为为了快速登录,所以不会以用户ID作为分片键。认证信息原子服务对应的分片键为用户ID,那么这种流程,就会引发分布式事务问题,那么针对此类场景是怎么解决。

同一应用系统-分布式事务解决方案

image

以上为注册服务的注册流程,首先调用登录标识原子服务,如果处理成功,则调用认证信息原子服务,如果失败则返回。

假如处理成功,并调用了认证信息原子服务,此时成功,则流程注册完成,给前端返回结果。

如果操作失败,那么就需要调用冲正服务,对第一步登录标识进行删除,一般情况都会成功,如果遇到极端情况,假如数据库down机,这会推送异常消息至监控平台进行报警,从而人为介入解决。

多系统交互-分布式事务问题

image
上图所示,为开户服务操作步骤,涉及到三个系统。

通过分析,如果采用上篇介绍的方案同步调用,那么会使处理时间拉长,对客户体验不好,同时系统处理能力也会下降。

如果在调用环节中有一个系统出现问题,就会导致各系统中数据状态不一致,而如果采用上篇介绍的冲正方案,处理时间会更加长,从而导致超时,那么针对此类问题,一般是基于消息最终一致性来解决的。

分布式事务解决方案-基于消息的最终一致性

我们知道分布式系统中的CAP理论,分别为

  1. Consistency(一致性), 数据一致更新,所有数据变动都是同步的
  2. Availability(可用性), 好的响应性能
  3. Partition tolerance(分区容错性) 可靠性

任何分布式系统只可同时满足二点,没法三者兼顾。
如果满足一致性,那么就需要在可用性和分区容错性,做出选择。

如果选择可用性,也就需要避免分区容错性的发生,那么需要将所有事务相关的东西都放在一台机器上,也就说把开户设计的表全部放在一个库中,由一个系统完成。这种情况下虽然分区容错性的可以避免,但是我们系统从分布式系统退化成了单机系统,从根本上失去了扩展性。

如果选择分区容错,一旦遇到分区事件,受影响的服务需要等待数据一致,因此等待期间,无法对外提供服务。而一个系统如果对外提供不了服务,是非常重大的事故,所以是不能接受的。

那么有什么方法,能解决这些问题呢,eBay架构师源于对大规模分布式系统的实践总结,在ACM上发表了BASE理论,
BASE理论是指

  1. Basically Available(基本可用)
  2. Soft state(软状态)
  3. Eventually consistent(最终一致性)

BASE理论是对CAP的延伸,核心思想是即使无法做到强一致性,但应用可以采取适当的方式来达到最终一致性。

我们这里分享的基于消息中间件的处理方式,就是最终一致性的体现。
image
如图所示,假如这里A系统为电子账户系统,B系统为客户信息系统,A系统开立电子账户后,保存需要发送消息的数据至消息发送表中,并提交事务后发送至MQ,本次交易就完成了。

剩下的操作由MQ推送至客户信息系统或者客户合约系统,这里以客户信息系统为例,系统拿到消息后,进行数据保存,保存成功,并调用MQ的签收操作,同时拿到此消息进行客户等级升级操作,如果操作失败,那么会有定时检查任务,检查消息消费状态,并进行调起,再次进行升级操作。

因为这种方式是有一定延时,所以业务上要多做一些考量,从而不影响客户体验。

跨节点Join的问题1-解决方案

image

以上是一个联表查询中,以一张关联表的分片键做为查询条件的场景,那么针对此类场景解决方案,就是拆分为多步。

  1. 根据分片键获取到对应另一张表的分片键。
  2. 根据返回分片键查询另一张表的数据。
  3. 对多张表的结果进行聚合。

这样跨节点join的问题就解决了。

跨节点Join的问题2-解决方案

image

以上是一个联表查询中,是没有分片键做为查询条件的场景,那么针对此类场景解决方案,也是拆分为单表的查询语句,并进行并行调用,同时从多个节点进行获取,然后在进行聚合。

注意,如果关联的表比较多,不建议所有的表都进行并行调用,因为这样很占数据库的连接数,可以采用以下方式操作,例如:首先拆分多个表语句,然后第一条语句并行访问,获取结果,并根据结果获取到关联表的分片键,在进行数据获取,最后在进行多张表的结果聚合

跨节点排序分页的问题

image

test表有数据[1,2,3,4,5,6,7,8],在单库的时候,查询第2页数据并且显示2条,语句是这样的

select * from test  order by id limit 2,2;

数据返回[3,4],但是数据切分以后,如果要查询,这样语句就可能就会有问题,例如:在节点1执行此语句,返回[5,7],节点2返回[6,8],然后在进行排序,返回了[5,6],所以结果就不准确了,所以应该对sql语句改写为:

select * from test  order by id limit 0,4;

然后在根据各节点返回的数据,在进行排序,筛选出第2页的2条。
这种有什么问题呢,

  • 每个节点返回更多的数据,增大了网络传输量
  • 服务层还需要进行二次排序,增大了服务层的计算量
  • 随着页码的增大,性能会急剧下降
    所以开发时,应尽量避免这种需求,以其它的方式来满足,如果非要实现,可以采用业务折中的方式,如静止跳页
select * from test where id>0 limit 2;

根据id值进行排序,返回对应的条数,在内存中对各个节点返回的数据进行排序,得到需要的数据,相比以前的方案,貌似跟以前处理流程一样,
但是在查询第二页时,根据上一页的id的最大值id_max,作为第二页的最小值,会将

select * from test  order by id limit 2,2;

改写成:

select * from test order by id> $id_max limit 2

这样每个节点不用返回4页数据了,只需要返回跟第一页一样页数的数据,可以看到通过对业务的折中,性能得到大大的提升。

高并发下多节点原子性问题

image
如上图所以,这种一个实名认证的交易场景,实名认证成功则插入到对应的客户表中,客户表分片键为用户ID,身份证是唯一索引,但是它只能保证在单个节点的唯一性,不能保证多个节点的唯一性,所以以上场景有可能会插入两条重复的数据。

为了解决保证多个节点的数据的唯一性,可以通过分布式锁来解决,redis、zookeeper都有提供分布式锁的功能
image
如上图,在进行认证时,首先登记身份证号至redis,如果缓存中没有此身份证则登记成功,在进行下一步操作,否则失败。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值