面试题答案
一键面试确保数据一致性的技术手段
- 两阶段提交(2PC):
- 在MongoDB多文档事务开始时,事务协调器(通常是主节点)会记录事务的开始状态。当事务中的各个操作准备完成后,进入第一阶段(准备阶段)。此时,每个参与事务的节点(副本集成员或分片)会执行事务中的操作,并将操作结果标记为“准备好提交”,同时记录相关的日志。
- 在第二阶段(提交阶段),如果所有节点在准备阶段都成功,事务协调器会向所有节点发送提交指令,节点将正式提交事务,持久化数据更改。如果任何一个节点在准备阶段失败,事务协调器会向所有节点发送回滚指令,各节点回滚事务,撤销之前的操作。
- Write Concern:
- 可以通过设置合适的
writeConcern
来控制写入操作的确认级别。例如,设置writeConcern: {w: "majority"}
,表示只有当大多数副本集成员确认写入成功后,才认为写入操作成功。这确保了数据在多数节点上的一致性,即使部分节点出现故障,数据也不会丢失或不一致。
- 可以通过设置合适的
- Read Concern:
- 配合事务使用,通过设置
readConcern
来指定读取操作的一致性级别。例如,readConcern: "local"
表示读取本地节点的数据,可能会读到未提交的数据;而readConcern: "majority"
表示读取多数节点已提交的数据,确保读取到的数据是最新且一致的。
- 配合事务使用,通过设置
不同读写场景下的一致性表现
- 读已提交(Read Committed)场景:
- 写操作:当一个写操作在事务中进行时,只有在事务成功提交后,数据才会对其他事务可见。如果事务回滚,写操作的更改不会持久化。在多文档事务中,所有相关文档的更改遵循原子性原则,要么全部提交,要么全部回滚。
- 读操作:如果设置
readConcern: "majority"
,读操作只会返回已提交的数据。这意味着读操作不会看到其他事务未提交的更改,保证了读已提交的一致性。即使在事务进行过程中,其他并发事务对数据进行了修改但未提交,本事务中的读操作也不会读取到这些未提交的数据。
- 快照读(Snapshot Read)场景:
- 写操作:与读已提交场景类似,写操作在事务提交前对其他事务不可见。不同的是,在快照读场景下,即使在事务进行过程中,其他事务成功提交了对数据的更改,本事务中的读操作仍然读取到的是事务开始时的数据快照。
- 读操作:设置
readConcern: "snapshot"
可以实现快照读。在整个事务期间,读操作始终读取事务开始时的数据版本,不受其他并发事务提交的影响。这对于需要在事务内保持数据一致性视图的场景非常有用,例如复杂的报表生成等,确保在事务执行过程中读取的数据不会因为其他并发事务的修改而发生变化。