亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

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

2019-11-11 04:46:11
字體:
來源:轉載
供稿:網友

安裝和配置詳解

本文介紹的 Zookeeper 是以 3.2.2 這個穩定版本為基礎,最新的版本可以通過官網http://hadoop.apache.org/zookeeper/來獲取,Zookeeper 的安裝非常簡單,下面將從單機模式和集群模式兩個方面介紹 Zookeeper 的安裝和配置。

單機模式

單機安裝非常簡單,只要獲取到 Zookeeper 的壓縮包并解壓到某個目錄如:/home/zookeeper-3.2.2 下,Zookeeper 的啟動腳本在 bin 目錄下,linux 下的啟動腳本是 zkServer.sh,在 3.2.2 這個版本 Zookeeper 沒有提供 windows 下的啟動腳本,所以要想在 windows 下啟動 Zookeeper 要自己手工寫一個,如清單 1 所示:

清單 1. Windows 下 Zookeeper 啟動腳本
 setlocal  set ZOOCFGDIR=%~dp0%../conf  set ZOO_LOG_DIR=%~dp0%..  set ZOO_LOG4J_PROP=INFO,CONSOLE  set CLASSPATH=%ZOOCFGDIR%  set CLASSPATH=%~dp0../*;%~dp0../lib/*;%CLASSPATH%  set CLASSPATH=%~dp0../build/classes;%~dp0../build/lib/*;%CLASSPATH%  set ZOOCFG=%ZOOCFGDIR%/zoo.cfg  set ZOOMAIN=org.apache.zookeeper.server.ZooKeeperServerMain  java "-Dzookeeper.log.dir=%ZOO_LOG_DIR%" "-Dzookeeper.root.logger=%ZOO_LOG4J_PROP%"  -cp "%CLASSPATH%" %ZOOMAIN% "%ZOOCFG%" %*  endlocal

在你執行啟動腳本之前,還有幾個基本的配置項需要配置一下,Zookeeper 的配置文件在 conf 目錄下,這個目錄下有 zoo_sample.cfg 和 log4j.properties,你需要做的就是將 zoo_sample.cfg 改名為 zoo.cfg,因為 Zookeeper 在啟動時會找這個文件作為默認配置文件。下面詳細介紹一下,這個配置文件中各個配置項的意義。

 tickTime=2000  dataDir=D:/devtools/zookeeper-3.2.2/build  clientPort=2181tickTime:這個時間是作為 Zookeeper 服務器之間或客戶端與服務器之間維持心跳的時間間隔,也就是每個 tickTime 時間就會發送一個心跳。dataDir:顧名思義就是 Zookeeper 保存數據的目錄,默認情況下,Zookeeper 將寫數據的日志文件也保存在這個目錄里。clientPort:這個端口就是客戶端連接 Zookeeper 服務器的端口,Zookeeper 會監聽這個端口,接受客戶端的訪問請求。

當這些配置項配置好后,你現在就可以啟動 Zookeeper 了,啟動后要檢查 Zookeeper 是否已經在服務,可以通過 netstat – ano 命令查看是否有你配置的 clientPort 端口號在監聽服務。

集群模式

Zookeeper 不僅可以單機提供服務,同時也支持多機組成集群來提供服務。實際上 Zookeeper 還支持另外一種偽集群的方式,也就是可以在一臺物理機上運行多個 Zookeeper 實例,下面將介紹集群模式的安裝和配置。

Zookeeper 的集群模式的安裝和配置也不是很復雜,所要做的就是增加幾個配置項。集群模式除了上面的三個配置項還要增加下面幾個配置項:

 initLimit=5  syncLimit=2  server.1=192.168.211.1:2888:3888  server.2=192.168.211.2:2888:3888initLimit:這個配置項是用來配置 Zookeeper 接受客戶端(這里所說的客戶端不是用戶連接 Zookeeper 服務器的客戶端,而是 Zookeeper 服務器集群中連接到 Leader 的 Follower 服務器)初始化連接時最長能忍受多少個心跳時間間隔數。當已經超過 10 個心跳的時間(也就是 tickTime)長度后 Zookeeper 服務器還沒有收到客戶端的返回信息,那么表明這個客戶端連接失敗。總的時間長度就是 5*2000=10 秒syncLimit:這個配置項標識 Leader 與 Follower 之間發送消息,請求和應答時間長度,最長不能超過多少個 tickTime 的時間長度,總的時間長度就是 2*2000=4 秒server.A=B:C:D:其中 A 是一個數字,表示這個是第幾號服務器;B 是這個服務器的 ip 地址;C 表示的是這個服務器與集群中的 Leader 服務器交換信息的端口;D 表示的是萬一集群中的 Leader 服務器掛了,需要一個端口來重新進行選舉,選出一個新的 Leader,而這個端口就是用來執行選舉時服務器相互通信的端口。如果是偽集群的配置方式,由于 B 都是一樣,所以不同的 Zookeeper 實例通信端口號不能一樣,所以要給它們分配不同的端口號。

除了修改 zoo.cfg 配置文件,集群模式下還要配置一個文件 myid,這個文件在 dataDir 目錄下,這個文件里面就有一個數據就是 A 的值,Zookeeper 啟動時會讀取這個文件,拿到里面的數據與 zoo.cfg 里面的配置信息比較從而判斷到底是那個 server。

數據模型

Zookeeper 會維護一個具有層次關系的數據結構,它非常類似于一個標準的文件系統,如圖 1 所示:

圖 1 Zookeeper 數據結構
圖 1 Zookeeper 數據結構

Zookeeper 這種數據結構有如下這些特點:

每個子目錄項如 NameService 都被稱作為 znode,這個 znode 是被它所在的路徑唯一標識,如 Server1 這個 znode 的標識為 /NameService/Server1znode 可以有子節點目錄,并且每個 znode 可以存儲數據,注意 EPHEMERAL 類型的目錄節點不能有子節點目錄znode 是有版本的,每個 znode 中存儲的數據可以有多個版本,也就是一個訪問路徑中可以存儲多份數據znode 可以是臨時節點,一旦創建這個 znode 的客戶端與服務器失去聯系,這個 znode 也將自動刪除,Zookeeper 的客戶端和服務器通信采用長連接方式,每個客戶端和服務器通過心跳來保持連接,這個連接狀態稱為 session,如果 znode 是臨時節點,這個 session 失效,znode 也就刪除了znode 的目錄名可以自動編號,如 App1 已經存在,再創建的話,將會自動命名為 App2znode 可以被監控,包括這個目錄節點中存儲的數據的修改,子節點目錄的變化等,一旦變化可以通知設置監控的客戶端,這個是 Zookeeper 的核心特性,Zookeeper 的很多功能都是基于這個特性實現的,后面在典型的應用場景中會有實例介紹

如何使用

Zookeeper 作為一個分布式的服務框架,主要用來解決分布式集群中應用系統的一致性問題,它能提供基于類似于文件系統的目錄節點樹方式的數據存儲,但是 Zookeeper 并不是用來專門存儲數據的,它的作用主要是用來維護和監控你存儲的數據的狀態變化。通過監控這些數據狀態的變化,從而可以達到基于數據的集群管理,后面將會詳細介紹 Zookeeper 能夠解決的一些典型問題,這里先介紹一下,Zookeeper 的操作接口和簡單使用示例。

常用接口列表

客戶端要連接 Zookeeper 服務器可以通過創建 org.apache.zookeeper. ZooKeeper 的一個實例對象,然后調用這個類提供的接口來和服務器交互。

前面說了 ZooKeeper 主要是用來維護和監控一個目錄節點樹中存儲的數據的狀態,所有我們能夠操作 ZooKeeper 的也和操作目錄節點樹大體一樣,如創建一個目錄節點,給某個目錄節點設置數據,獲取某個目錄節點的所有子目錄節點,給某個目錄節點設置權限和監控這個目錄節點的狀態變化。

這些接口如下表所示:

表 1 org.apache.zookeeper. ZooKeeper 方法列表
方法名方法功能描述
Stringcreate(String path, byte[] data, List<ACL> acl,CreateMode createMode)創建一個給定的目錄節點 path, 并給它設置數據,CreateMode 標識有四種形式的目錄節點,分別是 PERSISTENT:持久化目錄節點,這個目錄節點存儲的數據不會丟失;PERSISTENT_SEQUENTIAL:順序自動編號的目錄節點,這種目錄節點會根據當前已近存在的節點數自動加 1,然后返回給客戶端已經成功創建的目錄節點名;EPHEMERAL:臨時目錄節點,一旦創建這個節點的客戶端與服務器端口也就是 session 超時,這種節點會被自動刪除;EPHEMERAL_SEQUENTIAL:臨時自動編號節點
Statexists(String path, boolean watch)判斷某個 path 是否存在,并設置是否監控這個目錄節點,這里的 watcher 是在創建 ZooKeeper 實例時指定的 watcher,exists方法還有一個重載方法,可以指定特定的 watcher
Statexists(String path,Watcher watcher)重載方法,這里給某個目錄節點設置特定的 watcher,Watcher 在 ZooKeeper 是一個核心功能,Watcher 可以監控目錄節點的數據變化以及子目錄的變化,一旦這些狀態發生變化,服務器就會通知所有設置在這個目錄節點上的 Watcher,從而每個客戶端都很快知道它所關注的目錄節點的狀態發生變化,而做出相應的反應
void delete(String path, int version)刪除 path 對應的目錄節點,version 為 -1 可以匹配任何版本,也就刪除了這個目錄節點所有數據
List<String>getChildren(String path, boolean watch)獲取指定 path 下的所有子目錄節點,同樣 getChildren方法也有一個重載方法可以設置特定的 watcher 監控子節點的狀態
StatsetData(String path, byte[] data, int version)給 path 設置數據,可以指定這個數據的版本號,如果 version 為 -1 怎可以匹配任何版本
byte[] getData(String path, boolean watch, Stat stat)獲取這個 path 對應的目錄節點存儲的數據,數據的版本等信息可以通過 stat 來指定,同時還可以設置是否監控這個目錄節點數據的狀態
voidaddAuthInfo(String scheme, byte[] auth)客戶端將自己的授權信息提交給服務器,服務器將根據這個授權信息驗證客戶端的訪問權限。
StatsetACL(String path,List<ACL> acl, int version)給某個目錄節點重新設置訪問權限,需要注意的是 Zookeeper 中的目錄節點權限不具有傳遞性,父目錄節點的權限不能傳遞給子目錄節點。目錄節點 ACL 由兩部分組成:perms 和 id。Perms 有 ALL、READ、WRITE、CREATE、DELETE、ADMIN 幾種 而 id 標識了訪問目錄節點的身份列表,默認情況下有以下兩種:ANYONE_ID_UNSAFE = new Id("world", "anyone") 和 AUTH_IDS = new Id("auth", "") 分別表示任何人都可以訪問和創建者擁有訪問權限。
List<ACL>getACL(String path,Stat stat)獲取某個目錄節點的訪問權限列表

除了以上這些上表中列出的方法之外還有一些重載方法,如都提供了一個回調類的重載方法以及可以設置特定 Watcher 的重載方法,具體的方法可以參考 org.apache.zookeeper. ZooKeeper 類的 API 說明。

基本操作

下面給出基本的操作 ZooKeeper 的示例代碼,這樣你就能對 ZooKeeper 有直觀的認識了。下面的清單包括了創建與 ZooKeeper 服務器的連接以及最基本的數據操作:

清單 2. ZooKeeper 基本的操作示例
 // 創建一個與服務器的連接 ZooKeeper zk = new ZooKeeper("localhost:" + CLIENT_PORT,         ClientBase.CONNECTION_TIMEOUT, new Watcher() {             // 監控所有被觸發的事件            public void process(WatchedEvent event) {                 System.out.println("已經觸發了" + event.getType() + "事件!");             }         });  // 創建一個目錄節點 zk.create("/testRootPath", "testRootData".getBytes(), Ids.OPEN_ACL_UNSAFE,   CreateMode.PERSISTENT);  // 創建一個子目錄節點 zk.create("/testRootPath/testChildPathOne", "testChildDataOne".getBytes(),   Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);  System.out.println(new String(zk.getData("/testRootPath",false,null)));  // 取出子目錄節點列表 System.out.println(zk.getChildren("/testRootPath",true));  // 修改子目錄節點數據 zk.setData("/testRootPath/testChildPathOne","modifyChildDataOne".getBytes(),-1);  System.out.println("目錄節點狀態:["+zk.exists("/testRootPath",true)+"]");  // 創建另外一個子目錄節點 zk.create("/testRootPath/testChildPathTwo", "testChildDataTwo".getBytes(),    Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);  System.out.println(new String(zk.getData("/testRootPath/testChildPathTwo",true,null)));  // 刪除子目錄節點 zk.delete("/testRootPath/testChildPathTwo",-1);  zk.delete("/testRootPath/testChildPathOne",-1);  // 刪除父目錄節點 zk.delete("/testRootPath",-1);  // 關閉連接 zk.close();

輸出的結果如下:

已經觸發了 None 事件! testRootData  [testChildPathOne] 目錄節點狀態:[5,5,1281804532336,1281804532336,0,1,0,0,12,1,6] 已經觸發了 NodeChildrenChanged 事件! testChildDataTwo 已經觸發了 NodeDeleted 事件!已經觸發了 NodeDeleted 事件!

當對目錄節點監控狀態打開時,一旦目錄節點的狀態發生變化,Watcher 對象的 process 方法就會被調用。

ZooKeeper 典型的應用場景

Zookeeper 從設計模式角度來看,是一個基于觀察者模式設計的分布式服務管理框架,它負責存儲和管理大家都關心的數據,然后接受觀察者的注冊,一旦這些數據的狀態發生變化,Zookeeper 就將負責通知已經在 Zookeeper 上注冊的那些觀察者做出相應的反應,從而實現集群中類似 Master/Slave 管理模式,關于 Zookeeper 的詳細架構等內部細節可以閱讀 Zookeeper 的源碼

下面詳細介紹這些典型的應用場景,也就是 Zookeeper 到底能幫我們解決那些問題?下面將給出答案。

統一命名服務(Name Service)

分布式應用中,通常需要有一套完整的命名規則,既能夠產生唯一的名稱又便于人識別和記住,通常情況下用樹形的名稱結構是一個理想的選擇,樹形的名稱結構是一個有層次的目錄結構,既對人友好又不會重復。說到這里你可能想到了 JNDI,沒錯 Zookeeper 的 Name Service 與 JNDI 能夠完成的功能是差不多的,它們都是將有層次的目錄結構關聯到一定資源上,但是 Zookeeper 的 Name Service 更加是廣泛意義上的關聯,也許你并不需要將名稱關聯到特定資源上,你可能只需要一個不會重復名稱,就像數據庫中產生一個唯一的數字主鍵一樣。

Name Service 已經是 Zookeeper 內置的功能,你只要調用 Zookeeper 的 API 就能實現。如調用 create 接口就可以很容易創建一個目錄節點。

配置管理(Configuration Management)

配置的管理在分布式應用環境中很常見,例如同一個應用系統需要多臺 PC Server 運行,但是它們運行的應用系統的某些配置項是相同的,如果要修改這些相同的配置項,那么就必須同時修改每臺運行這個應用系統的 PC Server,這樣非常麻煩而且容易出錯。

像這樣的配置信息完全可以交給 Zookeeper 來管理,將配置信息保存在 Zookeeper 的某個目錄節點中,然后將所有需要修改的應用機器監控配置信息的狀態,一旦配置信息發生變化,每臺應用機器就會收到 Zookeeper 的通知,然后從 Zookeeper 獲取新的配置信息應用到系統中。

圖 2. 配置管理結構圖
圖 2. 配置管理結構圖

集群管理(Group Membership)

Zookeeper 能夠很容易的實現集群管理的功能,如有多臺 Server 組成一個服務集群,那么必須要一個“總管”知道當前集群中每臺機器的服務狀態,一旦有機器不能提供服務,集群中其它集群必須知道,從而做出調整重新分配服務策略。同樣當增加集群的服務能力時,就會增加一臺或多臺 Server,同樣也必須讓“總管”知道。

Zookeeper 不僅能夠幫你維護當前的集群中機器的服務狀態,而且能夠幫你選出一個“總管”,讓這個總管來管理集群,這就是 Zookeeper 的另一個功能 Leader Election。

它們的實現方式都是在 Zookeeper 上創建一個 EPHEMERAL 類型的目錄節點,然后每個 Server 在它們創建目錄節點的父目錄節點上調用getChildren(String path, boolean watch) 方法并設置 watch 為 true,由于是 EPHEMERAL 目錄節點,當創建它的 Server 死去,這個目錄節點也隨之被刪除,所以 Children 將會變化,這時 getChildren上的 Watch 將會被調用,所以其它 Server 就知道已經有某臺 Server 死去了。新增 Server 也是同樣的原理。

Zookeeper 如何實現 Leader Election,也就是選出一個 Master Server。和前面的一樣每臺 Server 創建一個 EPHEMERAL 目錄節點,不同的是它還是一個 SEQUENTIAL 目錄節點,所以它是個 EPHEMERAL_SEQUENTIAL 目錄節點。之所以它是 EPHEMERAL_SEQUENTIAL 目錄節點,是因為我們可以給每臺 Server 編號,我們可以選擇當前是最小編號的 Server 為 Master,假如這個最小編號的 Server 死去,由于是 EPHEMERAL 節點,死去的 Server 對應的節點也被刪除,所以當前的節點列表中又出現一個最小編號的節點,我們就選擇這個節點為當前 Master。這樣就實現了動態選擇 Master,避免了傳統意義上單 Master 容易出現單點故障的問題。

圖 3. 集群管理結構圖
圖 3. 集群管理結構圖

這部分的示例代碼如下,完整的代碼請看附件:

清單 3. Leader Election 關鍵代碼
 void findLeader() throws InterruptedException {         byte[] leader = null;         try {             leader = zk.getData(root + "/leader", true, null);         } catch (Exception e) {             logger.error(e);         }         if (leader != null) {             following();         } else {             String newLeader = null;             try {                 byte[] localhost = InetAddress.getLocalHost().getAddress();                 newLeader = zk.create(root + "/leader", localhost,                 ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);             } catch (Exception e) {                 logger.error(e);             }             if (newLeader != null) {                 leading();             } else {                 mutex.wait();             }         }     }

共享鎖(Locks)

共享鎖在同一個進程中很容易實現,但是在跨進程或者在不同 Server 之間就不好實現了。Zookeeper 卻很容易實現這個功能,實現方式也是需要獲得鎖的 Server 創建一個 EPHEMERAL_SEQUENTIAL 目錄節點,然后調用 getChildren方法獲取當前的目錄節點列表中最小的目錄節點是不是就是自己創建的目錄節點,如果正是自己創建的,那么它就獲得了這個鎖,如果不是那么它就調用 exists(String path, boolean watch) 方法并監控 Zookeeper 上目錄節點列表的變化,一直到自己創建的節點是列表中最小編號的目錄節點,從而獲得鎖,釋放鎖很簡單,只要刪除前面它自己所創建的目錄節點就行了。

圖 4. Zookeeper 實現 Locks 的流程圖
圖 4. Zookeeper 實現 Locks 的流程圖

同步鎖的實現代碼如下,完整的代碼請看附件:

清單 4. 同步鎖的關鍵代碼
 void getLock() throws KeeperException, InterruptedException{         List<String> list = zk.getChildren(root, false);         String[] nodes = list.toArray(new String[list.size()]);         Arrays.sort(nodes);         if(myZnode.equals(root+"/"+nodes[0])){             doAction();         }         else{             waitForLock(nodes[0]);         }     }     void waitForLock(String lower) throws InterruptedException, KeeperException {        Stat stat = zk.exists(root + "/" + lower,true);         if(stat != null){             mutex.wait();         }         else{             getLock();         }     }

隊列管理

Zookeeper 可以處理兩種類型的隊列:

當一個隊列的成員都聚齊時,這個隊列才可用,否則一直等待所有成員到達,這種是同步隊列。隊列按照 FIFO 方式進行入隊和出隊操作,例如實現生產者和消費者模型。

同步隊列用 Zookeeper 實現的實現思路如下:

創建一個父目錄 /synchronizing,每個成員都監控標志(Set Watch)位目錄 /synchronizing/start 是否存在,然后每個成員都加入這個隊列,加入隊列的方式就是創建 /synchronizing/member_i 的臨時目錄節點,然后每個成員獲取 / synchronizing 目錄的所有目錄節點,也就是 member_i。判斷 i 的值是否已經是成員的個數,如果小于成員個數等待 /synchronizing/start 的出現,如果已經相等就創建 /synchronizing/start。

用下面的流程圖更容易理解:

圖 5. 同步隊列流程圖
圖 5. 同步隊列流程圖

同步隊列的關鍵代碼如下,完整的代碼請看附件:

清單 5. 同步隊列
 void addQueue() throws KeeperException, InterruptedException{         zk.exists(root + "/start",true);         zk.create(root + "/" + name, new byte[0], Ids.OPEN_ACL_UNSAFE,         CreateMode.EPHEMERAL_SEQUENTIAL);         synchronized (mutex) {             List<String> list = zk.getChildren(root, false);             if (list.size() < size) {                 mutex.wait();             } else {                 zk.create(root + "/start", new byte[0], Ids.OPEN_ACL_UNSAFE,                 CreateMode.PERSISTENT);             }         }  }

當隊列沒滿是進入 wait(),然后會一直等待 Watch 的通知,Watch 的代碼如下:

 public void process(WatchedEvent event) {         if(event.getPath().equals(root + "/start") &&         event.getType() == Event.EventType.NodeCreated){             System.out.println("得到通知");             super.process(event);             doAction();         }     }

FIFO 隊列用 Zookeeper 實現思路如下:

實現的思路也非常簡單,就是在特定的目錄下創建 SEQUENTIAL 類型的子目錄 /queue_i,這樣就能保證所有成員加入隊列時都是有編號的,出隊列時通過 getChildren( ) 方法可以返回當前所有的隊列中的元素,然后消費其中最小的一個,這樣就能保證 FIFO。

下面是生產者和消費者這種隊列形式的示例代碼,完整的代碼請看附件:

清單 6. 生產者代碼
 boolean produce(int i) throws KeeperException, InterruptedException{         ByteBuffer b = ByteBuffer.allocate(4);         byte[] value;         b.putInt(i);         value = b.array();         zk.create(root + "/element", value, ZooDefs.Ids.OPEN_ACL_UNSAFE,                     CreateMode.PERSISTENT_SEQUENTIAL);         return true;     }
清單 7. 消費者代碼
 int consume() throws KeeperException, InterruptedException{         int retvalue = -1;         Stat stat = null;         while (true) {             synchronized (mutex) {                 List<String> list = zk.getChildren(root, true);                 if (list.size() == 0) {                     mutex.wait();                 } else {                     Integer min = new Integer(list.get(0).substring(7));                     for(String s : list){                         Integer tempValue = new Integer(s.substring(7));                         if(tempValue < min) min = tempValue;                     }                     byte[] b = zk.getData(root + "/element" + min,false, stat);                     zk.delete(root + "/element" + min, 0);                     ByteBuffer buffer = ByteBuffer.wrap(b);                     retvalue = buffer.getInt();                     return retvalue;                 }             }         }  }

總結

Zookeeper 作為 Hadoop 項目中的一個子項目,是 Hadoop 集群管理的一個必不可少的模塊,它主要用來控制集群中的數據,如它管理 Hadoop 集群中的 NameNode,還有 Hbase 中 Master Election、Server 之間狀態同步等。

本文介紹的 Zookeeper 的基本知識,以及介紹了幾個典型的應用場景。這些都是 Zookeeper 的基本功能,最重要的是 Zoopkeeper 提供了一套很好的分布式集群管理的機制,就是它這種基于層次型的目錄樹的數據結構,并對樹中的節點進行有效管理,從而可以設計出多種多樣的分布式的數據管理模型,而不僅僅局限于上面提到的幾個常用應用場景。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产日韩精品视频| 欧美黑人xxx| 国产欧美一区二区三区久久| 国产中文欧美精品| 2023亚洲男人天堂| 欧美中文在线观看| 亚洲国产成人精品女人久久久| 欧美国产视频日韩| 国产香蕉精品视频一区二区三区| 日韩成人黄色av| 日韩免费在线电影| 青青草99啪国产免费| 45www国产精品网站| 亚洲香蕉成人av网站在线观看| 91免费人成网站在线观看18| 久久91精品国产91久久跳| 国产成人精品a视频一区www| 国产欧美精品xxxx另类| 亚洲天堂男人的天堂| 不卡av电影在线观看| 欧美www在线| 亚洲一级免费视频| 欧美黄色三级网站| 亚洲免费av网址| 国产综合香蕉五月婷在线| 亚洲女在线观看| 国产精品小说在线| 色噜噜国产精品视频一区二区| 国产成人av网址| 国产精品一区二区三区成人| 亚洲缚视频在线观看| 伊人一区二区三区久久精品| 亚洲欧美国产日韩天堂区| 日本精品中文字幕| 欧美日韩国产激情| 国产精品ⅴa在线观看h| 日韩美女写真福利在线观看| 亚洲级视频在线观看免费1级| 日韩美女写真福利在线观看| 青青久久av北条麻妃海外网| 久久精品国产亚洲精品2020| 狠狠综合久久av一区二区小说| 狠狠综合久久av一区二区小说| 欧美第一黄网免费网站| 久久久免费电影| 国产精品亚洲精品| 久久99热精品| 日韩高清不卡av| 精品美女永久免费视频| 77777亚洲午夜久久多人| 亚洲va男人天堂| 亚洲人成在线一二| 九九热这里只有在线精品视| 亚洲最大福利视频网| 亚洲免费电影一区| 亚洲国产精品999| 久久精品国产欧美激情| 韩国v欧美v日本v亚洲| 亚洲精品www久久久久久广东| 久久久91精品国产一区不卡| 91精品视频一区| 国产成人精品久久久| 2019国产精品自在线拍国产不卡| 国产色视频一区| 欧美日韩视频免费播放| 91老司机精品视频| 91精品在线观看视频| 日韩在线观看网址| 欧美日韩国产成人| 亚洲成人黄色在线| 欧美裸身视频免费观看| 国产精品福利在线观看| 一区二区在线视频播放| 欧美国产视频日韩| 中日韩美女免费视频网站在线观看| 九九久久精品一区| 国产日韩在线免费| 久久久91精品国产一区不卡| 欧美一级免费看| 一本色道久久88综合亚洲精品ⅰ| 国产日韩欧美夫妻视频在线观看| 爽爽爽爽爽爽爽成人免费观看| 欧美性受xxx| 国产乱人伦真实精品视频| 久久精品国产一区二区电影| 日韩在线中文视频| 色播久久人人爽人人爽人人片视av| 亚洲色图第三页| 成人激情视频免费在线| 97国产真实伦对白精彩视频8| 亚洲在线免费视频| 热久久99这里有精品| 久久91亚洲人成电影网站| 久久精品99国产精品酒店日本| 精品久久久久久中文字幕| 色吧影院999| 亚洲国产成人久久综合| 久久999免费视频| 国产精品久久久久福利| 6080yy精品一区二区三区| 国产ts人妖一区二区三区| 欧美黄网免费在线观看| 中文字幕亚洲在线| 激情懂色av一区av二区av| 亚洲深夜福利在线| 中文字幕亚洲在线| 亚洲高清在线观看| 91人人爽人人爽人人精88v| 在线观看久久久久久| 国产日韩专区在线| 久久精品视频播放| 亚洲国产日韩一区| 色综合色综合久久综合频道88| 日本欧美国产在线| 国产精品白丝av嫩草影院| 日韩网站免费观看| 91久久国产精品| 精品爽片免费看久久| 97在线视频免费看| 国产精品看片资源| 国产精品老女人视频| 俺去了亚洲欧美日韩| 欧美激情免费视频| 国产婷婷色综合av蜜臀av| 在线观看国产精品淫| 欧美激情精品久久久| 精品久久久久久久久久ntr影视| 亚洲女人天堂视频| 久久久久久久国产精品视频| 日韩av免费一区| 国产精品久久久久久五月尺| 欧美日韩成人黄色| 国产一区二区三区三区在线观看| 亚洲欧美精品伊人久久| 亚洲欧洲在线播放| 中文字幕亚洲自拍| 91成人国产在线观看| 亚洲人成在线观看网站高清| 欧美人与性动交| 国产精品视频精品| 亚洲精品97久久| 88国产精品欧美一区二区三区| 欧美激情xxxx| 国产精品久久久久久中文字| 欧美成人全部免费| 国产日韩在线播放| 欧美在线视频在线播放完整版免费观看| 全亚洲最色的网站在线观看| 欧美刺激性大交免费视频| 国产一区二区三区欧美| 91视频国产一区| 欧美日韩午夜剧场| 久色乳综合思思在线视频| 日韩av影视综合网| 久久深夜福利免费观看| 亚洲另类激情图| 国产成人精品999| 国产精品视频免费在线| 黑人巨大精品欧美一区二区免费| 51视频国产精品一区二区| 国产精品欧美日韩久久| 日本韩国在线不卡| 久久久www成人免费精品| 久久亚洲综合国产精品99麻豆精品福利|