Cassandra与Mongo的事务实现之分布式协议

来源:互联网 发布:知乎 情人节送玫瑰由来 编辑:程序博客网 时间:2024/05/16 13:46

摘要

NoSql不同于关系型数据库,是分布式存储,因此想要实现关系型数据库中的事务就不是那么简单了。本文结合Cassandra中的paxos和Mongo的two phase commit来谈谈Nosql如何利用分布式协议来实现事务的。

关系型数据库

读取

脏读

一个事务还未提交,另外一个事务访问此事务修改的数据并使用。
这种现象叫脏读。脏读读取了事务的中间状态数据,违背了隔离性。

幻读(table级别)

一个事务读取2次数据,得到记录条数不一致。
(可能两次读取之间另外一个事务对数据进行了增删)

不可重复读 (行级别)

在一个事务内,多次读同一数据。读取的结果不一样。原因是因为其他事务修改了数据

事务隔离级别

Read uncommitted

读未提交,当事务开始写数据,通过排他写锁来隔离,不允许其他事务同时写,但是允许其他事务读。

只有写锁,这样就可能会出现脏读、幻读、不可重复读

Read committed
读提交,通过排他写锁以及瞬间共享读锁来实现不允许脏读取,即读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。

有写锁+SELECT操作锁,用完释放。解决了脏读,但是可能会出现不可重复读取、幻读

大多数数据库默认级别是Read commited,如Oracle,Sql Server

Repeatable read

通过共享读锁,排他写锁来实现。基于行的读写锁,不要求范围锁,即table级别的锁,所以有可能会有幻读

可序列化

写锁+读锁,范围锁。读写锁直到事务结束后才能释放

Cassandra

Cassandra的paxos机制在这篇译文中已有详细解释了。
下面时序图方便理解。
注意acceptor节点数量由replicate factor数量决定,quorum个返回就是超过一半的replicate factor。
这里写图片描述

Cassandra只能通过轻量级事务来实现行层面的原子性和隔离性。因此没有关系型数据库那么丰富的事务操作,如开启事务,提交事务,和回滚

eg.给mike的账户加一块钱,IF就是Cassandra中的关键字,实现事务的。这样可以确保在事务中正确更改miki的账户。但是如果涉及到转账,两行记录,是实现不了的原子性操作的,因为没有回滚机制的。

UPDATE test.bank SET amount = 2WHERE name = 'mike' AND id = 123 IF amount = 1

mongo

mongo 的原子性是基于document级别,而document又是可以嵌套的,所以基本可以满足大部分情况的原子性要求。但是如果需要实现多个document的的事务。则需要两阶段协议。

2pc(2 phase commit) 两阶段即请求阶段,以及提交阶段。
相比较paxos的Proposer和Acceptor。两阶段协议也包含两种角色,一个是coordinator(协调者),集群中一般只有1个,另外一种角色是workers(参与者)

  1. 请求阶段
    coordinator通知workers准备提交或者取消事务。workers返回应答信号,当所有的workers都返回应答信号了,再进行下一阶段。
  2. 提交阶段
    coordinator根据请求阶段收集到的所有结果,当所有的结果都为提交的时候,就通知所有的workers提交事务,否则取消。

参考

https://docs.mongodb.com/manual/core/write-operations-atomicity/

0 0