日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

zookeeper中展示所有节点_分布式协调服务之Zookeeper

發布時間:2025/3/12 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 zookeeper中展示所有节点_分布式协调服务之Zookeeper 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

??理論篇

一、基礎概念

ZooKeeper是開源分布式協調服務,提供高可用、高性能、穩定的分布式數據一致性解決方案,通常被用于實現諸如數據發布/訂閱、負載均衡、命名服務、分布式協調/通知、集群管理、Master選舉、分布式鎖和分布式隊列等功能。

二、ZooKeeper數據模型

image.png

2.1 znode(數據節點)

Zookeeper中所有存儲的數據由znode組成,節點也成為znode,并以key value鍵值對形式存儲數據。整體結構類似linux文件系統,根路徑以/開頭。

znode中數據的讀寫都是原子的,而且每一個znode都有一個Access Control List(ACL)用來限制誰可以做什么。每一個znode的數據大小不能超過1M

2.1.1 znode數據節點名稱規范
  • null 字符(即\u0000)不能組成znode節點path的命名
  • \ud800 - uF8FF, \uFFF0 - uFFFF, \u0001 - \u001F 以及 \u007F、\u009F 這些玩意無法很好地進行展示,看起來像亂碼
  • "."可以構成命名的一部分,但是不能單獨作為path的命名
  • "zookeeper"是保留字
2.1.2 znode數據節點組成:
  • stat 狀態屬性組成:
屬性名稱屬性描述
czxid創建節點的事務ID
mzxid節點最后一次修改的事務ID
pzxid子節點列表最后的一次修改(子節點列表的增加或刪除)的事務ID
ctime創建節點的時間,單位:毫秒
mtime節點最后一次修改的時間,單位:毫秒
version節點數據變更的次數
cversion子節點變更的次數
aversion節點ACL變更的次數
ephemeralOwner如果節點是臨時節點, 則此值為創建該節點的session的id,否則為0
dataLength節點數據長度
numChildren子節點個數
  • data
  • children
2.1.3 znode數據節點類型:
  • 持久節點(Persistent Nodes)

  • 臨時節點(Ephemeral Nodes) 臨時節點的生命周期即為創建這些節點的會話生命周期,即會話結束,則這些節點就會被刪除。所以臨時節點不允許創建子節點。

  • 順序節點(Sequence Nodes ) 順序節點可以是持久的,也可以是臨時的。在創建節點時,可為節點路徑添加一個單調遞增計數器,Zookeeper將通過將10位的序列號附加到原始節點名稱后來設置節點路徑。

  • 容器節點(Container Nodes) 此類型節點是3.6.0版本之后添加,容器節點是一種有特殊用途的節點,可用于leader選舉和分布式鎖等,當容器中最后一個子節點被刪除,此容器節點將會在未來某個時刻被刪除。

  • 超時過期節點(TTL Nodes) 此類型節點是3.6.0版本之后添加,當創建一個持久節點或者順序持久節點時,可以為其設置一個毫秒級的超時過期時間,如果在設置時間內,此節點沒又被修改過而且也沒有子節點,則此節點將作為候選項,在未來某個時刻被刪除。當然TTL Nodes默認是禁用狀態的。

三、Zookeeper Time

Zookeeper中時間有很多表示時間的方式。

  • Zxid 事務ID。Zookeeper狀態的每次變化都會收到這樣一個事務ID

  • Version numbers

  • Ticks

  • Real time

四、ZooKeeper Sessions (會話)

Zookeeper客戶端通過

五、ZooKeeper Watches (監聽)

5.1 watch基本概念

Zookeeper所有讀相關操作:getData()、getChildren()、 exists()等都有一個參數boolean watch用來設置watche。按照讀的內容不同,有兩種watch:Data WatchChild Watch,像getData()和exists()這種屬于讀取znode數據,所以屬于Data Watch,所以當znode數據發生變更,將觸發znode的Data Watch;getChildren()對應的就是Child Watch。創建子節點將觸發父節點的Child Watch,而節點的刪除將同時觸發Data Watch和Child Watch。

Watch是一個一次性觸發器,比如當調用 getData("/znode1", true) 后--true代表設置監聽,該節點被刪除或者數據發生變更,將會觸發客戶端注冊的watch,觸發之后,將被刪除,也就是往后數據再變化就不會再觸發此watch了。

5.2 watch 事件類型

那么當觸發watch的時候有因為數據發生變化的,有因為節點創建或刪除的等等,客戶端如何判斷服務端觸發的watch是各種類型呢?zookeeper提供了EventType的枚舉,服務端觸發watch時,會告訴客戶端是何種類型。

一共有如下這么多事件類型:

  • None
  • NodeCreated
  • NodeDeleted
  • NodeDataChanged
  • NodeChildrenChanged
  • DataWatchRemoved
  • ChildWatchRemoved
  • PersistentWatchRemoved

其中最后三個事件類型:DataWatchRemoved、ChildWatchRemoved、PersistentWatchRemoved分別是刪除不同類型的watch的時候事件類型,從單詞字面意思也應該能夠理解。

5.3 永久遞歸watch

3.6.0之后(包括3.6.0) 客戶端可以通過addWatch()為znode設置永久、遞歸的watch,這意味著watch不再是一次性的了,可以多次觸發不會被刪除,并且還會遞歸觸發。當然也有移除永久watch的機制:removeWatches()

watch是維護在zookeeper服務端的,所有當客戶端與服務端斷鏈,將不會接受到watch的觸發,而當重連后都將恢復可以重新觸發。

5.3 關于watch的一些注意事項?

1.標準watch是一次性的,如果當客戶端接收到watch的回調通知,那么此watch將被刪除,如果客戶端還想接收到通知,則需要注冊另一個watch

2.正如第一條所講,在客戶端接收到watch回調通知時,可能會繼續設置一個watch以監聽znode的下次變更,但是假如在接收到watch和發送請求設置新watch的中間,znode發生了多次變化,這個可能客戶端會接收不到此變更通知。

3.如果為比如exist、getData注冊了同一個watch,那么當watch被刪除的時候,僅會觸發一次delete watch事件

六、ZooKeeper access control using ACLs(權限控制器)

ACL全稱Access Control List,即訪問控制列表。Zookeeper的ACL實現很類似與UNIX的文件系統權限控制。每一個ACL針對指定的znode,但是并不針對指定znode的子節點,也就是ACL并不遞歸生效。假如給/app設置了一個ACL,那么/app/childtest將不受此ACL控制。

權限的表達式為scheme:id, permissions

6.1 scheme-->授權策略

授權策略一共有4種

授權策略含義
world默認策略。任何人都可以訪問
auth即已經認證通過的用戶
digest通過使用MD5進行哈希 username:password格式生成的字符串來進行身份驗證,當進行身份驗證時,是使用usename:password明文形式字符串,當用做ACL驗證時,會先經過base64編碼,然后使用SHA1加密
ip使用客戶端IP作為ACL身份標識。其格式為addr/bits,bits代表客戶端的IP地址要至少匹配ACL中IP地址的多少位
x509

6.2 id-->授權對象

6.3 permissions-->權限點

權限點含義
CREATE可以創建子節點
READ可以獲取znode數據,以及znode的子節點列表
WRITE可以為znode設置數據
DELETE可以刪除znode的子節點
ADMIN可以為znode設置ACL,ADMIN就像是znode的owner

六、ZooKeeper ?Consistency Guarantees(一致性保障)

Zookeeper是高性能、可擴展的服務,它的讀操作和寫操作都非常的快

6.1 Sequential Consistency(順序一致性)

來自客戶端的更新將會按照順序進行處理

6.2 Atomicity (原子性)

6.3 Single System Image(單一系統鏡像)

無論客戶端連接到哪一個服務器上,其看到的服務端數據模型都是一致的

6.4Reliability(可靠性)

一旦更新請求被處理,更改的結果將會持久化

6.5 Timeliness (及時性)


??實戰篇

一、下載安裝

1.1 下載

下載地址:https://zookeeper.apache.org/releases.html#download [apache-zookeeper-3.6.2-bin.tar.gz](https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.6.2/apache-zookeeper-3.6.2-bin.tar.gz)

1.2 單機模式

1.2.1 設置配置文件

在conf目錄下會有一個zoo_sample.cfg文件,這里提供了樣例配置信息,我們只需要將此文件改名為zoo.cfg,這樣才會被zookeeper識別。該配置文件中的配置項說明:

  • tickTime 單位:毫秒。是服務器之間或客戶端與服務器之間維持心跳的時間間隔;且最小會話超時時間將是tickTime的兩倍

  • dataDir zookeeper保存的數據的目錄地址,默認情況下,事務log也會記在這里(除非另外指定)

  • clientPort 客戶端連接服務端的端口 zoo.cfg示例

tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
1.2.2 啟動zookeeper服務端(前提是需要保證安裝機器上有JDK)
./zkServer.sh?start
1.2.3 客戶端連接服務器
./zkCli.sh?-server?127.0.0.1:2181

1.3 集群模式

zookeeper集群部署可以獲得高可靠性,要想實現高可靠容錯好集群,至少需要3臺服務器,且集群數量最好為奇數。

1.3.1 設置集群配置文件zoo.conf
tickTime=2000
dataDir=/var/lib/zookeeper/
clientPort=2181
initLimit=5
syncLimit=2
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888

除了單機模式中需要配置的那幾個參數外,需要配置和集群相關的參數

  • initLimit 表示集群中的followers服務器 在連接leader服務器時,經過最大initLimit個tickTime后,若leader還未接收到followers的信息,則認為連接失敗
  • syncLimit 表示集群中follower服務器與leader服務器在同步消息時最大syncLimit*tickTime時間間隔未收到響應,則此follower會被拋棄
  • server.id=host:port:port 配置文件中每行的server.id=host:port:port共同組成一個集群。這里有兩個端口,前面的端口用于與集群leader連接的端口,后面的端口用于leader選舉。如果想在同一臺機器上搭建偽集群,則第一個端口不同即可

1.3.2 設置myid文件

myid文件中只有一行內容,且這行內容就是上述配置server.id=host:port:port 中的id,在集群模式下該id不可重復,范圍為1-255,將此文件放在dataDir參數表示的目錄下

1.3.3 查看服務器狀態

./zkServer.sh?status
followerleader

1.3.4 搭建集群過程遇到的問題

在搭建集群的時候,啟動三臺機器都顯示啟動成功,但是使用客戶端命令也連接失敗,通過./zkServer.sh status 顯示Error contacting service. It is probably not running.查看logs下的日志,發現有這么一行:Exception when following the leader java.io.EOFException。查資料發現是我將客戶端端口和follower服務器與leader服務器通信的端口混到一起了,如下圖配置的相同,所以出現了這種錯誤,所以這兩個端口不可以相同

錯誤配置

二、zk客戶端 操作 Zookeeper及基礎命令

2.1 bin/zkServer.sh

