Zookeeper應(yīng)用

Zookeeper

1. Zookeeper概念簡介:

Zookeeper是一個(gè)分布式協(xié)調(diào)服務(wù);就是為用戶的分布式應(yīng)用程序提供協(xié)調(diào)服務(wù)
A、zookeeper是為別的分布式程序服務(wù)的
B、Zookeeper本身就是一個(gè)分布式程序(只要有半數(shù)以上節(jié)點(diǎn)存活,zk就能正常服務(wù))
C、Zookeeper所提供的服務(wù)涵蓋:主從協(xié)調(diào)、服務(wù)器節(jié)點(diǎn)動(dòng)態(tài)上下線、統(tǒng)一配置管理、分布式共享鎖、統(tǒng)一名稱服務(wù)……
D、雖然說可以提供各種服務(wù),但是zookeeper在底層其實(shí)只提供了兩個(gè)功能:
管理(存儲(chǔ),讀取)用戶程序提交的數(shù)據(jù);
并為用戶程序提供數(shù)據(jù)節(jié)點(diǎn)監(jiān)聽服務(wù);
Zookeeper常用應(yīng)用場景:
《見圖》
Zookeeper集群的角色: Leader 和 follower (Observer)
只要集群中有半數(shù)以上節(jié)點(diǎn)存活,集群就能提供服務(wù)

2. zookeeper集群機(jī)制

半數(shù)機(jī)制:集群中半數(shù)以上機(jī)器存活,集群可用。
zookeeper適合裝在奇數(shù)臺(tái)機(jī)器上!?。?/p>

3. 安裝

3.1. 安裝

3.1.1. 機(jī)器部署

安裝到3臺(tái)虛擬機(jī)上
安裝好JDK

3.1.2. 上傳

上傳用工具。

3.1.3. 解壓

su – hadoop(切換到hadoop用戶)
tar -zxvf zookeeper-3.4.5.tar.gz(解壓)

3.1.4. 重命名

mv zookeeper-3.4.5 zookeeper(重命名文件夾zookeeper-3.4.5為zookeeper)

3.1.5. 修改環(huán)境變量

1、su – root(切換用戶到root)
2、vi /etc/profile(修改文件)
3、添加內(nèi)容:
|
export ZOOKEEPER_HOME=/home/hadoop/zookeeper
export PATH=$PATH:$ZOOKEEPER_HOME/bin
|
4、重新編譯文件:
source /etc/profile
5、注意:3臺(tái)zookeeper都需要修改
6、修改完成后切換回hadoop用戶:
su - hadoop

3.1.6. 修改配置文件

1、用hadoop用戶操作
cd zookeeper/conf
cp zoo_sample.cfg zoo.cfg
2、vi zoo.cfg
3、添加內(nèi)容
|
dataDir=/home/hadoop/zookeeper/data
dataLogDir=/home/hadoop/zookeeper/log
server.1=slave1:2888:3888 (主機(jī)名, 心跳端口、數(shù)據(jù)端口)
server.2=slave2:2888:3888
server.3=slave3:2888:3888

4、創(chuàng)建文件夾:
cd /home/hadoop/zookeeper/
mkdir -m 755 data
mkdir -m 755 log
5、在data文件夾下新建myid文件,myid的文件內(nèi)容為:
cd data
vi myid
添加內(nèi)容:
|
1
|

3.1.7. 將集群下發(fā)到其他機(jī)器上

scp -r /home/hadoop/zookeeper hadoop@slave2:/home/hadoop/
scp -r /home/hadoop/zookeeper hadoop@slave3:/home/hadoop/

3.1.8. 修改其他機(jī)器的配置文件

到slave2上:修改myid為:2
到slave3上:修改myid為:3

3.1.9. 啟動(dòng)(每臺(tái)機(jī)器)

zkServer.sh start

3.1.10. 查看集群狀態(tài)

1、 jps(查看進(jìn)程)
2、 zkServer.sh status(查看集群狀態(tài),主從信息)

