面试题答案
一键面试两阶段提交(2PC)
- 原理:
- 第一阶段(投票阶段):协调者向所有参与者发送事务内容,询问是否可以提交事务,参与者检查自身操作能否成功完成,并反馈给协调者。
- 第二阶段(执行阶段):如果所有参与者都返回可以提交,协调者向所有参与者发送提交指令,参与者执行提交操作;如果有任何一个参与者返回不能提交,协调者向所有参与者发送回滚指令,参与者执行回滚操作。
- 优点:
- 简单:实现相对简单,对于开发人员理解和实现事务一致性较为直观。
- 强一致性:能保证事务要么全部成功提交,要么全部回滚,满足强一致性要求。
- 缺点:
- 单点故障:协调者是整个事务的核心,一旦协调者故障,整个事务无法推进,可能导致事务悬而不决。
- 同步阻塞:在整个两阶段过程中,参与者资源一直被锁定,直到事务结束,期间无法处理其他事务,影响系统并发性能。
- 网络问题敏感:任何一次网络故障都可能导致协调者与参与者之间通信中断,从而使事务无法正常完成。
三阶段提交(3PC)
- 原理:
- 第一阶段(CanCommit阶段):协调者向参与者发送CanCommit请求,询问是否可以执行事务提交操作,参与者根据自身情况返回响应。
- 第二阶段(PreCommit阶段):如果所有参与者都返回Yes响应,协调者向参与者发送PreCommit请求,参与者执行事务操作,但不提交,先将Undo和Redo信息记录到日志中。
- 第三阶段(DoCommit阶段):如果协调者收到所有参与者的Ack响应,向参与者发送DoCommit请求,参与者正式提交事务;若协调者在规定时间内未收到所有Ack响应或有参与者返回No响应,则发送Abort请求,参与者回滚事务。
- 优点:
- 减少单点故障影响:通过引入准备阶段,一定程度上减少了协调者故障导致事务悬而不决的情况。当协调者在PreCommit阶段故障,参与者可以根据自身状态进行相应处理,而不像2PC那样完全依赖协调者。
- 提高并发性能:相对2PC,3PC缩短了资源锁定时间,在PreCommit阶段参与者可以释放部分资源,提高了系统并发能力。
- 缺点:
- 实现复杂:相比2PC,3PC增加了一个阶段,逻辑更加复杂,开发和维护成本更高。
- 依然存在网络问题:虽然对协调者故障有一定改进,但网络故障仍可能导致事务异常,如在DoCommit阶段网络故障,部分参与者可能已提交事务,而部分未提交,导致数据不一致。
TCC(Try - Confirm - Cancel)
- 原理:
- Try阶段:尝试执行业务,完成所有业务检查(一致性),预留必须的业务资源。
- Confirm阶段:确认执行业务,不做任何业务检查,直接使用Try阶段预留的资源完成业务操作。
- Cancel阶段:取消执行业务,释放Try阶段预留的业务资源。
- 优点:
- 性能高:不依赖数据库锁,资源锁定时间短,能提高系统并发性能。
- 灵活性:业务代码侵入性相对较小,每个阶段业务逻辑可根据实际需求定制,适用于复杂业务场景。
- 异步化:可以异步执行Confirm和Cancel操作,进一步提升系统性能。
- 缺点:
- 开发成本高:需要业务开发人员手动实现三个阶段的业务逻辑,对开发人员要求较高。
- 一致性依赖业务实现:如果Confirm或Cancel阶段出现异常,需要业务层面自行保证数据一致性,实现不当可能导致数据不一致问题。
本地消息表(可靠消息最终一致性)
- 原理:
- 微服务A在本地事务中向消息表插入一条待发送消息,并执行业务操作。
- 消息表有独立的消息发送服务,定期扫描消息表,将待发送消息发送到消息中间件。
- 微服务B从消息中间件消费消息,执行相应业务操作,并向微服务A发送确认消息。
- 微服务A收到确认消息后,删除消息表中的对应记录;若未收到确认消息,消息发送服务会重试发送消息。
- 优点:
- 实现简单:基于本地事务和消息中间件,对现有业务系统侵入性较小,开发成本相对较低。
- 最终一致性:通过消息重试机制,能保证最终数据一致性。
- 解耦性好:微服务之间通过消息进行异步通信,降低了服务之间的耦合度。
- 缺点:
- 消息延迟:消息的发送、消费存在一定延迟,不适用于对数据一致性要求极高的场景。
- 消息中间件依赖:依赖消息中间件的可靠性,如果消息中间件出现故障,可能影响事务一致性。
最大努力通知
- 原理:
- 发起方在本地事务执行完成后,向接收方发送消息。
- 发起方提供查询操作接口,接收方定期调用该接口查询操作执行结果。如果接收方调用查询接口多次仍未获取到正确结果,发起方进行最大努力重试通知接收方。
- 优点:
- 实现简单:实现逻辑相对简单,对业务系统侵入性小。
- 灵活性高:重试策略可根据业务需求灵活调整。
- 缺点:
- 最终一致性:只能保证最终一致性,无法做到强一致性。
- 依赖查询接口:接收方需要依赖发起方提供的查询接口,增加了接口调用复杂性和维护成本。