./zkServer.sh [--config]startstart-foreground|stop|version|restart|status|print-cmd

用于操作zk服務器相關,不同的參數代表不同的操作

#啟動zk服務器
bin/zkServer.sh?start

#重啟zk服務器
bin/zkServer.sh?restart

#停止zk服務器
bin/zkServer.sh?stop

#查看zk運行狀態
bin/zkServer.sh?status

#查看zk版本信息
bin/zkServer.sh?version

2.2 bin/zkCli.sh

  • 啟動客戶端連接zk服務器
bin/zkCli.sh?-server?{host}:{port}

2.3 客戶端命令

  • ls列出指定路徑下所有子節點 ls [-s] [-w] [-R] path
#列出根路徑下所有節點
ls?/
#列出指定路徑節點下的子節點同時,輸出指定路徑節點狀態細膩些
ls?-s?/
  • get查看指定路徑節點信息 get [-s] [-w] path
#查看/node1節點信息
get?/node1
#?查看/node1節點信息及狀態信息
get?-s?/node1
  • create創建節點 create [-s] [-e] [-c] [-t ttl] path [data] [acl] 可選參數 -s 代表創建順序節點 可選參數 -e 代表創建臨時節點 可選參數 -c 代表創建容器節點 可選參數 -t 設置節點過期時間
#?創建路徑為/node1,數據為data的持久節點
create?/node1?data
  • set修改節點 set [-s] [-v version] path data 可選參數-s代表更新節點后,輸出節點狀態信息 可選參數-v用來表示根據版本號進行更新,低版本肯定是無法更新高版本節點的(樂觀鎖)
#創建/node2節點
[zk:?localhost:2181(CONNECTED)?27]?create?/node2?data
Created?/node2
#查看/node2節點狀態信息
[zk:?localhost:2181(CONNECTED)?28]?get?-s?/node2
data
#...省略其他信息
dataVersion?=?0
#...省略其他信息
#更新節點,此時版本號為1
[zk:?localhost:2181(CONNECTED)?29]?set?-s?/node2?data2
#...省略其他信息
dataVersion?=?1
#...省略其他信息
[zk:?localhost:2181(CONNECTED)?30]?set?-v?1?/node2?data3
#更新失敗
[zk:?localhost:2181(CONNECTED)?31]?set?-v?1?/node2?data3
version?No?is?not?valid?:?/node2
[zk:?localhost:2181(CONNECTED)?32]?
  • deletedelete [-v version] path 刪除節點 因為刪除本身也是更新的意思,-v參數同上set的-v參數
#刪除/node2節點
delete?/node2

三、Java 操作 Zookeeper

通過Java操作Zookeeper有兩種方式,一種就是通過Zookeeper提供的原生API(鏈接)進行操作,一種就是通過Apache Curator(官網) ---進行操作。

3.1 Apache Curator是什么

Apache Curator是比較完善的Zookeeper客戶端框架,針對Zookeeper原生API的封裝和擴展,降低了使用 Zookeeper的復雜性,使得使用Zookeeper更加可靠、更加簡單。Curator有很多不同的artifacts,可以根據我們的需要進行引入使用:

  • curator-recipes 該artifact包含了對Zookeeper的所有操作,大部分場景只需要使用該artifact即可滿足需求。

  • curator-framework 針對zookeeper的高級功能的簡化封裝,該artifact構建在整個客戶端之上,所有應該自動包含此模塊

  • curator-client 對于Zookeeper客戶端鏈接相關操作的封裝

3.2 使用apache-curator操作zookeeper

3.2.1 引入pom
org.apache.curatorcurator-recipes5.1.0

5.1.0版本對應的zookeeper客戶端版本為3.6.0

3.2.2 創建連接

創建鏈接需要zk host地址,需要重試策略,還可以設置一些諸如超時時間等等參數。創建客戶端連接的入口類是CuratorFrameworkFactory,該類中有一個內部靜態類Builder,用于設置連接的一些額外高級參數。重試策略則是RetryPolicy。

????public?static?CuratorFramework?createWithOptions(String?connectionString,?RetryPolicy?retryPolicy,?int?connectionTimeoutMs,?int?sessionTimeoutMs){
????????return?CuratorFrameworkFactory.builder()
????????????????.connectString(connectionString)
????????????????.retryPolicy(retryPolicy)
????????????????.connectionTimeoutMs(connectionTimeoutMs)
????????????????.sessionTimeoutMs(sessionTimeoutMs)
????????????????.build();
????}

3.2.3 創建節點,更新節點內容

????/**
?????*?創建持久性節點
?????*?@param?client?CuratorFramework
?????*?@param?path?節點路徑
?????*?@param?payload?節點內容
?????*?@throws?Exception
?????*/
????public?static?void?create(CuratorFramework?client,?String?path,?byte[]?payload)?throws?Exception?{
????????client.create().forPath(path,?payload);
????}

更多參考官方示例:https://github.com/apache/curator/tree/master/curator-examples/src/main/java/framework

??應用篇

一、應用場景

  • 命名服務:按名稱標識集群中的節點
  • 統一配置管理
  • 數據發布/訂閱
  • 分布式鎖
  • Leader 選舉

二、通過Zookeeper實現統一配置管理

三、通過Zookeeper實現分布式鎖

Apache Curator針對分布式鎖提供了多種實現

  • InterProcessMutex:分布式可重入排它鎖
  • InterProcessSemaphoreMutex:分布式排它鎖
  • InterProcessReadWriteLock:分布式可重入讀寫鎖
  • InterProcessMultiLock:將多個鎖作為單個實體管理的容器

3.1 代碼實戰

3.1.1 分布式可重入排它鎖
/**
?*?@author?miaomiao
?*?@date?2020/10/25?11:15
?*/
public?class?DistributReetrantLock?{

????private?final?InterProcessMutex?interProcessMutex;
????private?final?String?lockPath;

????public?DistributReetrantLock(CuratorFramework?client,?String?lockPath)?{
????????this.lockPath?=?lockPath;
????????//?此InterProcessMutex構造方法的maxLeases為1,表示為排他鎖
????????this.interProcessMutex?=?new?InterProcessMutex(client,?lockPath);
????}

????/**
?????*?阻塞式獲取
?????*/
????public?void?tryLock()?throws?Exception?{
????????this.interProcessMutex.acquire();
????}

????/**
?????*?超時未獲取到鎖則獲取鎖失敗
?????*?@param?time
?????*?@param?unit
?????*?@return?是否獲取到鎖
?????*?@throws?Exception
?????*/
????public?boolean?tryLock(long?time,?TimeUnit?unit)?throws?Exception?{
????????return?this.interProcessMutex.acquire(time,unit);
????}

????/**
?????*?釋放鎖
?????*?@throws?Exception
?????*/
????public?void?unLock()?throws?Exception?{
????????this.interProcessMutex.release();
????}
}

測試

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

????????ExecutorService?executorService?=?Executors.newFixedThreadPool(5);

????????final?String?lockPath?=?"/lock";

????????for?(int?i?=?0;?i?????????????final?int?clientIndex?=?i;
????????????Callable?callable?=?new?Callable()?{
????????????????public?Void?call()?throws?Exception?{
????????????????????CuratorFramework?simpleClient?=?MyZookeeperClient.createSimpleClient("192.168.0.104:2181");
????????????????????try?{
????????????????????????simpleClient.start();
????????????????????????DistributReetrantLock?distributReetrantLock?=?new?DistributReetrantLock(simpleClient,?lockPath);
????????????????????????//?阻塞式獲取
????????????????????????distributReetrantLock.tryLock();
????????????????????????System.out.println("Client:"?+?clientIndex?+?"?get?lock!");
????????????????????????//?驗證是否是可重入的
????????????????????????distributReetrantLock.tryLock();
????????????????????????System.out.println("Client:"?+?clientIndex?+?"?get?lock?again!");
????????????????????????Thread.sleep(1000);
????????????????????????//?持有鎖一秒后釋放,以便其他客戶端獲取到鎖
????????????????????????System.out.println("Client:"?+?clientIndex?+?"?release?lock!");
????????????????????????distributReetrantLock.unLock();
????????????????????}?finally?{
????????????????????????CloseableUtils.closeQuietly(simpleClient);
????????????????????}return?null;
????????????????}
????????????};
????????????executorService.submit(callable);
????????}
????????executorService.awaitTermination(10,?TimeUnit.MINUTES);
????}

輸出結果

Client:4?get?lock!
Client:4?get?lock?again!
Client:4?release?lock!
Client:3?get?lock!
Client:3?get?lock?again!
Client:3?release?lock!
Client:0?get?lock!
Client:0?get?lock?again!
Client:0?release?lock!
Client:1?get?lock!
Client:1?get?lock?again!
Client:1?release?lock!
Client:2?get?lock!
Client:2?get?lock?again!
Client:2?release?lock!

3.1.2 分布式排它鎖
/**
?*?分布式排它鎖
?*?@author?miaomiao
?*?@date?2020/10/25?12:54
?*/
public?class?DistributeLock?{
????private?final?String?lockPath;
????private?InterProcessSemaphoreMutex?interProcessSemaphoreMutex;
????public?DistributeLock(CuratorFramework?client,String?lockPath){
????????this.lockPath?=?lockPath;
????????this.interProcessSemaphoreMutex?=?new?InterProcessSemaphoreMutex(client,lockPath);
????}
????/**
?????*?阻塞式獲取
?????*/
????public?void?tryLock()?throws?Exception?{
????????this.interProcessSemaphoreMutex.acquire();
????}

????/**
?????*?超時未獲取到鎖則獲取鎖失敗
?????*?@param?time
?????*?@param?unit
?????*?@return?是否獲取到鎖
?????*?@throws?Exception
?????*/
????public?boolean?tryLock(long?time,?TimeUnit?unit)?throws?Exception?{
????????return?this.interProcessSemaphoreMutex.acquire(time,unit);
????}

????/**
?????*?釋放鎖
?????*?@throws?Exception
?????*/
????public?void?unLock()?throws?Exception?{
????????this.interProcessSemaphoreMutex.release();
????}
}

3.1.3 分布式可重入讀寫鎖

獲取到寫鎖的進程可以繼續獲取讀鎖,當釋放掉寫鎖后,降級為讀鎖。

/**
?*?分布式可重入讀寫鎖
?*?@author?miaomiao
?*?@date?2020/10/25?13:07
?*/
public?class?DistributeReetrantReadWriteLock?{
????private?InterProcessReadWriteLock?interProcessReadWriteLock;
????private?String?lockPath;
????public?DistributeReetrantReadWriteLock(CuratorFramework?client,String?lockPath){
????????this.lockPath?=?lockPath;
????????this.interProcessReadWriteLock?=?new?InterProcessReadWriteLock(client,lockPath);
????}

????/**
?????*?阻塞式獲取讀鎖
?????*?@throws?Exception
?????*/
????public?void?tryReadLock()?throws?Exception?{
???????interProcessReadWriteLock.readLock().acquire();
????}

????/**
?????*?獲阻塞式獲取寫鎖
?????*?@throws?Exception
?????*/
????public?void?tryWriteLock()?throws?Exception?{
????????interProcessReadWriteLock.writeLock().acquire();
????}

????/**
?????*?釋放寫鎖
?????*?@throws?Exception
?????*/
????public?void?unlockWriteLock()?throws?Exception?{
????????interProcessReadWriteLock.writeLock().release();
????}

????/**
?????*?釋放讀鎖
?????*?@throws?Exception
?????*/
????public?void?unlockReadLock()?throws?Exception?{
????????interProcessReadWriteLock.readLock().release();
????}
}