4. zookeeper結(jié)構(gòu)和命令

4.1. zookeeper特性

1、Zookeeper:一個(gè)leader,多個(gè)follower組成的集群
2、全局?jǐn)?shù)據(jù)一致:每個(gè)server保存一份相同的數(shù)據(jù)副本,client無論連接到哪個(gè)server,數(shù)據(jù)都是一致的
3、分布式讀寫,更新請求轉(zhuǎn)發(fā),由leader實(shí)施
4、更新請求順序進(jìn)行,來自同一個(gè)client的更新請求按其發(fā)送順序依次執(zhí)行
5、數(shù)據(jù)更新原子性,一次數(shù)據(jù)更新要么成功,要么失敗
6、實(shí)時(shí)性,在一定時(shí)間范圍內(nèi),client能讀到最新數(shù)據(jù)

4.2. zookeeper數(shù)據(jù)結(jié)構(gòu)

1、層次化的目錄結(jié)構(gòu),命名符合常規(guī)文件系統(tǒng)規(guī)范(見下圖)
2、每個(gè)節(jié)點(diǎn)在zookeeper中叫做znode,并且其有一個(gè)唯一的路徑標(biāo)識(shí)
3、節(jié)點(diǎn)Znode可以包含數(shù)據(jù)和子節(jié)點(diǎn)(但是EPHEMERAL類型的節(jié)點(diǎn)不能有子節(jié)點(diǎn),下一頁詳細(xì)講解)
4、客戶端應(yīng)用可以在節(jié)點(diǎn)上設(shè)置監(jiān)視器(后續(xù)詳細(xì)講解)

4.3. 數(shù)據(jù)結(jié)構(gòu)的圖

[圖片上傳失敗...(image-e8a62b-1518076423457)]

4.4. 節(jié)點(diǎn)類型

1、Znode有兩種類型:
短暫(ephemeral)(斷開連接自己刪除)
持久(persistent)(斷開連接不刪除)
2、Znode有四種形式的目錄節(jié)點(diǎn)(默認(rèn)是persistent )
PERSISTENT
PERSISTENT_SEQUENTIAL(持久序列/test0000000019 )
EPHEMERAL
EPHEMERAL_SEQUENTIAL
3、創(chuàng)建znode時(shí)設(shè)置順序標(biāo)識(shí),znode名稱后會(huì)附加一個(gè)值,順序號(hào)是一個(gè)單調(diào)遞增的計(jì)數(shù)器,由父節(jié)點(diǎn)維護(hù)
4、在分布式系統(tǒng)中,順序號(hào)可以被用于為所有的事件進(jìn)行全局排序,這樣客戶端可以通過順序號(hào)推斷事件的順序

4.5. zookeeper命令行操作

運(yùn)行 zkCli.sh –server <ip>進(jìn)入命令行工具
[圖片上傳失敗...(image-e71e98-1518076423458)]
1、使用 ls 命令來查看當(dāng)前 ZooKeeper 中所包含的內(nèi)容:
[zk: 202.115.36.251:2181(CONNECTED) 1] ls /
2、創(chuàng)建一個(gè)新的 znode ,使用 create /zk myData 。這個(gè)命令創(chuàng)建了一個(gè)新的 znode 節(jié)點(diǎn)“ zk ”以及與它關(guān)聯(lián)的字符串:
[zk: 202.115.36.251:2181(CONNECTED) 2] create /zk "myData“
3、我們運(yùn)行 get 命令來確認(rèn) znode 是否包含我們所創(chuàng)建的字符串:
[zk: 202.115.36.251:2181(CONNECTED) 3] get /zk

監(jiān)聽這個(gè)節(jié)點(diǎn)的變化,當(dāng)另外一個(gè)客戶端改變/zk時(shí),它會(huì)打出下面的

WATCHER::

WatchedEvent state:SyncConnected type:NodeDataChanged path:/zk

