Paxos、2PC辨析

http://www.cnblogs.com/cchust/p/5617989.html

 

Q&A

1.分布式事务与Paxos协议的关系?

    在数据库领域,提到分布式系统,就会提到分布式事务。Paxos协议与分布式事务并不是同一层面的东西分布式事务的作用是保证跨节点事务的原子性,涉及事务的节点要么都提交(执行成功),要么都不提交(回滚)

分布式事务的一致性通常通过2PC来保证(Two-Phase Commit, 2PC),这里面涉及到一个协调者和若干个参与者。第一阶段,协调者询问参与者事务是否可以执行,参与者回复同意(本地执行成功),回复取消(本地执行失败)。第二阶段,协调者根据第一阶段的投票结果进行决策,当且仅当所有的参与者同意提交事务时才能提交,否则回滚。2PC的最大问题是,协调者是单点(需要有一个备用节点),另外协议是阻塞协议,任何一个参与者故障,都需要等待(可以通过加入超时机制)。

Paxos协议用于解决多个副本之间的一致性问题。比如日志同步,保证各个节点的日志一致性,或者选主(主故障情况下),保证投票达成一致,选主的唯一性。简而言之,2PC用于保证多个数据分片上事务的原子性,Paxos协议用于保证同一个数据分片在多个副本的一致性,所以两者可以是互补的关系,绝不是替代关系。对于2PC协调者单点问题,可以利用Paxos协议解决,当协调者出问题时,选一个新的协调者继续提供服务。工程实践中,Google Spanner,Google Chubby就是利用Paxos来实现多副本日志同步。

2.Paxos协议数据同步方式相对于基于传统1主N备的同步方式有啥区别?

      一般情况下,传统数据库的高可用都是基于主备来实现,1主1备2个副本,主库crash后,通过HA工具来进行切换,提升备库为主库。在强一致场景下,复制可以开启强同步(强一致和Paxos没有必然联系,使用Paxos不一定能实现强一致),Oracle和Mysql都是类似的复制模式。但是如果备库网络抖动,或者crash,都会导致日志同步失败,服务不可用。为此,可以引入1主N备的多副本形式,我们对比都是3副本的情况,一个是基于传统的1主2备,另一种基于paxos的1主2备。传统的1主两备,进行日志同步时,只要有一个副本接收到日志并就持久化成功,就可以返回,在一定程度上解决了网络抖动和备库crash问题。但如果主库出问题后,还是要借助于HA工具来进行切换,那么HA切换工具的可用性如何来保证又成为一个问题。基于Paxos的多副本同步其实是在1主N备的基础上引入了一致性协议,这样整个系统的可用性完全有3个副本控制,不需要额外的HA工具。而实际上,很多系统为了保证多节点HA工具获取主备信息的一致性,采用了zookeeper等第三方接口来实现分布式锁,其实本质也是基于Paxos来实现的。

      我这里以MySQL的主备复制一套体系为例来具体说明传统的主备保持强一致性的一些问题。整个系统中主要包含以下几种角色:Master,Slave,Zookeeper-Service(zk),HA-Console(HA),Zookeeper-Agent(Agent)