3.2 分布式鎖原理

3.1 排它鎖原理

利用 zookeeper 的同級節點的唯一性特性,在需要獲取排他鎖時,所有的客戶端試圖通過調用 create() 接口,在 /指定 節點下創建相同臨時子節點 /exclusive_lock/lock,最終只有一個客戶端能創建成功,那么此客戶端就獲得了分布式鎖。同時,所有沒有獲取到鎖的客戶端可以在 /exclusive_lock 節點上注冊一個子節點變更的 watcher 監聽事件,以便重新爭取獲得鎖。

3.2 讀寫鎖原理

共享鎖需要實現共享讀,排他寫。實現原理:當多個客戶端請求共享鎖時,為指定節點創建臨時順序子節點,且子節點的path能夠區分是哪個客戶端以及當前該客戶端的操作(寫還是讀)就像這樣 [hostname]-請求類型W/R-序號。之后在判斷當前客戶端是否獲得鎖時,如果當前客戶端的操作為讀請求,則判斷如果存在小于自己節點序號的寫請求節點或者自己本身就是最小序列的節點,則獲取到鎖;如果當前客戶端的操作為寫請求時,則只有自己節點序號是最小的節點時,才可以獲取到鎖。如果沒有獲取到鎖,讀請求在比自己序號小的最后一個寫請求節點添加監聽器;寫請求在子節點列表比自己小的最后一個節點注冊watcher監聽。

四、通過Zookeeper實現Leader選舉

在分布式系統中,leader選舉是指指定一個進程(一個實例、一臺機器)作為分配給多臺服務器任務的組織者的過程。在任務開始之前,所有服務器節點都不知道哪個節點將作為任務的領導者或者說協調者,然后在leader選舉之后,每個節點都會識別出一個特定的、唯一的節點作為任務leader。

Apache Curator針對Leader 選舉提供了兩種方式:

4.1 利用順序臨時節點實現

最簡單的方式就是,當有一個"/election"節點,客戶端們為此節點創建一個順序、臨時節點,每個客戶端創建的子節點都會自動帶上一個序號后綴,并且最早創建的序號最小,只需要選舉序號最小的子節點對應的客戶端作為leader即可。

當然這些肯定是遠遠不夠的,還要有假如leader宕機出現故障,必須要重新推舉新的leader機制。一種解決辦法就是所有的應用客戶端都監聽序號最小的子節點來判斷自己是否可以成為leader,因為假如leader客戶端宕機,那么最小序號節點也會消失,所以會產生新的最小序號節點,也就是產生新的leader。但是這樣做會產生羊群效應(herd effect):所有的客戶端都接收到了最小序號子節點被刪除的通知,接下來所有客戶端都調用getChilrden()獲取"/election"的子節點列表,如果客戶端數量很大,將會給zookeeper服務器帶來一定的壓力。為了避免羊群效應,每個客戶端只需要監聽自己對應子節點的前一個節點就足夠了,這樣當leader客戶端宕機,最小子序列節點被刪除,那么最小序列子節點的下一個節點對應的客戶端就成為新的leader。

對應在Apache Curator中的相關實現類為

  • org.apache.curator.framework.recipes.leader.LeaderLatch

核心類,主入口

  • org.apache.curator.framework.recipes.leader.LeaderLatchListener leader latch監聽器,當leader狀態發生改變時回調,該接口有兩個方法
??//當稱為leader時調用
??public?void?isLeader();
??//當失去leader時調用
??public?void?notLeader();

示例

????????????????????????CuratorFramework?simpleClient?=?MyZookeeperClient.createSimpleClient("192.168.0.104:2181");

????????????????????????simpleClient.start();

????????????????????????MyLeaderLatch?leaderLatch?=?new?MyLeaderLatch(simpleClient,"/leader_election"?,new?LeaderLatchListener(){
????????????????????????????public?void?isLeader()?{
????????????????????????????????System.out.println("Client:"+clientIndex+"?is?leader");
????????????????????????????}

????????????????????????????public?void?notLeader()?{
????????????????????????????????System.out.println("Client:"+clientIndex+"?lose?leader");

????????????????????????????}
????????????????????????});
????????????????????????leaderLatch.start();

4.2 利用分布式鎖實現

相關類:

  • org.apache.curator.framework.recipes.leader.LeaderSelector

核心類,選舉主入口,構造LeaderSelector 必須傳入LeaderSelectorListener

  • org.apache.curator.framework.recipes.leader.LeaderSelectorListener

leader selector監聽器,當被選為leader時回調。當某節點被選舉為leader時,調用takeLeadership,當takeLeadership方法執行完畢后,則此節點就會放棄leader,從而致使重新選舉,即leader得生命周期等于takeLeadership方法得周期。

  • org.apache.curator.framework.recipes.leader.LeaderSelectorListenerAdapter

LeaderSelectorListenerAdapter是對LeaderSelectorListener的一個抽象實現,覆寫了stateChanged方法,并當選舉失敗時拋出CancelLeadershipException,官方推薦使用該監聽器

  • org.apache.curator.framework.recipes.leader.CancelLeadershipException示例:
?????????????CuratorFramework?simpleClient?=?MyZookeeperClient.createSimpleClient("192.168.0.104:2181");

????????????????simpleClient.start();

????????????????MyLeaderSelector?leaderSelector?=?new?MyLeaderSelector(simpleClient,?"/leader_selector",?new?LeaderSelectorListenerAdapter()?{

????????????????????public?void?takeLeadership(CuratorFramework?client)?throws?Exception?{
????????????????????????System.out.println("Client:"?+?clientIndex?+?"?get?leader!");
????????????????????}
????????????????});
????????????????//開始選舉
????????????????leaderSelector.start();

??參考文章

https://github.com/Snailclimb/JavaGuide/blob/master/docs/system-design/framework/zookeeper/

https://zookeeper.apache.org/doc/r3.6.2/zookeeperProgrammers.html

https://www.cnblogs.com/qlqwjy/p/10517231.html

ZooKeeper 的應用場景

分布式服務框架 Zookeeper —— 管理分布式環境中的數據

https://www.runoob.com/w3cnote_genre/zookeeper/page/2

http://curator.apache.org/

??理論篇

一、基礎概念

ZooKeeper是開源分布式協調服務,提供高可用、高性能、穩定的分布式數據一致性解決方案,通常被用于實現諸如數據發布/訂閱、負載均衡、命名服務、分布式協調/通知、集群管理、Master選舉、分布式鎖和分布式隊列等功能。

二、ZooKeeper數據模型

image.png

2.1 znode(數據節點)

Zookeeper中所有存儲的數據由znode組成,節點也成為znode,并以key value鍵值對形式存儲數據。整體結構類似linux文件系統,根路徑以/開頭。

znode中數據的讀寫都是原子的,而且每一個znode都有一個Access Control List(ACL)用來限制誰可以做什么。每一個znode的數據大小不能超過1M

2.1.1 znode數據節點名稱規范
  • null 字符(即\u0000)不能組成znode節點path的命名
  • \ud800 - uF8FF, \uFFF0 - uFFFF, \u0001 - \u001F 以及 \u007F、\u009F 這些玩意無法很好地進行展示,看起來像亂碼
  • "."可以構成命名的一部分,但是不能單獨作為path的命名
  • "zookeeper"是保留字
2.1.2 znode數據節點組成:
  • stat 狀態屬性組成:
屬性名稱屬性描述
czxid創建節點的事務ID
mzxid節點最后一次修改的事務ID
pzxid子節點列表最后的一次修改(子節點列表的增加或刪除)的事務ID
ctime創建節點的時間,單位:毫秒
mtime節點最后一次修改的時間,單位:毫秒
version節點數據變更的次數
cversion子節點變更的次數
aversion節點ACL變更的次數
ephemeralOwner如果節點是臨時節點, 則此值為創建該節點的session的id,否則為0
dataLength節點數據長度
numChildren子節點個數
  • data
  • children
2.1.3 znode數據節點類型:
  • 持久節點(Persistent Nodes)

  • 臨時節點(Ephemeral Nodes) 臨時節點的生命周期即為創建這些節點的會話生命周期,即會話結束,則這些節點就會被刪除。所以臨時節點不允許創建子節點。

  • 順序節點(Sequence Nodes ) 順序節點可以是持久的,也可以是臨時的。在創建節點時,可為節點路徑添加一個單調遞增計數器,Zookeeper將通過將10位的序列號附加到原始節點名稱后來設置節點路徑。

  • 容器節點(Container Nodes) 此類型節點是3.6.0版本之后添加,容器節點是一種有特殊用途的節點,可用于leader選舉和分布式鎖等,當容器中最后一個子節點被刪除,此容器節點將會在未來某個時刻被刪除。

  • 超時過期節點(TTL Nodes) 此類型節點是3.6.0版本之后添加,當創建一個持久節點或者順序持久節點時,可以為其設置一個毫秒級的超時過期時間,如果在設置時間內,此節點沒又被修改過而且也沒有子節點,則此節點將作為候選項,在未來某個時刻被刪除。當然TTL Nodes默認是禁用狀態的。

三、Zookeeper Time

Zookeeper中時間有很多表示時間的方式。

  • Zxid 事務ID。Zookeeper狀態的每次變化都會收到這樣一個事務ID

  • Version numbers

  • Ticks

  • Real time

四、ZooKeeper Sessions (會話)

Zookeeper客戶端通過

五、ZooKeeper Watches (監聽)

5.1 watch基本概念

Zookeeper所有讀相關操作:getData()、getChildren()、 exists()等都有一個參數boolean watch用來設置watche。按照讀的內容不同,有兩種watch:Data WatchChild Watch,像getData()和exists()這種屬于讀取znode數據,所以屬于Data Watch,所以當znode數據發生變更,將觸發znode的Data Watch;getChildren()對應的就是Child Watch。創建子節點將觸發父節點的Child Watch,而節點的刪除將同時觸發Data Watch和Child Watch。

Watch是一個一次性觸發器,比如當調用 getData("/znode1", true) 后--true代表設置監聽,該節點被刪除或者數據發生變更,將會觸發客戶端注冊的watch,觸發之后,將被刪除,也就是往后數據再變化就不會再觸發此watch了。

5.2 watch 事件類型