[zk: localhost:2181(CONNECTED) 4] get /zk watch
4、下面我們通過 set 命令來對 zk 所關(guān)聯(lián)的字符串進(jìn)行設(shè)置:
[zk: 202.115.36.251:2181(CONNECTED) 4] set /zk "zsl“

5、下面我們將剛才創(chuàng)建的 znode 刪除:

[zk: 202.115.36.251:2181(CONNECTED) 5] delete /zk

6、刪除節(jié)點(diǎn):rmr

[zk: 202.115.36.251:2181(CONNECTED) 5] rmr /zk

4.6. zookeeper-api應(yīng)用

4.6.1. 基本使用

org.apache.zookeeper.Zookeeper是客戶端入口主類,負(fù)責(zé)建立與server的會(huì)話

它提供了表 1 所示幾類主要方法 :

|

功能

|

描述

|
|

create

|

在本地目錄樹中創(chuàng)建一個(gè)節(jié)點(diǎn)

|
|

delete

|

刪除一個(gè)節(jié)點(diǎn)

|
|

exists

|

測試本地是否存在目標(biāo)節(jié)點(diǎn)

|
|

get/set data

|

從目標(biāo)節(jié)點(diǎn)上讀取 / 寫數(shù)據(jù)

|
|

get/set ACL

|

獲取 / 設(shè)置目標(biāo)節(jié)點(diǎn)訪問控制列表信息

|
|

get children

|

檢索一個(gè)子節(jié)點(diǎn)上的列表

|
|

sync

|

等待要被傳送的數(shù)據(jù)

|

表 1 : ZooKeeper API 描述

4.6.2. demo增刪改查

|