Master,Slave:分别表示主节点和备节点,主节点提供读写服务,备节点可以提供读服务,或者完全用于容灾。
Zookeeper-Service(zk):分布式一致性服务,负责管理Master/Slave节点的存活信息和切换信息。zk基于zab协议,zab协议是一种一致性协议,与paxos,raft协议类似,它主要有两种模式,包括恢复模式(选主)和广播模式(同步)。一般zk包含N个节点(zk-node),只要有超过半数的zk-node存活且相互连通,则zk可以对外提供一致性服务。
HA-Console:切换工具,负责具体的切换流程
Zookeeper-Agent(Agent):Master/Slave实例上的监听进程,与监听的实例保持心跳,维护Master/Slave的状态,每个实例有一个对应的Agent。大概工作流程如下:
(1).Master/Slave正常启动并搭建好了复制关系,对应的Agent会调用zk接口去注册alive节点信息,假设分别为A和B。
(2).如果此时Master Crash,则实例对应的Agent发现心跳失败,如果重试几次后仍然失败,则将调用zk接口注销掉A节点信息。
(3).HA工具通过zk接口比较两次的节点信息,发现少了A节点,表示A可能不存在了,需要切换,尝试连接A,如果仍然不通,注册A的dead节点,并开始切换流程。
(4).HA工具读取配置信息,找到对应的Slave节点B,(更改读写比配置信息,设置B提供写),打开写。
(5).应用程序通过拉取最新的配置信息,得知新主B,新的写入会写入B。
前面几部基本介绍了MySQL借助zk实现高可用的流程,由于zk-node可以多地部署,HA无状态,因此可以很容易实现同城或者是异地的高可用系统,并且动态可扩展,一个HA节点可以同时管理多个Master/Slave的切换。那么能保证一致性吗?前面提到的Agent除了做监听,还有一个作用是尽可能保持主备一致,并且不丢数据。
(6).假设此时A节点重启,Agent检测到,通过zk接口发现A节点在dead目录下,表示被切换过,需要kill上面的所有连接,并回滚crash时A比B多的binlog,为了尽可能的少丢数据,然后再开启binlog后,将这部分数据重做。这里要注意rollback和replay都在old-Master上面进行,rollback时需要关闭binlog,而replay需要开启binlog,保证这部分数据能流向new-Master。
(7).从第6步来看,可以一定程度上保证主备一致性,但是进行rollback和replay时,实际上是往new-Slave上写数据,这一定程度上造成了双写,如果此时new—Master也在写同一条记录,可能会导致写覆盖等问题。
(8).如果开启半同步呢?old-Master crash时,仍然可能比old-Slave多一个group的binlog,所以仍然需要借助于rollback和replay,依然避免不了双写,所以也不能做到严格意义上的强一致。

3.如何将Paxos应用于传统的数据库复制协议中?

    复制协议相当于是对Paxos的定制应用,通过对一系列日志进行投票确认达成多数派,就相当于日志已经在多数派持久化成功。副本通过应用已经持久化的日志,实现与Master节点同步。由于数据库ACID特性,本质是由一个一致的状态到另外一个一致的状态,每次事务操作都是对应数据库状态的变更,并生成一条日志。由于client操作有先后顺序,因此需要保证日志的先后的顺序,在任何副本中,不仅仅要保证所有日志都持久化了,而且要保证顺序。对于每条日志,通过一个logID标示,logID严格递增(标示顺序),由leader对每个日志进行投票达成多数派,如果中途发生了leader切换,对于新leader中logID的“空洞”,需要重新投票,确认日志的有效性。

4.Multi-Paxos的非leader节点可以提供服务吗?

     Multi-Paxos协议中只有leader确保包含了所有已经已经持久化的日志,当然本地已经持久化的日志不一定达成了多数派,因此对于没有confirm的日志,需要再进行一次投票,然后将最新的结果返回给client。而非leader节点不一定有所有最新的数据,需要通过leader确认,所以一般工程实现中,所有的读写服务都由leader提供。

5.客户端请求过程中失败了,如何处理?

    client向leader发起一次请求,leader在返回前crash了。对于client而言,这次操作可能成功也可能失败。因此client需要检查操作的结果,确定是否要重新操作。如果leader在本地持久化后,并没有达成多数派时就crash,新leader首先会从各个副本获取最大的logID作为恢复结束点,对于它本地没有confirm的日志进行Paxos确认,如果此时达成多数派,则应用成功,如果没有则不应用。client进行检查时,会知道它的操作是否成功。当然具体工程实践中,这里面涉及到client超时时间,以及选主的时间和日志恢复时间。

参考文档

https://ramcloud.stanford.edu/~ongaro/userstudy/paxos.pdf

http://www.cs.utexas.edu/users/lorenzo/corsi/cs380d/papers/paper2-1.pdf
http://research.microsoft.com/en-us/um/people/lamport/pubs/paxos-simple.pdf
https://zhuanlan.zhihu.com/p/20417442
http://my.oschina.net/hgfdoing/blog/666781
http://www.cnblogs.com/foxmailed/p/5487533.html
http://www.wtoutiao.com/p/1a7mSx6.html

猜你喜欢

转载自blog.csdn.net/songchuwang1868/article/details/89973147
2PC