那么當觸發watch的時候有因為數據發生變化的,有因為節點創建或刪除的等等,客戶端如何判斷服務端觸發的watch是各種類型呢?zookeeper提供了EventType的枚舉,服務端觸發watch時,會告訴客戶端是何種類型。

一共有如下這么多事件類型:

  • None
  • NodeCreated
  • NodeDeleted
  • NodeDataChanged
  • NodeChildrenChanged
  • DataWatchRemoved
  • ChildWatchRemoved
  • PersistentWatchRemoved

其中最后三個事件類型:DataWatchRemoved、ChildWatchRemoved、PersistentWatchRemoved分別是刪除不同類型的watch的時候事件類型,從單詞字面意思也應該能夠理解。

5.3 永久遞歸watch

3.6.0之后(包括3.6.0) 客戶端可以通過addWatch()為znode設置永久遞歸的watch,這意味著watch不再是一次性的了,可以多次觸發不會被刪除,并且還會遞歸觸發。當然也有移除永久watch的機制:removeWatches()

watch是維護在zookeeper服務端的,所有當客戶端與服務端斷鏈,將不會接受到watch的觸發,而當重連后都將恢復可以重新觸發。

5.3 關于watch的一些注意事項?

1.標準watch是一次性的,如果當客戶端接收到watch的回調通知,那么此watch將被刪除,如果客戶端還想接收到通知,則需要注冊另一個watch

2.正如第一條所講,在客戶端接收到watch回調通知時,可能會繼續設置一個watch以監聽znode的下次變更,但是假如在接收到watch和發送請求設置新watch的中間,znode發生了多次變化,這個可能客戶端會接收不到此變更通知。

3.如果為比如exist、getData注冊了同一個watch,那么當watch被刪除的時候,僅會觸發一次delete watch事件

六、ZooKeeper access control using ACLs(權限控制器)

ACL全稱Access Control List,即訪問控制列表。Zookeeper的ACL實現很類似與UNIX的文件系統權限控制。每一個ACL針對指定的znode,但是并不針對指定znode的子節點,也就是ACL并不遞歸生效。假如給/app設置了一個ACL,那么/app/childtest將不受此ACL控制。

權限的表達式為scheme:id, permissions

6.1 scheme-->授權策略

授權策略一共有4種

授權策略含義
world默認策略。任何人都可以訪問
auth即已經認證通過的用戶
digest通過使用MD5進行哈希 username:password格式生成的字符串來進行身份驗證,當進行身份驗證時,是使用usename:password明文形式字符串,當用做ACL驗證時,會先經過base64編碼,然后使用SHA1加密
ip使用客戶端IP作為ACL身份標識。其格式為addr/bits,bits代表客戶端的IP地址要至少匹配ACL中IP地址的多少位
x509

6.2 id-->授權對象

6.3 permissions-->權限點

權限點含義
CREATE可以創建子節點
READ可以獲取znode數據,以及znode的子節點列表
WRITE可以為znode設置數據
DELETE可以刪除znode的子節點
ADMIN可以為znode設置ACL,ADMIN就像是znode的owner

六、ZooKeeper ?Consistency Guarantees(一致性保障)

Zookeeper是高性能、可擴展的服務,它的讀操作和寫操作都非常的快

6.1 Sequential Consistency(順序一致性)

來自客戶端的更新將會按照順序進行處理

6.2 Atomicity (原子性)

6.3 Single System Image(單一系統鏡像)

無論客戶端連接到哪一個服務器上,其看到的服務端數據模型都是一致的

6.4Reliability(可靠性)

一旦更新請求被處理,更改的結果將會持久化

6.5 Timeliness (及時性)


??實戰篇

一、下載安裝

1.1 下載

下載地址:https://zookeeper.apache.org/releases.html#download [apache-zookeeper-3.6.2-bin.tar.gz](https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.6.2/apache-zookeeper-3.6.2-bin.tar.gz)

1.2 單機模式

1.2.1 設置配置文件

在conf目錄下會有一個zoo_sample.cfg文件,這里提供了樣例配置信息,我們只需要將此文件改名為zoo.cfg,這樣才會被zookeeper識別。該配置文件中的配置項說明:

  • tickTime 單位:毫秒。是服務器之間或客戶端與服務器之間維持心跳的時間間隔;且最小會話超時時間將是tickTime的兩倍

  • dataDir zookeeper保存的數據的目錄地址,默認情況下,事務log也會記在這里(除非另外指定)

  • clientPort 客戶端連接服務端的端口 zoo.cfg示例

tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
1.2.2 啟動zookeeper服務端(前提是需要保證安裝機器上有JDK)
./zkServer.sh?start
1.2.3 客戶端連接服務器
./zkCli.sh?-server?127.0.0.1:2181

1.3 集群模式

zookeeper集群部署可以獲得高可靠性,要想實現高可靠容錯好集群,至少需要3臺服務器,且集群數量最好為奇數。

1.3.1 設置集群配置文件zoo.conf
tickTime=2000
dataDir=/var/lib/zookeeper/
clientPort=2181
initLimit=5
syncLimit=2
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888

除了單機模式中需要配置的那幾個參數外,需要配置和集群相關的參數

  • initLimit 表示集群中的followers服務器 在連接leader服務器時,經過最大initLimit個tickTime后,若leader還未接收到followers的信息,則認為連接失敗
  • syncLimit 表示集群中follower服務器與leader服務器在同步消息時最大syncLimit*tickTime時間間隔未收到響應,則此follower會被拋棄
  • server.id=host:port:port 配置文件中每行的server.id=host:port:port共同組成一個集群。這里有兩個端口,前面的端口用于與集群leader連接的端口,后面的端口用于leader選舉。如果想在同一臺機器上搭建偽集群,則第一個端口不同即可

1.3.2 設置myid文件

myid文件中只有一行內容,且這行內容就是上述配置server.id=host:port:port 中的id,在集群模式下該id不可重復,范圍為1-255,將此文件放在dataDir參數表示的目錄下

1.3.3 查看服務器狀態

./zkServer.sh?status
followerleader

1.3.4 搭建集群過程遇到的問題

在搭建集群的時候,啟動三臺機器都顯示啟動成功,但是使用客戶端命令也連接失敗,通過./zkServer.sh status 顯示Error contacting service. It is probably not running.查看logs下的日志,發現有這么一行:Exception when following the leader java.io.EOFException。查資料發現是我將客戶端端口和follower服務器與leader服務器通信的端口混到一起了,如下圖配置的相同,所以出現了這種錯誤,所以這兩個端口不可以相同

錯誤配置

二、zk客戶端 操作 Zookeeper及基礎命令

2.1 bin/zkServer.sh

./zkServer.sh [--config]startstart-foreground|stop|version|restart|status|print-cmd

用于操作zk服務器相關,不同的參數代表不同的操作

#啟動zk服務器
bin/zkServer.sh?start

#重啟zk服務器
bin/zkServer.sh?restart

#停止zk服務器
bin/zkServer.sh?stop

#查看zk運行狀態
bin/zkServer.sh?status

#查看zk版本信息
bin/zkServer.sh?version

2.2 bin/zkCli.sh

  • 啟動客戶端連接zk服務器
bin/zkCli.sh?-server?{host}:{port}

2.3 客戶端命令

  • ls列出指定路徑下所有子節點 ls [-s] [-w] [-R] path
#列出根路徑下所有節點
ls?/
#列出指定路徑節點下的子節點同時,輸出指定路徑節點狀態細膩些
ls?-s?/
  • get查看指定路徑節點信息 get [-s] [-w] path
#查看/node1節點信息
get?/node1
#?查看/node1節點信息及狀態信息
get?-s?/node1
  • create創建節點 create [-s] [-e] [-c] [-t ttl] path [data] [acl] 可選參數 -s 代表創建順序節點 可選參數 -e 代表創建臨時節點 可選參數 -c 代表創建容器節點 可選參數 -t 設置節點過期時間
#?創建路徑為/node1,數據為data的持久節點
create?/node1?data
  • set修改節點 set [-s] [-v version] path data 可選參數-s代表更新節點后,輸出節點狀態信息 可選參數-v用來表示根據版本號進行更新,低版本肯定是無法更新高版本節點的(樂觀鎖)
#創建/node2節點
[zk:?localhost:2181(CONNECTED)?27]?create?/node2?data
Created?/node2
#查看/node2節點狀態信息
[zk:?localhost:2181(CONNECTED)?28]?get?-s?/node2
data
#...省略其他信息
dataVersion?=?0
#...省略其他信息
#更新節點,此時版本號為1
[zk:?localhost:2181(CONNECTED)?29]?set?-s?/node2?data2
#...省略其他信息
dataVersion?=?1
#...省略其他信息
[zk:?localhost:2181(CONNECTED)?30]?set?-v?1?/node2?data3
#更新失敗
[zk:?localhost:2181(CONNECTED)?31]?set?-v?1?/node2?data3
version?No?is?not?valid?:?/node2
[zk:?localhost:2181(CONNECTED)?32]?
  • deletedelete [-v version] path 刪除節點 因為刪除本身也是更新的意思,-v參數同上set的-v參數
#刪除/node2節點
delete?/node2

三、Java 操作 Zookeeper

通過Java操作Zookeeper有兩種方式,一種就是通過Zookeeper提供的原生API(鏈接)進行操作,一種就是通過Apache Curator(官網) ---進行操作。

3.1 Apache Curator是什么

Apache Curator是比較完善的Zookeeper客戶端框架,針對Zookeeper原生API的封裝和擴展,降低了使用 Zookeeper的復雜性,使得使用Zookeeper更加可靠、更加簡單。Curator有很多不同的artifacts,可以根據我們的需要進行引入使用:

  • curator-recipes 該artifact包含了對Zookeeper的所有操作,大部分場景只需要使用該artifact即可滿足需求。

  • curator-framework 針對zookeeper的高級功能的簡化封裝,該artifact構建在整個客戶端之上,所有應該自動包含此模塊

  • curator-client 對于Zookeeper客戶端鏈接相關操作的封裝

3.2 使用apache-curator操作zookeeper

3.2.1 引入pom
org.apache.curatorcurator-recipes5.1.0

5.1.0版本對應的zookeeper客戶端版本為3.6.0

3.2.2 創建連接

創建鏈接需要zk host地址,需要重試策略,還可以設置一些諸如超時時間等等參數。創建客戶端連接的入口類是CuratorFrameworkFactory,該類中有一個內部靜態類Builder,用于設置連接的一些額外高級參數。重試策略則是RetryPolicy。

????public?static?CuratorFramework?createWithOptions(String?connectionString,?RetryPolicy?retryPolicy,?int?connectionTimeoutMs,?int?sessionTimeoutMs){
????????return?CuratorFrameworkFactory.builder()
????????????????.connectString(connectionString)
????????????????.retryPolicy(retryPolicy)
????????????????.connectionTimeoutMs(connectionTimeoutMs)
????????????????.sessionTimeoutMs(sessionTimeoutMs)
????????????????.build();
????}