public class SimpleDemo {

// 會(huì)話超時(shí)時(shí)間,設(shè)置為與系統(tǒng)默認(rèn)時(shí)間一致

private static final int SESSION_TIMEOUT = 30000;

// 創(chuàng)建 ZooKeeper 實(shí)例

ZooKeeper zk;

// 創(chuàng)建 Watcher 實(shí)例

Watcher wh = new Watcher() {
public void process(org.apache.zookeeper.WatchedEvent event)
{
System.out.println(event.toString());
}

};

// 初始化 ZooKeeper 實(shí)例

private void createZKInstance() throws IOException

{

zk = new ZooKeeper("weekend01:2181", SimpleDemo.SESSION_TIMEOUT, this.wh);

}

private void ZKOperations() throws IOException, InterruptedException, KeeperException

{

System.out.println("/n1. 創(chuàng)建 ZooKeeper 節(jié)點(diǎn) (znode : zoo2, 數(shù)據(jù): myData2 ,權(quán)限: OPEN_ACL_UNSAFE ,節(jié)點(diǎn)類型: Persistent");

zk.create("/zoo2", "myData2".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

System.out.println("/n2. 查看是否創(chuàng)建成功: ");

System.out.println(new String(zk.getData("/zoo2", false, null)));

System.out.println("/n3. 修改節(jié)點(diǎn)數(shù)據(jù) ");

zk.setData("/zoo2", "shenlan211314".getBytes(), -1);

System.out.println("/n4. 查看是否修改成功: ");

System.out.println(new String(zk.getData("/zoo2", false, null)));

System.out.println("/n5. 刪除節(jié)點(diǎn) ");

zk.delete("/zoo2", -1);

System.out.println("/n6. 查看節(jié)點(diǎn)是否被刪除: ");

System.out.println(" 節(jié)點(diǎn)狀態(tài): [" + zk.exists("/zoo2", false) + "]");

}

private void ZKClose() throws InterruptedException

{

zk.close();

}

public static void main(String[] args) throws IOException, InterruptedException, KeeperException {

SimpleDemo dm = new SimpleDemo();

dm.createZKInstance();

dm.ZKOperations();

dm.ZKClose();

}

}

|

Zookeeper的監(jiān)聽器工作機(jī)制

[圖片上傳失敗...(image-90d58b-1518076423458)]

監(jiān)聽器是一個(gè)接口,我們的代碼中可以實(shí)現(xiàn)Wather這個(gè)接口,實(shí)現(xiàn)其中的process方法,方法中即我們自己的業(yè)務(wù)邏輯

監(jiān)聽器的注冊是在獲取數(shù)據(jù)的操作中實(shí)現(xiàn):

getData(path,watch?)監(jiān)聽的事件是:節(jié)點(diǎn)數(shù)據(jù)變化事件

getChildren(path,watch?)監(jiān)聽的事件是:節(jié)點(diǎn)下的子節(jié)點(diǎn)增減變化事件

4.7. zookeeper應(yīng)用案例(分布式應(yīng)用HA||分布式鎖)

3.7.1 實(shí)現(xiàn)分布式應(yīng)用的(主節(jié)點(diǎn)HA)及客戶端動(dòng)態(tài)更新主節(jié)點(diǎn)狀態(tài)

某分布式系統(tǒng)中,主節(jié)點(diǎn)可以有多臺(tái),可以動(dòng)態(tài)上下線

任意一臺(tái)客戶端都能實(shí)時(shí)感知到主節(jié)點(diǎn)服務(wù)器的上下線

[圖片上傳失敗...(image-27b147-1518076423458)]

A、客戶端實(shí)現(xiàn)

|

public class AppClient {

private String groupNode = "sgroup";

private ZooKeeper zk;

private Stat stat = new Stat();

private volatile List<String> serverList;

/**

  • 連接zookeeper

*/

public void connectZookeeper() throws Exception {

zk

= new ZooKeeper("localhost:4180,localhost:4181,localhost:4182", 5000, new Watcher() {

public void process(WatchedEvent event) {

// 如果發(fā)生了"/sgroup"節(jié)點(diǎn)下的子節(jié)點(diǎn)變化事件, 更新server列表, 并重新注冊監(jiān)聽

if (event.getType() == EventType.NodeChildrenChanged

&& ("/" + groupNode).equals(event.getPath())) {

try {

updateServerList();

} catch (Exception e) {

e.printStackTrace();

}

}

}

});

updateServerList();

}

/**

  • 更新server列表

*/

private void updateServerList() throws Exception {

List<String> newServerList = new ArrayList<String>();

// 獲取并監(jiān)聽groupNode的子節(jié)點(diǎn)變化

// watch參數(shù)為true, 表示監(jiān)聽子節(jié)點(diǎn)變化事件.

// 每次都需要重新注冊監(jiān)聽, 因?yàn)橐淮巫? 只能監(jiān)聽一次事件, 如果還想繼續(xù)保持監(jiān)聽, 必須重新注冊

List<String> subList = zk.getChildren("/" + groupNode, true);

for (String subNode : subList) {

// 獲取每個(gè)子節(jié)點(diǎn)下關(guān)聯(lián)的server地址

byte[] data = zk.getData("/" + groupNode + "/" + subNode, false, stat);

newServerList.add(new String(data, "utf-8"));

}

// 替換server列表

serverList = newServerList;

System.out.println("server list updated: " + serverList);

}

/**

  • client的工作邏輯寫在這個(gè)方法中

  • 此處不做任何處理, 只讓client sleep

*/

public void handle() throws InterruptedException {

Thread.sleep(Long.MAX_VALUE);

}

public static void main(String[] args) throws Exception {

AppClient ac = new AppClient();

ac.connectZookeeper();

ac.handle();

}

}

|

B、服務(wù)器端實(shí)現(xiàn)

|

public class AppServer {

private String groupNode = "sgroup";

private String subNode = "sub";

/**

  • 連接zookeeper

  • @param address server的地址

*/

public void connectZookeeper(String address) throws Exception {

ZooKeeper zk = new ZooKeeper(

"localhost:4180,localhost:4181,localhost:4182",

5000, new Watcher() {

public void process(WatchedEvent event) {

// 不做處理

}

});

// 在"/sgroup"下創(chuàng)建子節(jié)點(diǎn)

// 子節(jié)點(diǎn)的類型設(shè)置為EPHEMERAL_SEQUENTIAL, 表明這是一個(gè)臨時(shí)節(jié)點(diǎn), 且在子節(jié)點(diǎn)的名稱后面加上一串?dāng)?shù)字后綴

// 將server的地址數(shù)據(jù)關(guān)聯(lián)到新創(chuàng)建的子節(jié)點(diǎn)上

String createdPath = zk.create("/" + groupNode + "/" + subNode, address.getBytes("utf-8"),

Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);

System.out.println("create: " + createdPath);

}

/**

  • server的工作邏輯寫在這個(gè)方法中

  • 此處不做任何處理, 只讓server sleep

*/

public void handle() throws InterruptedException {

Thread.sleep(Long.MAX_VALUE);

}

public static void main(String[] args) throws Exception {

// 在參數(shù)中指定server的地址

if (args.length == 0) {

System.err.println("The first argument must be server address");

System.exit(1);

}

AppServer as = new AppServer();

as.connectZookeeper(args[0]);

as.handle();

}

}

|

3.7.2分布式共享鎖的簡單實(shí)現(xiàn)

ü 客戶端A

|

public class DistributedClient {

// 超時(shí)時(shí)間

private static final int SESSION_TIMEOUT = 5000;

// zookeeper server列表

private String hosts = "localhost:4180,localhost:4181,localhost:4182";

private String groupNode = "locks";

private String subNode = "sub";

private ZooKeeper zk;

// 當(dāng)前client創(chuàng)建的子節(jié)點(diǎn)

private String thisPath;

// 當(dāng)前client等待的子節(jié)點(diǎn)

private String waitPath;

private CountDownLatch latch = new CountDownLatch(1);

/**

  • 連接zookeeper

*/

public void connectZookeeper() throws Exception {

zk = new ZooKeeper(hosts, SESSION_TIMEOUT, new Watcher() {

public void process(WatchedEvent event) {

try {

// 連接建立時(shí), 打開latch, 喚醒wait在該latch上的線程

if (event.getState() == KeeperState.SyncConnected) {

latch.countDown();

}

// 發(fā)生了waitPath的刪除事件

if (event.getType() == EventType.NodeDeleted && event.getPath().equals(waitPath)) {

doSomething();

}

} catch (Exception e) {

e.printStackTrace();

}

}

});

// 等待連接建立

latch.await();

// 創(chuàng)建子節(jié)點(diǎn)

thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,

CreateMode.EPHEMERAL_SEQUENTIAL);

// wait一小會(huì), 讓結(jié)果更清晰一些

Thread.sleep(10);

// 注意, 沒有必要監(jiān)聽"/locks"的子節(jié)點(diǎn)的變化情況

List<String> childrenNodes = zk.getChildren("/" + groupNode, false);

// 列表中只有一個(gè)子節(jié)點(diǎn), 那肯定就是thisPath, 說明client獲得鎖

if (childrenNodes.size() == 1) {

doSomething();

} else {

String thisNode = thisPath.substring(("/" + groupNode + "/").length());

// 排序

Collections.sort(childrenNodes);

int index = childrenNodes.indexOf(thisNode);

if (index == -1) {

// never happened

} else if (index == 0) {

// inddx == 0, 說明thisNode在列表中最小, 當(dāng)前client獲得鎖

doSomething();

} else {

// 獲得排名比thisPath前1位的節(jié)點(diǎn)

this.waitPath = "/" + groupNode + "/" + childrenNodes.get(index - 1);

// 在waitPath上注冊監(jiān)聽器, 當(dāng)waitPath被刪除時(shí), zookeeper會(huì)回調(diào)監(jiān)聽器的process方法

zk.getData(waitPath, true, new Stat());

}

}

}

private void doSomething() throws Exception {

try {

System.out.println("gain lock: " + thisPath);

Thread.sleep(2000);

// do something

} finally {

System.out.println("finished: " + thisPath);

// 將thisPath刪除, 監(jiān)聽thisPath的client將獲得通知

// 相當(dāng)于釋放鎖

zk.delete(this.thisPath, -1);

}

}

public static void main(String[] args) throws Exception {

for (int i = 0; i < 10; i++) {

new Thread() {

public void run() {

try {

DistributedClient dl = new DistributedClient();

dl.connectZookeeper();

} catch (Exception e) {

e.printStackTrace();

}

}

}.start();

}

Thread.sleep(Long.MAX_VALUE);

}

}

