1. 程式人生 > >zookeeper兩個經典問題-帶著問題看原始碼

zookeeper兩個經典問題-帶著問題看原始碼

1. 機器1,機器2,機器3.

   機器3是Leader.

   機器3接受到a,b,c訊息.

   機器2接受到a的proposal和commit. 沒有收到b的訊息.

   當收到c的proposal和commit時會怎麼辦? 資料是否錯亂?

2. zk資料同步是拉取還是推送?

3.機器1,2,機器3

機器3是Leader. 機器2斷開了. 機器2重新選舉,連線到Leader上,同步相關資料.

相關程式碼如下:

執行緒A:

synchronized public void processSync(LearnerSyncRequest r){
synchronized public long 
startForwarding(LearnerHandler handler,...){ ...
  addForwardingFollower(handler);  //加入到轉發佇列之後,leader才會將proposal和commit資料提交.
...
}
synchronized public void processAck(long sid, long zxid, SocketAddress followerAddr) {}

執行緒B:

/**
 * send a packet to all the followers ready to follow
 * 
 * @param qp
* the packet to be sent */ void sendPacket(QuorumPacket qp) { synchronized (forwardingFollowers) { for (LearnerHandler f : forwardingFollowers) { f.queuePacket(qp); } } }
  • Leader.sendPacket(QuorumPacket) (org.apache.zookeeper.server.quorum)
  •   呼叫方1 Leader.propose(Request) (org.apache.zookeeper.server.quorum)
  •   呼叫方1 Leader.commit(long) (org.apache.zookeeper.server.quorum)
 同步資料推送完畢,但是因為時間差後續新的proposal請求和commit又沒有推送給Follower.

  例如 Leader 有 a(已提交) b(已多數通過但未提交) c(已prososal但未多數通過) 三個訊息.

    此時Follower將三個資料都同步過來. 此時Leader對c進行commit, 又接受了一個d的proposal. 都沒有發到機器2.

   此時機器2上的 queuedList為 a,b,c ; commitList為a,b;

   然後Leader收到d的半數通過,發給機器2 d的commit ;

   此時機器2上的 queuedList為 a,b,c ; commitList為a,b d.

  請問這種情況會發生麼?

答案:

1.答案在zookeeper的原始碼實現裡.

    zk依賴於長連線進行叢集間通訊.

     一旦資料沒有傳送到,就代表連線斷了. 拋異常,重啟.

2.

執行緒A:

synchronized public void processSync(LearnerSyncRequest r){
synchronized public long startForwarding(LearnerHandler handler,...){
 ...
  addForwardingFollower(handler);  //加入到轉發佇列之後,leader才會將proposal和commit資料提交.
...
}
synchronized public void processAck(long sid, long zxid, SocketAddress followerAddr) {}

執行緒B:

/**
 * send a packet to all the followers ready to follow
 * 
 * @param qp
*                the packet to be sent
 */
void sendPacket(QuorumPacket qp) {
    synchronized (forwardingFollowers) {
        for (LearnerHandler f : forwardingFollowers) {                
            f.queuePacket(qp);
        }
    }
}
  • Leader.sendPacket(QuorumPacket) (org.apache.zookeeper.server.quorum)
  •   呼叫方1 Leader.propose(Request) (org.apache.zookeeper.server.quorum)
  •   呼叫方1 Leader.commit(long) (org.apache.zookeeper.server.quorum)

不會因為有鎖.

  訊息c的commit肯定會同步給機器2