3.2.3 創建節點,更新節點內容

????/**
?????*?創建持久性節點
?????*?@param?client?CuratorFramework
?????*?@param?path?節點路徑
?????*?@param?payload?節點內容
?????*?@throws?Exception
?????*/
????public?static?void?create(CuratorFramework?client,?String?path,?byte[]?payload)?throws?Exception?{
????????client.create().forPath(path,?payload);
????}

更多參考官方示例:https://github.com/apache/curator/tree/master/curator-examples/src/main/java/framework

??應用篇

一、應用場景

  • 命名服務:按名稱標識集群中的節點
  • 統一配置管理
  • 數據發布/訂閱
  • 分布式鎖
  • Leader 選舉

二、通過Zookeeper實現統一配置管理

三、通過Zookeeper實現分布式鎖

Apache Curator針對分布式鎖提供了多種實現

  • InterProcessMutex:分布式可重入排它鎖
  • InterProcessSemaphoreMutex:分布式排它鎖
  • InterProcessReadWriteLock:分布式可重入讀寫鎖
  • InterProcessMultiLock:將多個鎖作為單個實體管理的容器

3.1 代碼實戰

3.1.1 分布式可重入排它鎖
/**
?*?@author?miaomiao
?*?@date?2020/10/25?11:15
?*/
public?class?DistributReetrantLock?{

????private?final?InterProcessMutex?interProcessMutex;
????private?final?String?lockPath;

????public?DistributReetrantLock(CuratorFramework?client,?String?lockPath)?{
????????this.lockPath?=?lockPath;
????????//?此InterProcessMutex構造方法的maxLeases為1,表示為排他鎖
????????this.interProcessMutex?=?new?InterProcessMutex(client,?lockPath);
????}

????/**
?????*?阻塞式獲取
?????*/
????public?void?tryLock()?throws?Exception?{
????????this.interProcessMutex.acquire();
????}

????/**
?????*?超時未獲取到鎖則獲取鎖失敗
?????*?@param?time
?????*?@param?unit
?????*?@return?是否獲取到鎖
?????*?@throws?Exception
?????*/
????public?boolean?tryLock(long?time,?TimeUnit?unit)?throws?Exception?{
????????return?this.interProcessMutex.acquire(time,unit);
????}

????/**
?????*?釋放鎖
?????*?@throws?Exception
?????*/
????public?void?unLock()?throws?Exception?{
????????this.interProcessMutex.release();
????}
}

測試

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

????????ExecutorService?executorService?=?Executors.newFixedThreadPool(5);

????????final?String?lockPath?=?"/lock";

????????for?(int?i?=?0;?i?????????????final?int?clientIndex?=?i;
????????????Callable?callable?=?new?Callable()?{
????????????????public?Void?call()?throws?Exception?{
????????????????????CuratorFramework?simpleClient?=?MyZookeeperClient.createSimpleClient("192.168.0.104:2181");
????????????????????try?{
????????????????????????simpleClient.start();
????????????????????????DistributReetrantLock?distributReetrantLock?=?new?DistributReetrantLock(simpleClient,?lockPath);
????????????????????????//?阻塞式獲取
????????????????????????distributReetrantLock.tryLock();
????????????????????????System.out.println("Client:"?+?clientIndex?+?"?get?lock!");
????????????????????????//?驗證是否是可重入的
????????????????????????distributReetrantLock.tryLock();
????????????????????????System.out.println("Client:"?+?clientIndex?+?"?get?lock?again!");
????????????????????????Thread.sleep(1000);
????????????????????????//?持有鎖一秒后釋放,以便其他客戶端獲取到鎖
????????????????????????System.out.println("Client:"?+?clientIndex?+?"?release?lock!");
????????????????????????distributReetrantLock.unLock();
????????????????????}?finally?{
????????????????????????CloseableUtils.closeQuietly(simpleClient);
????????????????????}return?null;
????????????????}
????????????};
????????????executorService.submit(callable);
????????}
????????executorService.awaitTermination(10,?TimeUnit.MINUTES);
????}

輸出結果

Client:4?get?lock!
Client:4?get?lock?again!
Client:4?release?lock!
Client:3?get?lock!
Client:3?get?lock?again!
Client:3?release?lock!
Client:0?get?lock!
Client:0?get?lock?again!
Client:0?release?lock!
Client:1?get?lock!
Client:1?get?lock?again!
Client:1?release?lock!
Client:2?get?lock!
Client:2?get?lock?again!
Client:2?release?lock!

3.1.2 分布式排它鎖
/**
?*?分布式排它鎖
?*?@author?miaomiao
?*?@date?2020/10/25?12:54
?*/
public?class?DistributeLock?{
????private?final?String?lockPath;
????private?InterProcessSemaphoreMutex?interProcessSemaphoreMutex;
????public?DistributeLock(CuratorFramework?client,String?lockPath){
????????this.lockPath?=?lockPath;
????????this.interProcessSemaphoreMutex?=?new?InterProcessSemaphoreMutex(client,lockPath);
????}
????/**
?????*?阻塞式獲取
?????*/
????public?void?tryLock()?throws?Exception?{
????????this.interProcessSemaphoreMutex.acquire();
????}

????/**
?????*?超時未獲取到鎖則獲取鎖失敗
?????*?@param?time
?????*?@param?unit
?????*?@return?是否獲取到鎖
?????*?@throws?Exception
?????*/
????public?boolean?tryLock(long?time,?TimeUnit?unit)?throws?Exception?{
????????return?this.interProcessSemaphoreMutex.acquire(time,unit);
????}

????/**
?????*?釋放鎖
?????*?@throws?Exception
?????*/
????public?void?unLock()?throws?Exception?{
????????this.interProcessSemaphoreMutex.release();
????}
}

3.1.3 分布式可重入讀寫鎖

獲取到寫鎖的進程可以繼續獲取讀鎖,當釋放掉寫鎖后,降級為讀鎖。

/**
?*?分布式可重入讀寫鎖
?*?@author?miaomiao
?*?@date?2020/10/25?13:07
?*/
public?class?DistributeReetrantReadWriteLock?{
????private?InterProcessReadWriteLock?interProcessReadWriteLock;
????private?String?lockPath;
????public?DistributeReetrantReadWriteLock(CuratorFramework?client,String?lockPath){
????????this.lockPath?=?lockPath;
????????this.interProcessReadWriteLock?=?new?InterProcessReadWriteLock(client,lockPath);
????}

????/**
?????*?阻塞式獲取讀鎖
?????*?@throws?Exception
?????*/
????public?void?tryReadLock()?throws?Exception?{
???????interProcessReadWriteLock.readLock().acquire();
????}

????/**
?????*?獲阻塞式獲取寫鎖
?????*?@throws?Exception
?????*/
????public?void?tryWriteLock()?throws?Exception?{
????????interProcessReadWriteLock.writeLock().acquire();
????}

????/**
?????*?釋放寫鎖
?????*?@throws?Exception
?????*/
????public?void?unlockWriteLock()?throws?Exception?{
????????interProcessReadWriteLock.writeLock().release();
????}

????/**
?????*?釋放讀鎖
?????*?@throws?Exception
?????*/
????public?void?unlockReadLock()?throws?Exception?{
????????interProcessReadWriteLock.readLock().release();
????}
}

3.2 分布式鎖原理

3.1 排它鎖原理

利用 zookeeper 的同級節點的唯一性特性,在需要獲取排他鎖時,所有的客戶端試圖通過調用 create() 接口,在 /指定 節點下創建相同臨時子節點 /exclusive_lock/lock,最終只有一個客戶端能創建成功,那么此客戶端就獲得了分布式鎖。同時,所有沒有獲取到鎖的客戶端可以在 /exclusive_lock 節點上注冊一個子節點變更的 watcher 監聽事件,以便重新爭取獲得鎖。

3.2 讀寫鎖原理

共享鎖需要實現共享讀,排他寫。實現原理:當多個客戶端請求共享鎖時,為指定節點創建臨時順序子節點,且子節點的path能夠區分是哪個客戶端以及當前該客戶端的操作(寫還是讀)就像這樣 [hostname]-請求類型W/R-序號。之后在判斷當前客戶端是否獲得鎖時,如果當前客戶端的操作為讀請求,則判斷如果存在小于自己節點序號的寫請求節點或者自己本身就是最小序列的節點,則獲取到鎖;如果當前客戶端的操作為寫請求時,則只有自己節點序號是最小的節點時,才可以獲取到鎖。如果沒有獲取到鎖,讀請求在比自己序號小的最后一個寫請求節點添加監聽器;寫請求在子節點列表比自己小的最后一個節點注冊watcher監聽。

四、通過Zookeeper實現Leader選舉

在分布式系統中,leader選舉是指指定一個進程(一個實例、一臺機器)作為分配給多臺服務器任務的組織者的過程。在任務開始之前,所有服務器節點都不知道哪個節點將作為任務的領導者或者說協調者,然后在leader選舉之后,每個節點都會識別出一個特定的、唯一的節點作為任務leader。

Apache Curator針對Leader 選舉提供了兩種方式:

4.1 利用順序臨時節點實現

最簡單的方式就是,當有一個"/election"節點,客戶端們為此節點創建一個順序、臨時節點,每個客戶端創建的子節點都會自動帶上一個序號后綴,并且最早創建的序號最小,只需要選舉序號最小的子節點對應的客戶端作為leader即可。

當然這些肯定是遠遠不夠的,還要有假如leader宕機出現故障,必須要重新推舉新的leader機制。一種解決辦法就是所有的應用客戶端都監聽序號最小的子節點來判斷自己是否可以成為leader,因為假如leader客戶端宕機,那么最小序號節點也會消失,所以會產生新的最小序號節點,也就是產生新的leader。但是這樣做會產生羊群效應(herd effect):所有的客戶端都接收到了最小序號子節點被刪除的通知,接下來所有客戶端都調用getChilrden()獲取"/election"的子節點列表,如果客戶端數量很大,將會給zookeeper服務器帶來一定的壓力。為了避免羊群效應,每個客戶端只需要監聽自己對應子節點的前一個節點就足夠了,這樣當leader客戶端宕機,最小子序列節點被刪除,那么最小序列子節點的下一個節點對應的客戶端就成為新的leader。

對應在Apache Curator中的相關實現類為

  • org.apache.curator.framework.recipes.leader.LeaderLatch

核心類,主入口

  • org.apache.curator.framework.recipes.leader.LeaderLatchListener leader latch監聽器,當leader狀態發生改變時回調,該接口有兩個方法
??//當稱為leader時調用
??public?void?isLeader();
??//當失去leader時調用
??public?void?notLeader();

示例

????????????????????????CuratorFramework?simpleClient?=?MyZookeeperClient.createSimpleClient("192.168.0.104:2181");

????????????????????????simpleClient.start();