|

ü 分布式多進(jìn)程模式實(shí)現(xiàn):

|

public class DistributedClientMy {

// 超時(shí)時(shí)間

private static final int SESSION_TIMEOUT = 5000;

// zookeeper server列表

private String hosts = "spark01:2181,spark02:2181,spark03:2181";

private String groupNode = "locks";

private String subNode = "sub";

private boolean haveLock = false;

private ZooKeeper zk;

// 當(dāng)前client創(chuàng)建的子節(jié)點(diǎn)

private volatile String thisPath;

/**

  • 連接zookeeper

*/

public void connectZookeeper() throws Exception {

zk = new ZooKeeper("spark01:2181", SESSION_TIMEOUT, new Watcher() {

public void process(WatchedEvent event) {

try {

// 子節(jié)點(diǎn)發(fā)生變化

if (event.getType() == EventType.NodeChildrenChanged && event.getPath().equals("/" + groupNode)) {

// thisPath是否是列表中的最小節(jié)點(diǎn)

List<String> childrenNodes = zk.getChildren("/" + groupNode, true);

String thisNode = thisPath.substring(("/" + groupNode + "/").length());

// 排序

Collections.sort(childrenNodes);

if (childrenNodes.indexOf(thisNode) == 0) {

doSomething();

thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,

CreateMode.EPHEMERAL_SEQUENTIAL);

}

}

} catch (Exception e) {

e.printStackTrace();

}

}

});

// 創(chuàng)建子節(jié)點(diǎn)

thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,

CreateMode.EPHEMERAL_SEQUENTIAL);

