2020年,截止目前,我收到了阿里巴巴、腾讯、美团、拼多多、京东、快手等互联网大厂的面试邀请。求职是一场流程很长的拉锯战,涉及岗位选择、简历投递、简历评估、技术面试、HR面试等环节。
我发现在技术面试中事务在面试中出现的次数非常非常多,幸好我面试之前也有所准备。今天结合面试经历写一篇面向面经的数据库事务有关的知识汇总。
事务
一个存取或改变数据库内容的程序执行单元, 或者说是一条或多条SQL语句的一次执行被看作事务。
- 事务是有开始和结束,结束前需要提交或撤销。
例子:
一个事务可以处理一个数据或一条记录。
特性:
-
宏观:独立完整
-
微观:交错执行
ACID特性
原子性:事务中的一组更新操作是原子不可分的,要么全部做,要么全部不做。
一致性:保证事务的操作状态是正确的,符合一致性的操作规则。事务的执行结果必须使数据库从一个一致性状态到另一个一致性状态。
- 不会出现三种典型的不一致性
隔离性:并发执行的多个事务不会相互影响。
持久性: 已提交的事务对数据库的更新是持久的。被撤销事务的影响是可恢复。
- 一个事务撤销后,对磁盘没有影响
并发控制
- 三种典型不一致状态
-
丢失修改
-
不能重复读
-
脏读
-
基于封锁
-
基于撤回
事务调度
并发调度的正确性
可串行性:
- 可串行化的调度
可串行化的等效串行序列不一定唯一
分类
隐式事务:比如insert、delete、update、select等。
显式事务:带有明显的开始和结束的标记。
两阶段提交
二阶提交协议、三阶提交协议 和 Paxos算法。
只有协调者拥有超时机制,即如果在一定时间内没有收到cohort的消息则默认失败。
两阶段提交协议可以保证数据的强一致性,即保证了分布式事务的原子性:所有结点要么全做要么全不做。
它是协调所有分布式原子事务参与者,并决定提交或取消(回滚)的分布式算法。
准备阶段(Prepare Phase)
协调者将通知事务参与者准备提交或取消事务,写本地的redo和undo日志,但不提交,然后进入表决过程。
流程如下:
-
写本地日志“BEGIN_COMMIT”,并进入WAIT状态;
-
向所有参与者发送“VOTE_REQUEST”消息;
-
等待并接收参与者发送的对“VOTE_REQUEST”的响应。参与者响应“VOTE_ABORT”或“VOTE_COMMIT”消息给协调者。
提交阶段(Commit Phase)
协调者将基于第一个阶段的投票结果进行决策:提交或取消。
当且仅当所有的参与者同意提交事务协调者才通知所有的参与者提交事务,否则协调者将通知所有的参与者取消事务。参与者在接收到协调者发来的消息后将执行响应的操作。
流程如下:
-
若收到任何一个参与者发送的“VOTE_ABORT”消息;写本地“GLOBAL_ABORT”日志,进入ABORT状态;向所有的参与者发送“GLOBAL_ABORT”消息。
-
若收到所有参与者发送的“VOTE_COMMIT”消息;写本地“GLOBAL_COMMIT”日志,进入COMMIT状态;向所有的参与者发送“GLOBAL_COMMIT”消息。
-
等待并接收参与者发送的确认响应消息,一旦收到所有参与者的确认消息,写本地“END_TRANSACTION”日志流程结束。
两阶段提交的缺陷
同步阻塞问题。执行过程中,所有参与节点都是事务阻塞型的。
当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
单点故障。由于协调者的重要性,一旦协调者发生故障,参与者会一直阻塞下去。
如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题
数据不一致。
在提交阶段中,当协调者向参与者发送commit请求之后,由于故障导致只有一部分参与者接受到了commit请求。
三段提交
对于协调者(Coordinator)和参与者(Cohort)都设置了超时机制
- CanCommit阶段
协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。
- PreCommit阶段
Coordinator根据Cohort的反应情况来决定是否可以继续事务的PreCommit操作。
假如Coordinator从所有的Cohort获得的反馈都是Yes响应,那么就会进行事务的预执行:
发送预提交请求。Coordinator向Cohort发送PreCommit请求,并进入Prepared阶段。
- 事务预提交。Cohort接收到PreCommit请求后,会执行事务操作
并将undo和redo信息记录到事务日志中。
- 响应反馈。如果Cohort成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令。
假如有任何一个Cohort向Coordinator发送了No响应,或者等待超时后Coordinator没有收到Cohort的响应,那么中断事务。
-
发送中断请求。Coordinator向所有Cohort发送abort请求。
-
中断事务。Cohort收到来自Coordinator的abort请求之后,执行事务的中断。
- DoCommit阶段
执行提交
-
发送提交请求。Coordinator接收到Cohort发送的ACK响应,那么他将从预提交状态进入到提交状态。并向所有Cohort发送doCommit请求。
-
事务提交。Cohort接收到doCommit请求之后,执行正式的事务提交并在完成事务提交之后释放所有事务资源。
-
响应反馈。事务提交完之后向Coordinator发送ACK响应。
-
完成事务。Coordinator接收到所有Cohort的ACK响应之后,完成事务。
中断事务
- Coordinator没有接收到Cohort发送的ACK响应,那么会执行中断事务。
三阶段和两阶段提交协议的不同
三阶段提交是“非阻塞”协议。
三阶段提交在两阶段提交的第一阶段与第二阶段之间插入了一个准备阶段,避免由于协调者发生崩溃或错误参与者处于是否提交或者中止的“不确定状态”所产生的延时问题。
PreCommit是一个缓冲,保证了在最后提交阶段之前各参与节点的状态是一致的。
缺点
如果进入PreCommit后,Coordinator发出的是abort请求,假设只有一个Cohort收到并进行了abort操作,而其他对于系统状态未知的Cohort会根据3PC选择继续Commit,此时系统状态发生不一致性。
Paxos算法
目前还有一种重要的算法就是Paxos算法,Zookeeper采用的就是Paxos算法的改进。
总结
咱们玩归玩,闹归闹,别拿面试开玩笑。
事务在面试中出现的次数非常非常多,一旦问到了,大家一定要回答全面,不要丢三落四,回答到点上。大家面试前要把基础打牢,包括事务的ACID特性,事务的并发控制,事务调度,以及事务的分布式提交。
参考链接:https://www.icourse163.org/learn/HIT-1001578001
参考链接:https://www.cnblogs.com/AndyAo/p/8228099.html