????????????????????????MyLeaderLatch?leaderLatch?=?new?MyLeaderLatch(simpleClient,"/leader_election"?,new?LeaderLatchListener(){
????????????????????????????public?void?isLeader()?{
????????????????????????????????System.out.println("Client:"+clientIndex+"?is?leader");
????????????????????????????}

????????????????????????????public?void?notLeader()?{
????????????????????????????????System.out.println("Client:"+clientIndex+"?lose?leader");

????????????????????????????}
????????????????????????});
????????????????????????leaderLatch.start();

4.2 利用分布式鎖實現

相關類:

  • org.apache.curator.framework.recipes.leader.LeaderSelector

核心類,選舉主入口,構造LeaderSelector 必須傳入LeaderSelectorListener

  • org.apache.curator.framework.recipes.leader.LeaderSelectorListener

leader selector監聽器,當被選為leader時回調。當某節點被選舉為leader時,調用takeLeadership,當takeLeadership方法執行完畢后,則此節點就會放棄leader,從而致使重新選舉,即leader得生命周期等于takeLeadership方法得周期。

  • org.apache.curator.framework.recipes.leader.LeaderSelectorListenerAdapter

LeaderSelectorListenerAdapter是對LeaderSelectorListener的一個抽象實現,覆寫了stateChanged方法,并當選舉失敗時拋出CancelLeadershipException,官方推薦使用該監聽器

  • org.apache.curator.framework.recipes.leader.CancelLeadershipException示例:
?????????????CuratorFramework?simpleClient?=?MyZookeeperClient.createSimpleClient("192.168.0.104:2181");

????????????????simpleClient.start();

????????????????MyLeaderSelector?leaderSelector?=?new?MyLeaderSelector(simpleClient,?"/leader_selector",?new?LeaderSelectorListenerAdapter()?{

????????????????????public?void?takeLeadership(CuratorFramework?client)?throws?Exception?{
????????????????????????System.out.println("Client:"?+?clientIndex?+?"?get?leader!");
????????????????????}
????????????????});
????????????????//開始選舉
????????????????leaderSelector.start();

??參考文章

https://github.com/Snailclimb/JavaGuide/blob/master/docs/system-design/framework/zookeeper/

https://zookeeper.apache.org/doc/r3.6.2/zookeeperProgrammers.html

https://www.cnblogs.com/qlqwjy/p/10517231.html

ZooKeeper 的應用場景

分布式服務框架 Zookeeper —— 管理分布式環境中的數據

https://www.runoob.com/w3cnote_genre/zookeeper/page/2

http://curator.apache.org/

總結

以上是生活随笔為你收集整理的zookeeper中展示所有节点_分布式协调服务之Zookeeper的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