// wait一小會(huì), 讓結(jié)果更清晰一些

Thread.sleep(new Random().nextInt(1000));

// 監(jiān)聽子節(jié)點(diǎn)的變化

List<String> childrenNodes = zk.getChildren("/" + groupNode, true);

// 列表中只有一個(gè)子節(jié)點(diǎn), 那肯定就是thisPath, 說明client獲得鎖

if (childrenNodes.size() == 1) {

doSomething();

thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,

CreateMode.EPHEMERAL_SEQUENTIAL);

}

}

/**

  • 共享資源的訪問邏輯寫在這個(gè)方法中

*/

private void doSomething() throws Exception {

try {

System.out.println("gain lock: " + thisPath);

Thread.sleep(2000);

// do something

} finally {

System.out.println("finished: " + thisPath);

// 將thisPath刪除, 監(jiān)聽thisPath的client將獲得通知

// 相當(dāng)于釋放鎖

zk.delete(this.thisPath, -1);

}

}

public static void main(String[] args) throws Exception {

DistributedClientMy dl = new DistributedClientMy();

dl.connectZookeeper();

Thread.sleep(Long.MAX_VALUE);

}

}

| |

動(dòng)手練習(xí)

5. zookeeper原理

Zookeeper雖然在配置文件中并沒有指定master和slave
但是,zookeeper工作時(shí),是有一個(gè)節(jié)點(diǎn)為leader,其他則為follower
Leader是通過內(nèi)部的選舉機(jī)制臨時(shí)產(chǎn)生的

5.1. zookeeper的選舉機(jī)制(全新集群paxos)

