美文网首页程序员我爱编程微服务
Zookeeper是如何保证顺序一致性的

Zookeeper是如何保证顺序一致性的

作者: 68号小喇叭 | 来源:发表于2018-05-28 00:11 被阅读1110次
    zookeeper架构.jpg

    本文适用于对Zookeeper有一定了解且想要了解源码或正在了解源码的同学,花费大约五分钟

    前几天看了一个帖子,讲Zookeeper的顺序一致性,比划了一通数学解释,看的云山雾罩的,在此讲下自己对于顺序一致性的理解

    Zookeeper常被用于分布式协调服务(即服务或元数据注册等场景,如Dubbo、Kafka:将生产者或元数据信息注册到Zookeeper集群上,以便分布式系统其他参与者及时看到,因为Zookeeper实现了类似Paxos的Zab协议,解决了分布式数据一致性问题)、分布式锁等用途

    什么叫顺序一致性:

    假设有一个Zookeeper集群(N>=3,N为奇数),那么只有一个Leader(通过FastLeaderElection选主策略选取),所有的写操作(客户端请求Leader或Follower的写操作)都由Leader统一处理,Follower虽然对外提供读写,但写操作会提交到Leader,由Leader和Follower共同保证同一个Follower请求的顺序性,Leader会为每个请求生成一个zxid(高32位是epoch,用来标识leader选举周期,每次一个leader被选出来,都会有一个新的epoch,标识当前属于哪个leader的统治时期,低32位用于递增计数)

    针对同一个Follower A提交的写请求request1、request2,某些Follower虽然可能不能在请求提交成功后立即看到(也就是强一致性),但经过自身与Leader之间的同步后,这些Follower在看到这两个请求时,一定是先看到request1,然后再看到request2,两个请求之间不会乱序,即顺序一致性

    zookeeper写请求流程.png

    Leader在处理第4步Follower的ack回复时,采用过半数响应即成功原则,也就是这时候有的Follower是还没有处理或者处理成功这个请求的

    那么问题来了,怎么保证顺序一致性的呢?

    • FollowerRequestProcessor为Follower的首个处理器,如果是写请求,先将请求写入commitprocessor的queuedRequests(方便后续commit时判断是否本Follower提交的写请求),然后转Leader
    • Leader为每个请求生成zxid,下发proposal给Follower,Follower会将请求写入到pendingTxns阻塞队列及txnLog中,然后发送ack给Leader
    public void logRequest(TxnHeader hdr, Record txn) {
            Request request = new Request(hdr.getClientId(), hdr.getCxid(), hdr.getType(), hdr, txn, hdr.getZxid());
            if ((request.zxid & 0xffffffffL) != 0) {
                pendingTxns.add(request);
            }
            syncProcessor.processRequest(request);
        }
    

    proposal这步是会发给所有的follower的(放到LearnerHandler的请求处理队列中,一个Follower一个LearnerHandler),之后Follower的ack就不一定全返回了

    • ack过半,Leader发送commit请求给所有Follower,Follower对比commit request的zxid和前面提到的pendingTxns的zxid,不一致的话Follower退出,重新跟Leader同步
    long firstElementZxid = pendingTxns.element().zxid;
            if (firstElementZxid != zxid) {
                LOG.error("Committing zxid 0x" + Long.toHexString(zxid)
                        + " but next pending txn 0x"
                        + Long.toHexString(firstElementZxid));
                System.exit(12);
            }
    
    • Follower处理commit请求,如果不是本Follower提交的写请求,直接调用FinalRequestProcessor做持久化,触发watches;如果是本Follower提交,则做一些特殊处理(主要针对客户端session失效的场景),然后调用FinalRequestProcessor等后续处理流程
    • FinalRequestProcessor做持久化,返回客户端

    总之:Follower通过队列和zxid等顺序标识保证请求的顺序处理,一言不合就会重新同步Leader

    相关文章

      网友评论

      本文标题:Zookeeper是如何保证顺序一致性的

      本文链接:https://www.haomeiwen.com/subject/wfxvjftx.html