最近中文字幕高清字幕在线视频 | 亚洲精品456在线播放第一页 | 最近免费中文字幕 | 日日干日日 | 久久人人精 | 欧美三级在线播放 | 手机看片国产日韩 | 午夜丁香网 | 欧美久久久久久久久中文字幕 | 欧美日韩亚洲国产一区 | 韩日电影在线 | 日韩午夜电影院 | 国产视频一区在线 | www日| www色,com | www久久久久| 一级性av | 91精品在线麻豆 | 97人人看| 天天爱综合 | av片在线看 | 天天看天天干天天操 | 精品av网站 | 激情婷婷六月 | 精品在线观 | 国产视频 久久久 | 激情五月网站 | 婷婷色中文网 | 日本三级吹潮在线 | 天天拍天天爽 | 91免费视频国产 | 国产精品免费不卡 | 在线观看亚洲电影 | 国产久草在线观看 | 天天干 夜夜操 | 996久久国产精品线观看 | 国产区欧美 | av免费看av | 久久婷婷国产色一区二区三区 | 91av视频网| 日韩免费电影网 | 在线天堂亚洲 | 亚洲九九爱 | 国产97碰免费视频 | 在线观看视频在线观看 | 91看片看淫黄大片 | 日韩成人中文字幕 | 精品亚洲免费 | 色姑娘综合天天 | 深夜激情影院 | 欧美精品乱码99久久影院 | 亚洲va韩国va欧美va精四季 | 狠狠色噜噜狠狠狠狠2021天天 | 久久激情视频 久久 | 福利一区二区三区四区 | 亚洲区另类春色综合小说校园片 | 欧美成年人在线视频 | 成人黄色电影免费观看 | 三级在线视频观看 | a级免费观看 | 久久精品国产成人精品 | 久久久久国产一区二区三区四区 | 精品久久久久久久久亚洲 | 日韩欧美网址 | 人人爱夜夜操 | 久久久国产精品电影 | 人人干人人模 | 精品国产一二三四区 | 日韩av电影网站在线观看 | 亚洲国产片色 | 在线日韩精品视频 | 国产精品 国内视频 | 成人动漫一区二区三区 | 日韩免费观看一区二区三区 | 欧美日本三级 | 99久久国产免费,99久久国产免费大片 | 天天爽天天做 | 韩国一区二区三区视频 | 欧美日韩另类在线观看 | 日韩性xxxx | 中文字幕欧美三区 | 久久亚洲私人国产精品va | 九九九九免费视频 | av黄色亚洲| 99久久99视频只有精品 | 久久久免费国产 | 国产区免费 | 日本中文字幕一二区观 | 久久久久久久久久久影院 | 中文字幕在线观看国产 | 色资源网免费观看视频 | 亚洲黄色免费网站 | 五月婷色| 亚洲欧美日韩精品久久奇米一区 | 亚洲精品在线免费看 | 四虎影视成人精品国库在线观看 | 69国产成人综合久久精品欧美 | 不卡av电影在线观看 | 国产成人精品a | 久久免费视频这里只有精品 | 亚洲激情视频在线观看 | 亚洲电影成人 | 天天干天天插 | 99精品久久精品一区二区 | 精品视频国产一区 | 日本中文字幕在线看 | 日韩高清精品一区二区 | 手机av在线网站 | 国产在线自| 久久精品1区 | 日本性久久 | 日韩一三区 | 六月丁香综合网 | 久久久这里有精品 | 日日爽天天操 | 黄色av免费电影 | 亚洲精品国产精品久久99热 | 中文字幕观看av | 久久免费看a级毛毛片 | 久久人人射 | 国产高h视频 | 九九热只有这里有精品 | 久久99亚洲精品久久久久 | 国内精品久久久久影院优 | 婷婷资源站 | 国产亚洲精品久久久久久网站 | 色综合久久88色综合天天 | 三级黄色网址 | 国产一级片直播 | 国产经典三级 | 国产一级大片在线观看 | 久久天天躁狠狠躁亚洲综合公司 | 亚洲a成人v| 久热av| 国产精品一区二区av影院萌芽 | 91日韩免费 | 91九色视频导航 | 国内精品亚洲 | 日韩欧美在线视频一区二区 | av动态图片 | 在线 欧美 日韩 | 粉嫩av一区二区三区四区在线观看 | wwwww.国产 | 午夜色影院 | 网址你懂的在线观看 | www.91国产| 91九色蝌蚪视频 | 三级黄色片在线观看 | 一二三区视频在线 | 丁香六月激情 | 国产精品久久久久久麻豆一区 | 成年人视频在线观看免费 | 2021国产精品| 狠狠色丁香久久综合网 | 久草网视频在线观看 | 成人黄色在线视频 | 久久国产日韩 | 美女精品网站 | 国产福利精品一区二区 | 久久婷婷开心 | 91免费看片黄 | 精品国产伦一区二区三区观看说明 | 成人在线网站观看 | 欧美怡红院视频 | 日韩四虎| 91传媒免费在线观看 | 奇米777777| 天天干夜夜爽 | 91av99| 久久69精品| 天天操天天操天天操天天操天天操天天操 | 亚洲日本在线一区 | 色资源网免费观看视频 | 91视频链接 | 日韩在线观看一区 | 青青五月天| 99热这里只有精品久久 | 六月丁香激情网 | 成人黄色在线视频 | 国产a精品| 免费91在线| 免费av网站在线 | 亚洲aⅴ在线观看 | 国产精品欧美激情在线观看 | 97人人添人澡人人爽超碰动图 | 国产精品专区在线观看 | 伊人欧美| 在线免费看黄色 | 香蕉国产91 | 久久97超碰 | 国产成人av电影在线观看 | 国产玖玖视频 | 国产精品九九久久久久久久 | 成人毛片一区二区三区 | 久久精品一二三区 | 国产成人一区二区三区影院在线 | 国产精成人品免费观看 | 美女在线国产 | 国产网站色 | 国产91在线 | 美洲 | 97超碰色 | 精品国产日本 | 天天爽天天爽夜夜爽 | 黄色毛片一级片 | 国产视频欧美视频 | 欧美极品少妇xbxb性爽爽视频 | www色com | 又色又爽又黄 | 天堂在线成人 | 中文字幕在线成人 | 国产精品99久久久久久久久 | av电影免费在线看 | 国产在线不卡视频 | 亚洲精品国产精品国产 | 99精彩视频| 日韩免费观看视频 | 91九色自拍 | 亚洲成人999 | 视频在线观看一区 | 99av在线视频 | 一区二区三区在线影院 | 国产精品视频免费在线观看 | 91精品在线视频观看 | 亚洲天堂社区 | 日本成人免费在线观看 | 成人免费视频网站在线观看 | 久久久成人精品 | 天天射天天 | 日本韩国精品一区二区在线观看 | 天天操天天曰 | 最新一区二区三区 | 亚洲欧美日韩不卡 | 99热官网 | 天天操狠狠操 | 麻豆 videos| 成年人电影免费看 | 三级av网站| 日韩理论影院 | 日韩精品中文字幕在线不卡尤物 | 国产成人久久精品亚洲 | av一本久道久久波多野结衣 | 97视频在线免费播放 | freejavvideo日本免费 | 色六月婷婷| 999国产在线 | 亚洲视频电影在线 | 五月天精品视频 | a在线观看国产 | 91人人揉日日捏人人看 | 久久久国产高清 | 欧美 亚洲 另类 激情 另类 | 日韩丝袜在线观看 | 久久综合久久综合这里只有精品 | 99re6热在线精品视频 | 在线国产一区二区 | 99视频在线精品 | 特级大胆西西4444www | 久久精品福利视频 | 国产在线精品一区二区不卡了 | 国产日韩精品一区二区 | 国产精品中文字幕av | 国产裸体永久免费视频网站 | 福利片视频区 | 婷婷国产视频 | 久久久精品国产一区二区 | 日韩欧美在线不卡 | 欧美色婷婷 | 国产91精品在线观看 | 高清不卡一区二区在线 | 精品国产电影 | 亚洲精品午夜久久久久久久 | 国产精品高清在线 | a黄色片 | 69成人在线 | 亚洲成人高清在线 | 日韩 精品 一区 国产 麻豆 | 成人午夜电影在线观看 | 日本中文一级片 | 特级aaa毛片 | 国产91探花 | 毛片一区二区 | 中文字幕久久精品亚洲乱码 | 人人爱人人舔 | 国产成人三级三级三级97 | 久久久久国产a免费观看rela | 日本精品在线看 | 久久69精品久久久久久久电影好 | 欧美网址在线观看 | 2019中文 | 日韩av片无码一区二区不卡电影 | 久久久久在线观看 | 五月天久久综合网 | 国产视频一区精品 | 午夜精品一区二区三区视频免费看 | 日韩电影久久 | 久久人人爽人人爽人人片av软件 | 三三级黄色片之日韩 | 在线观看免费黄视频 | 在线观看不卡视频 | 欧美做受高潮电影o | 欧美午夜视频在线 | 中文字幕人成人 | 免费视频xnxx com| 四虎影视精品永久在线观看 | 日韩视频中文 | 999日韩| 中文字幕在线观看不卡 | 日韩免费小视频 | 丁香高清视频在线看看 | 黄网站色欧美视频 | 黄色app网站在线观看 | 精品久久久久久久久中文字幕 | 久久综合久久综合久久 | 黄色毛片网站在线观看 | 在线日韩亚洲 | 色视频在线观看免费 | 日韩v欧美v日本v亚洲v国产v | 欧美日韩观看 | 国产高清视频在线免费观看 | 综合色影院 | 韩国av三级 | 丁香综合网| 亚洲专区路线二 | 在线亚洲午夜片av大片 | 婷婷在线免费视频 | 人人爽人人澡 | 欧美午夜精品久久久久久浪潮 | 天天躁天天狠天天透 | 日韩精品视频在线观看免费 | 91探花在线 | 天天天天射 | 99久久精品国产欧美主题曲 | 国产福利精品视频 | 亚洲欧美视频网站 | 色在线中文字幕 | 国产资源免费 | 色偷偷网站视频 | 成人va在线观看 | www免费视频com━ | 久久99影院 | 91丨九色丨蝌蚪丨老版 | 日韩欧美电影网 | 免费看国产a | 日韩电影久久 | 久久久免费精品 | 天天干天天操天天拍 | 亚洲精品一区二区18漫画 | 国产成人福利在线观看 | 久久爱导航 | 欧美日bb| 综合久久综合久久 | 欧美日韩国产色综合一二三四 | 国产免费xvideos视频入口 | 在线国产能看的 | 伊人日日干 | 国产中文字幕视频在线 | 国产手机视频 | 久久视频这里有久久精品视频11 | 久久女同性恋中文字幕 | 亚洲天堂毛片 | 免费观看www7722午夜电影 | 国产不卡一二三区 | 久久久96 | 国产精品久久一卡二卡 | 亚洲日本va中文字幕 | 免费看国产a | 丁香婷婷社区 | 国产午夜精品一区二区三区 | 精品一区 在线 | 日本高清免费中文字幕 | 欧美久草视频 | 国产麻豆精品传媒av国产下载 | 美女免费视频一区 | 亚洲干视频在线观看 | 五月亚洲综合 | a视频在线观看 | 中文字幕日韩高清 | 亚洲黄色一级视频 | 国产视频99| 国产一区二区三区免费在线观看 | 亚洲精品国产精品久久99 | 日p视频 | 免费裸体视频网 | 99精品在线观看 | 久久综合久久久 | 九色精品在线 | 91精品办公室少妇高潮对白 | 一级片观看 | 日韩午夜一级片 | 亚洲 欧美 变态 国产 另类 | 91亚洲狠狠婷婷综合久久久 | 免费视频色 | 成人免费观看在线视频 | 草莓视频在线观看免费观看 | 免费观看国产视频 | 五月天亚洲综合 | 日日操日日插 | 激情丁香综合五月 | 激情影音先锋 | 欧美在线观看视频 | 亚洲第一区精品 | 黄在线免费观看 | av电影一区二区 | 亚洲人成影院在线 | 国产欧美在线一区二区三区 | 欧美性色19p | 五月婷婷伊人网 | 婷婷丁香国产 | 麻豆久久久久 | 亚洲精品午夜久久久久久久久久久 | 丝袜美女在线 | 在线观看国产亚洲 | 国产一二区精品 | www.夜夜爱 | 国产精品精| 免费在线国产黄色 | 国产精品国产亚洲精品看不卡15 | 国产精品视频你懂的 | 香蕉精品视频在线观看 | 99国产精品视频免费观看一公开 | 久久精品视频在线免费观看 | 伊人中文字幕在线 | 亚洲婷久久 | 色av网站 | 久久综合五月婷婷 | www夜夜操| 国产精品精品久久久久久 | 精品天堂av | 人人看人人草 | 中文字幕有码在线 | 国产一区二区不卡在线 | 最新日韩视频 | 国产精品美女久久久久久2018 | 色婷婷激情 | 国产一区二区三区免费在线观看 | 日韩网站在线观看 | 国产精品欧美激情在线观看 | 亚洲激情 | 9在线观看免费高清完整版 玖玖爱免费视频 | 69久久久 | 久草在线最新免费 | 国产精品国产三级在线专区 | 狠狠五月婷婷 | 国产精品免费视频久久久 | 91福利免费 | 97碰碰碰 | 成年人毛片在线观看 | 日产av在线播放 | 99视频在线免费播放 | 免费在线成人av | 天天操夜夜操国产精品 | 久久精品视频网站 | 天天干天天射天天爽 | 日韩一区二区三区免费视频 | av手机在线播放 | 高清中文字幕av | 手机在线欧美 | 青青射 | 91亚色免费视频 | 亚洲精选99| 高清av免费观看 | 亚洲激情视频在线观看 | 制服丝袜一区二区 | 懂色av一区二区三区蜜臀 | 精品久久九九 | 亚洲视频www| 国产成人免费观看 | 天天综合成人网 | 精品国产乱码久久久久久久 | 人人干97 | 91精品国产成人www | 毛片视频电影 | 精品国模一区二区三区 | 久久精品视频免费观看 | 九九久久久 | 国产无套精品久久久久久 | 国产黄免费| av成人免费在线 | 色的网站在线观看 | 女人魂免费观看 | 国产精品电影在线 | 欧美日韩免费视频 | 欧美91片| 99视屏| 色婷婷综合久久久久 | 久久国产精品系列 | bayu135国产精品视频 | 亚洲视频 在线观看 | 国产精品亚洲a | 国产免费久久久久 | 婷婷激情久久 | 国产精品福利在线观看 | 久久久久黄色 | 成人一级电影在线观看 | 亚洲欧美日韩一区二区三区在线观看 | 免费在线国产视频 | 天天操天天操天天操天天操天天操 | 久久国产精品区 | 日韩免费观看av | 四虎影视国产精品免费久久 | 超碰免费在线公开 | 成人免费共享视频 | 99热这里只有精品久久 | 黄色在线观看www | 在线免费观看黄色大片 | 丁香 久久 综合 | 九九热在线精品 | 久久久久在线 | 成人影视免费看 | 综合久久2023 | 久久久影视 | 国产精品免费成人 | 人人插超碰 | 激情大尺度视频 | 黄色毛片观看 | 天天激情天天干 | 亚洲国产精品影院 | 亚洲黄色av网址 | 丝袜少妇在线 | 亚洲国产精彩中文乱码av | 97色在线观看免费视频 | 在线免费看黄网站 | 中文字幕在线看 | 2019免费中文字幕 | 黄毛片在线观看 | 伊人在线视频 | 人人爽人人乐 | 国产精品18p| 国产精品久久久久婷婷二区次 | 亚在线播放中文视频 | 日韩视频一区二区在线 | 最新国产一区二区三区 | 日韩精品一区二区在线视频 | 国产亚洲精品免费 | 国产一区二区网址 | 欧美午夜精品久久久久久孕妇 | 夜夜摸夜夜爽 | 免费成人在线电影 | 欧美一区二区精品在线 | 黄色在线成人 | 日日夜夜人人天天 | 久久免费视频播放 | 一本之道乱码区 | 免费看的国产视频网站 | 99视频+国产日韩欧美 | 狠狠躁夜夜躁人人爽超碰91 | 色婷婷激情四射 | 五月婷婷综合久久 | www毛片com| 婷婷av色综合 | 91久久国产综合精品女同国语 | 超碰在线98 | 蜜臀久久99精品久久久久久网站 | 91av99| 国产视频中文字幕在线观看 | 欧美午夜理伦三级在线观看 | 欧美日韩网址 | 欧美日韩中文字幕在线视频 | 国产成人一区二区三区在线观看 | 久久五月天婷婷 | 91精品视频免费观看 | 最近中文字幕在线 | 久久久久久国产精品免费 | 国产高清免费在线播放 | 伊人精品在线 | 成人av资源站 | 久久久久久久久久久电影 | 91成人网在线 | 亚洲国产三级 | 超碰精品在线 | 欧美成人手机版 | 91精品国产综合久久久久久久 | 亚洲一区二区三区miaa149 | 在线观看免费观看在线91 | 日韩高清一二区 | 精品久久久久久久久久 | 国产精品男女啪啪 | 91精品对白一区国产伦 | 一本大道久久精品懂色aⅴ 五月婷社区 | 亚洲激精日韩激精欧美精品 | 国产小视频你懂的 | 国产精品igao视频网入口 | 天天射天天干天天操 | 欧美日韩国产精品一区二区亚洲 | 成人黄色免费在线观看 | 啪嗒啪嗒免费观看完整版 | 五月亚洲婷婷 | 日韩首页 | 久久99最新地址 | 久久久久久久99 | 婷婷色在线播放 | 91色影院 | 手机看片1042 | 欧美另类高清 videos | 天天射天天干天天爽 | 久久99国产精品久久99 | 在线播放精品一区二区三区 | 成 人 黄 色 视频免费播放 | 国产伦精品一区二区三区在线 | 国产婷婷vvvv激情久 | 日韩专区av | 亚洲精品视频第一页 | 亚洲va男人天堂 | 色99色| 国产精品高潮呻吟久久av无 | 超碰人人91 | 四虎精品成人免费网站 | 不卡av免费在线观看 | 成人午夜免费剧场 | 日韩一级黄色av | 91在线视频免费91 | 亚洲我射av | 欧美色综合天天久久综合精品 | 日日爱av| 制服丝袜天堂 | 深爱婷婷网 | 国产精品自产拍在线观看网站 | 精品久久久国产 | 中文字幕第 | 在线中文字幕一区二区 | 天天操比 | 人人搞人人爽 | 国产精品2019 | 91精品国自产在线观看 | 国产一区二区播放 | 国产亚洲精品久久久久动 | 日韩国产精品一区 | 日韩高清免费无专码区 | 欧日韩在线| 久操伊人| 成人国产精品一区二区 | 波多野结衣小视频 | 国产成人久久精品77777综合 | aaawww| 一区二区视频播放 | 亚洲综合网站在线观看 | 天天干天天操天天 | 国产精品一区二区三区免费看 | 日本一区二区三区免费观看 | 精品国产久 | 亚洲国产精品一区二区久久hs | 天天亚洲| 国产成人99久久亚洲综合精品 | 在线探花| 九九热在线精品视频 | 91亚洲国产| 奇米网网址 | 看毛片的网址 | 日韩极品视频在线观看 | 欧美国产亚洲精品久久久8v | 国产96在线 | 日韩精品久久一区二区三区 | 色吊丝在线永久观看最新版本 | 久久av电影| 国产精品久久久久久999 | 一区二区三区四区精品 | 97精品伊人 | 九九视频免费在线观看 | av在线一级 | 激情五月五月婷婷 | 免费三级a | 国产一区二三区好的 | 99这里都是精品 | 色a资源在线 | 亚洲h视频在线 | 日日草夜夜操 | 久久爱资源网 | 欧美精品国产综合久久 | 国产日韩一区在线 | 亚洲精品xx | 九九九九精品九九九九 | 深爱激情综合网 | 久草免费资源 | 日本大尺码专区mv | 日韩午夜电影网 | 欧美a√大片 | 懂色av一区二区在线播放 | 91在线最新 | 久久精品91视频 | 久草在线视频精品 | 在线成人免费电影 | 欧美成人亚洲成人 | 成人久久国产 | 色欧美视频 | 国产成人免费高清 | 激情五月婷婷综合 | 日韩中文字幕电影 | 国产在线999 | 欧美一级片 | 九热精品 | 亚洲婷婷免费 | 色六月婷婷| 国产成人精品综合久久久久99 | 久久综合欧美精品亚洲一区 | 三级黄色a | 国产精品一区二区三区在线 | 中文字幕久久精品亚洲乱码 | 日韩二区在线播放 | 欧美做受69 | 狠狠干五月天 | 亚洲精品国产精品国自产在线 | 99免费在线播放99久久免费 | 久草网视频在线观看 | 久久久国产精品成人免费 | 怡红院久久 | 精品国产一二三 | 黄色在线观看污 | 国偷自产中文字幕亚洲手机在线 | 网站免费黄色 | 亚洲精品一区二区三区新线路 | 国产不卡在线观看 | 日日夜夜艹| h动漫中文字幕 | 五月丁香 | 狠狠干狠狠操 | 国内精品久久久久影院一蜜桃 | 婷婷国产精品 | 日韩一区二区免费在线观看 | 欧美午夜理伦三级在线观看 | 国产一区免费 | 在线观看黄色小视频 | 一级免费av | 狠狠干婷婷色 | 波多野结衣在线观看一区二区三区 | 久草免费手机视频 | 国产精品久久久久久久久久新婚 | 在线免费黄色av | av一区二区三区在线观看 | 在线精品亚洲 | 精品国产一区二区三区久久久蜜月 | 黄色免费在线看 | 啪一啪在线 | a久久久久| 午夜色婷婷 | 欧美午夜理伦三级在线观看 | 99精品在线观看视频 | 色天天久久 | 天天操天天弄 | 91av蜜桃| 国产成人久久精品 | 成年人免费在线看 | 免费男女羞羞的视频网站中文字幕 | 久视频在线 | 国产日韩欧美综合在线 | 丁香九月激情综合 | 久久99精品国产麻豆婷婷 | 国产精品一区二区三区视频免费 | av中文天堂在线 | 最近更新的中文字幕 | 欧美analxxxx | 国产精品情侣视频 | 久久精品久久久久久久 | 国产成人精品999在线观看 | 国产精品 中文字幕 亚洲 欧美 | 高清av在线免费观看 | 色综合 久久精品 | 高清av中文在线字幕观看1 | 91精品国产一区 | 国产精品区免费视频 | 丰满少妇在线观看网站 | 亚洲欧美国产日韩在线观看 | 青草草在线 | 欧美日韩精品久久久 | 久草视频在线看 | 亚洲欧美一区二区三区孕妇写真 | 日韩黄色免费电影 | 日韩一级黄色片 | 91激情小视频 | 国产黄色视 | 国产黄网站在线观看 | 中文字幕在线观看一区二区 | 激情视频一区二区三区 | 一区二区三区高清在线观看 | 五月婷网站 | 91视频啪| 粉嫩高清一区二区三区 | 久久久男人的天堂 | 91视频专区 | 亚洲精品国产拍在线 | 成人亚洲免费 | www.超碰97.com| 亚洲最大成人免费网站 | 四虎8848免费高清在线观看 | 99综合视频 | 黄色.com| 波多野结衣在线观看视频 | 免费av试看 | 在线视频 成人 | 日韩精品国产一区 | 国产精品a久久久久 | 高清不卡免费视频 | 欧美成人h版| 天天色天天草天天射 | 91桃色免费观看 | av最新资源 | 免费日韩高清 | 狠狠色丁香婷婷综合基地 | 美女精品网站 | 国产黄色成人av | 色资源中文字幕 | 中文字幕黄色网址 | 亚洲精品1区2区3区 超碰成人网 | 丁香九月激情综合 | 911久久香蕉国产线看观看 | 婷婷丁香激情综合 | 国产高清 不卡 | 亚洲视频在线播放 | 在线亚洲欧美日韩 | 色网站中文字幕 | 婷婷在线不卡 | 91福利试看 | 黄色的网站免费看 | 黄网站app在线观看免费视频 | 亚洲国产精品久久久久久 | 狠狠久久 | 精品久久久影院 | 97国产超碰 | 在线免费视频你懂的 | 亚洲成人软件 | 在线视频 成人 | 久草视频在线看 | www.夜夜操.com | 日本九九视频 | 久久精品视频免费 | 2019中文在线观看 | 丁香久久激情 | av一区二区三区在线观看 | 99精品乱码国产在线观看 | 粉嫩av一区二区三区四区在线观看 | 91精选在线观看 | 91在线免费视频观看 | 天堂久久电影网 | 韩国一区在线 | 欧美日韩一区二区免费在线观看 | 中文视频一区二区 | 色婷婷在线播放 | 中文字字幕在线 | 视频一区二区国产 | 伊人在线视频 | 国产偷国产偷亚洲清高 | 亚洲日本黄色 | 久久人人爽av | 精品久久久久久综合 | 日韩系列在线观看 | 久久精品一区二区三区视频 | 九九涩涩av台湾日本热热 | 91av免费观看 | 超碰九九 | 色婷婷国产精品一区在线观看 | 高清在线一区二区 | 日本亚洲国产 | 丁香六月国产 | 人人射人人爱 | 天天曰天天射 | 日韩av电影中文字幕 | 国产精品久久久久久久久岛 | 亚洲欧美日韩精品久久奇米一区 | 亚洲高清视频在线 | 国产麻豆剧传媒免费观看 | 久久无码精品一区二区三区 | 91在线亚洲 | 日韩高清免费在线观看 | 欧美日韩高清在线观看 | 亚洲精品动漫成人3d无尽在线 | 国产精品99在线播放 | 超碰97人人射妻 | 免费久久久久久 | av片子在线观看 | 精品在线视频一区二区三区 | 久草视频在线播放 | 免费av在 | 欧美日韩国产一区二区三区 | 天天操天天射天天插 | 精品视频中文字幕 | 日本精品中文字幕在线观看 | 婷婷视频在线观看 | 久久不卡日韩美女 | 亚洲最新av网址 | 毛片视频网址 | 日韩精品免费在线视频 | 黄色91在线观看 | 天天操天天干天天综合网 | 麻豆国产在线视频 | a级一a一级在线观看 | 69绿帽绿奴3pvideos | 精品国产乱码久久久久久1区二区 | 国产精品乱码久久久久久1区2区 | 久久久久久久久久网站 | 日日操日日 | 特级aaa毛片 | 91桃色在线观看视频 | 丝袜美腿在线视频 | 久草在线视频在线 | 夜夜夜夜猛噜噜噜噜噜初音未来 | 久久人人爽爽人人爽人人片av | 成人在线视频在线观看 | 国产九九九视频 | 免费的黄色av | 九九爱免费视频 | 久久精品欧美一区二区三区麻豆 | 免费在线观看av的网站 | 欧美va天堂va视频va在线 | 亚洲伊人成综合网 | aav在线| 天天舔天天射天天操 | 91麻豆精品国产91久久久使用方法 | 国产一级小视频 | 99情趣网视频 | 97精品国产 | 狠狠狠狠狠狠天天爱 | 成人午夜剧场在线观看 | 久久久国产精品一区二区三区 | 日韩国产精品一区 | 成人蜜桃 | 亚洲五月综合 | 亚洲国产剧情av | 国产在线播放一区二区三区 | 天天干天天拍天天操 | 97超级碰碰碰碰久久久久 | 国产精品久久久久久欧美 | 国产成人精品免费在线观看 | 久久免费成人网 | 亚洲精品乱码久久久久久久久久 | 日韩久久精品一区二区 | 国产91免费在线 | 中文一区在线观看 | 久久69精品久久久久久久电影好 | 精品999久久久 | www黄| av丁香花| 色在线中文字幕 | 色网站国产精品 | 欧美人人爱| 最近2019好看的中文字幕免费 | 91激情 | 在线日本看片免费人成视久网 | 91视频免费看网站 | 国产精品久久久久久久免费大片 | 日韩两性视频 | 蜜臀av性久久久久蜜臀aⅴ涩爱 | 久久精品超碰 | 欧美日韩视频在线 | 91av大全 | 97精品国产97久久久久久免费 | 久久99电影| 国产明星视频三级a三级点| 久久成人在线视频 | 免费在线色 | 国内精品视频久久 | 久草视频99 | www.夜夜操 | 丁香在线观看完整电影视频 | 91欧美日韩国产 | 国产色在线观看 | 国产色影院 | 久久精品视 | 亚州性色 | 国产精品自产拍在线观看桃花 | 波多野结衣视频一区 | 日韩精品一区二区久久 | 久久视频在线观看免费 | 国产午夜三级 | 婷婷色在线资源 | 日韩视频一区二区三区 | 国产一区二区在线播放 | 亚洲三级影院 | 亚洲国产网站 | 伊人永久 | 在线看的av网站 | 欧美激情在线看 | 五月天久久久久久 | 日韩精品一区二区三区中文字幕 | av看片网 | 亚洲午夜精品一区二区三区电影院 | 五月婷婷亚洲 | 免费a v在线| 伊人一级 | 天天操天天摸天天干 | 国产精品高潮呻吟久久av无 | 丁香电影小说免费视频观看 | 国产精品免费观看在线 | 毛片网站在线观看 | 久久久亚洲成人 | 免费在线观看不卡av | 亚洲一区美女视频在线观看免费 | 婷婷综合电影 | 国产真实在线 | 中文字幕 成人 | 久久免费精品一区二区三区 | 亚洲更新最快 | 92中文资源在线 | 黄色小说免费观看 | 日韩有码在线播放 | 中文字幕在线观看播放 | 国产一级黄色电影 | 久久看看 | 精品国产免费看 | 国产大陆亚洲精品国产 |