以一個(gè)簡單的例子來說明整個(gè)選舉的過程. 假設(shè)有五臺(tái)服務(wù)器組成的zookeeper集群,它們的id從1-5,同時(shí)它們都是最新啟動(dòng)的,也就是沒有歷史數(shù)據(jù),在存放數(shù)據(jù)量這一點(diǎn)上,都是一樣的.假設(shè)這些服務(wù)器依序啟動(dòng),來看看會(huì)發(fā)生什么.

  1. 服務(wù)器1啟動(dòng),此時(shí)只有它一臺(tái)服務(wù)器啟動(dòng)了,它發(fā)出去的報(bào)沒有任何響應(yīng),所以它的選舉狀態(tài)一直是LOOKING狀態(tài) 2) 服務(wù)器2啟動(dòng),它與最開始啟動(dòng)的服務(wù)器1進(jìn)行通信,互相交換自己的選舉結(jié)果,由于兩者都沒有歷史數(shù)據(jù),所以id值較大的服務(wù)器2勝出,但是由于沒有達(dá)到超過半數(shù)以上的服務(wù)器都同意選舉它(這個(gè)例子中的半數(shù)以上是3),所以服務(wù)器1,2還是繼續(xù)保持LOOKING狀態(tài).
  2. 服務(wù)器3啟動(dòng),根據(jù)前面的理論分析,服務(wù)器3成為服務(wù)器1,2,3中的老大,而與上面不同的是,此時(shí)有三臺(tái)服務(wù)器選舉了它,所以它成為了這次選舉的leader.
  3. 服務(wù)器4啟動(dòng),根據(jù)前面的分析,理論上服務(wù)器4應(yīng)該是服務(wù)器1,2,3,4中最大的,但是由于前面已經(jīng)有半數(shù)以上的服務(wù)器選舉了服務(wù)器3,所以它只能接收當(dāng)小弟的命了.
  4. 服務(wù)器5啟動(dòng),同4一樣,當(dāng)小弟.

5.2. 非全新集群的選舉機(jī)制(數(shù)據(jù)恢復(fù))

那么,初始化的時(shí)候,是按照上述的說明進(jìn)行選舉的,但是當(dāng)zookeeper運(yùn)行了一段時(shí)間之后,有機(jī)器down掉,重新選舉時(shí),選舉過程就相對復(fù)雜了。

需要加入數(shù)據(jù)id、leader id和邏輯時(shí)鐘。

數(shù)據(jù)id:數(shù)據(jù)新的id就大,數(shù)據(jù)每次更新都會(huì)更新id。

Leader id:就是我們配置的myid中的值,每個(gè)機(jī)器一個(gè)。

邏輯時(shí)鐘:這個(gè)值從0開始遞增,每次選舉對應(yīng)一個(gè)值,也就是說: 如果在同一次選舉中,那么這個(gè)值應(yīng)該是一致的 ;邏輯時(shí)鐘值越大,說明這一次選舉leader的進(jìn)程更新.

選舉的標(biāo)準(zhǔn)就變成:

1、邏輯時(shí)鐘小的選舉結(jié)果被忽略,重新投票

2、統(tǒng)一邏輯時(shí)鐘后,數(shù)據(jù)id大的勝出

3、數(shù)據(jù)id相同的情況下,leader id大的勝出

根據(jù)這個(gè)規(guī)則選出leader。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1 Zookeeper概述# ZooKeeper是一個(gè)為分布式應(yīng)用所設(shè)計(jì)的分布的、開源的協(xié)調(diào)服務(wù),它主要是用來解決...
    七寸知架構(gòu)閱讀 7,484評論 0 101
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,554評論 19 139
  • 2017年北京的春天似乎比以往的春天來得早一些。二月下了幾場雨,三月下了一場桃花雪,冷了幾天后便迎來了蘊(yùn)藉華美的春...
    藍(lán)主咖閱讀 599評論 0 5
  • 看瘦枝疏影入衣 隨蝶秀亂舞飛急 閑眠陋室清歌起 月色纖柔淚成熹
    醒骨真人閱讀 406評論 0 1
  • 這是一個(gè)很叼的技能,至少之前我 碰到過 這種情況,但我并不知道它的原理,以及 怎么搞的; 有時(shí)候我們并 不想 讓我...
    _信仰zmh閱讀 3,480評論 0 1

友情鏈接更多精彩內(nèi)容