一、什么是Zookeeper
Zookeeper是一個分布式開源框架,提供了協調分布式應用的基本服務,它向外部應用暴露一組通用服務——分布式同步(Distributed Synchronization)、命名服務(Naming Service)、集群維護(Group Maintenance)等,簡化分布式應用協調及其管理的難度,提供高性能的分布式服務。ZooKeeper本身可以以單機模式安裝運行,不過它的長處在於通過分布式ZooKeeper集群(一個Leader,多個Follower),基於一定的策略來保證ZooKeeper集群的穩定性和可用性,從而實現分布式應用的可靠性。
1、zookeeper是為別的分布式程序服務的
2、Zookeeper本身就是一個分布式程序(只要有半數以上節點存活,zk就能正常服務)
3、Zookeeper所提供的服務涵蓋:主從協調、服務器節點動態上下線、統一配置管理、分布式共享鎖、統> 一名稱服務等
4、雖然說可以提供各種服務,但是zookeeper在底層其實只提供了兩個功能:
管理(存儲,讀取)用戶程序提交的數據(類似namenode中存放的metadata);
並為用戶程序提供數據節點監聽服務;
1.1 Zookeeper集群機制
Zookeeper集群的角色: Leader 和 follower
只要集群中有半數以上節點存活,集群就能提供服務
1.2 Zookeeper特性
1、Zookeeper:一個leader,多個follower組成的集群
2、全局數據一致:每個server保存一份相同的數據副本,client無論連接到哪個server,數據都是一致的
3、分布式讀寫,更新請求轉發,由leader實施
4、更新請求順序進行,來自同一個client的更新請求按其發送順序依次執行
5、數據更新原子性,一次數據更新要么成功,要么失敗
6、實時性,在一定時間范圍內,client能讀到最新數據
1.3 Zookeeper數據結構
1、層次化的目錄結構,命名符合常規文件系統規范(類似文件系統)

2、每個節點在zookeeper中叫做znode,並且其有一個唯一的路徑標識
3、節點Znode可以包含數據和子節點(但是EPHEMERAL類型的節點不能有子節點)
節點類型
a、Znode有兩種類型:
短暫(ephemeral)(create -e /app1/test1 “test1” 客戶端斷開連接zk刪除ephemeral類型節點)
持久(persistent) (create -s /app1/test2 “test2” 客戶端斷開連接zk不刪除persistent類型節點)
b、Znode有四種形式的目錄節點(默認是persistent )
PERSISTENT
PERSISTENT_SEQUENTIAL(持久序列/test0000000019 )
EPHEMERAL
EPHEMERAL_SEQUENTIAL
c、創建znode時設置順序標識,znode名稱后會附加一個值,順序號是一個單調遞增的計數器,由父節點維護
d、在分布式系統中,順序號可以被用於為所有的事件進行全局排序,這樣客戶端可以通過順序號推斷事件的順序
二、Zookeeper應用場景
統一命名服務
分布式環境下,經常需要對應用/服務進行統一命名,便於識別不同服務。類似於域名與ip之間對應關系,域名容易記住。通過名稱來獲取資源或服務的地址,提供者等信息按照層次結構組織服務/應用名稱可將服務名稱以及地址信息寫到Zookeeper上,客戶端通過Zookeeper獲取可用服務列表類。
配置管理
分布式環境下,配置文件管理和同步是一個常見問題。一個集群中,所有節點的配置信息是一致的,比如Hadoop。對配置文件修改后,希望能夠快速同步到各個節點上配置管理可交由Zookeeper實現。可將配置信息寫入Zookeeper的一個znode上。各個節點監聽這個znode。一旦znode中的數據被修改,zookeeper將通知各個節點。
集群管理
分布式環境中,實時掌握每個節點的狀態是必要的。可根據節點實時狀態作出一些調整。Zookeeper可將節點信息寫入Zookeeper的一個znode上。監聽這個znode可獲取它的實時狀態變化。典型應用比如Hbase中Master狀態監控與選舉。
分布式通知/協調
分布式環境中,經常存在一個服務需要知道它所管理的子服務的狀態。例如,NameNode須知道各DataNode的狀態,JobTracker須知道各TaskTracker的狀態。心跳檢測機制和信息推送也是可通過Zookeeper實現。
分布式鎖
Zookeeper是強一致的。多個客戶端同時在Zookeeper上創建相同znode,只有一個創建成功。Zookeeper實現鎖的獨占性。多個客戶端同時在Zookeeper上創建相同znode ,創建成功的那個客戶端得到鎖,其他客戶端等待。Zookeeper 控制鎖的時序。各個客戶端在某個znode下創建臨時znode (類型為CreateMode. EPHEMERAL _SEQUENTIAL),這樣,該znode可掌握全局訪問時序。
分布式隊列
兩種隊列。當一個隊列的成員都聚齊時,這個隊列才可用,否則一直等待所有成員到達,這種是同步隊列。隊列按照 FIFO 方式進行入隊和出隊操作,例如實現生產者和消費者模型。(可通過分布式鎖實現)
同步隊列。一個job由多個task組成,只有所有任務完成后,job才運行完成。可為job創建一個/job目錄,然后在該目錄下,為每個完成的task創建一個臨時znode,一旦臨時節點數目達到task總數,則job運行完成。
三、Zookeeper環境搭建
環境要求:必須要有jdk環境,本次講課使用jdk1.8
3.1結構
一共三個節點
(zk服務器集群規模不小於3個節點),要求服務器之間系統時間保持一致。
3.2上傳zk並且解壓
進行解壓: tar -zxvf zookeeper-3.4.6.tar.gz
重命名: mv zookeeper-3.4.6 zookeeper
3.3 修改zookeeper環境變量
vi /etc/profile
export JAVA_HOME=/opt/jdk1.8.0_71
export ZOOKEEPER_HOME=/usr/local/zookeeper
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$JAVA_HOME/bin:$ZOOKEEPER_HOME/bin:$PATH
source /etc/profile
3.4 修改zoo_sample.cfg文件
cd /usr/local/zookeeper/conf
mv zoo_sample.cfg zoo.cfg
修改conf: vi zoo.cfg 修改兩處
(1) dataDir=/usr/local/zookeeper/data(注意同時在zookeeper創建data目錄)
(2)最后面添加
server.0=bhz:2888:3888
server.1=hadoop1:2888:3888
server.2=hadoop2:2888:3888
3.5 創建服務器標識
服務器標識配置:
創建文件夾: mkdir data
創建文件myid並填寫內容為0: vi
myid (內容為服務器標識 : 0)
3.6 復制zookeeper
進行復制zookeeper目錄到hadoop01和hadoop02
還有/etc/profile文件
把hadoop01、 hadoop02中的myid文件里的值修改為1和2
路徑(vi /usr/local/zookeeper/data/myid)
3.7 啟動zookeeper
啟動zookeeper:
路徑: /usr/local/zookeeper/bin
執行: zkServer.sh start
(注意這里3台機器都要進行啟動)
狀態: zkServer.sh
status(在三個節點上檢驗zk的mode,一個leader和倆個follower)
3.8常用命令
zkServer.sh status 查詢狀態
四、Zookeeper配置文件介紹
| # The number of milliseconds of each tick tickTime=2000
# The number of ticks that the initial # synchronization phase can take initLimit=10
# The number of ticks that can pass between # sending a request and getting an acknowledgement syncLimit=5
# the directory where the snapshot is stored. # do not use /tmp for storage, /tmp here is just # example sakes. dataDir=/home/myuser/zooA/data
# the port at which the clients will connect clientPort=2181
# ZooKeeper server and its port no. # ZooKeeper ensemble should know about every other machine in the ensemble # specify server id by creating 'myid' file in the dataDir # use hostname instead of IP address for convenient maintenance server.1=127.0.0.1:2888:3888 server.2=127.0.0.1:2988:3988 server.3=127.0.0.1:2088:3088
# # Be sure to read the maintenance section of the # administrator guide before turning on autopurge. # # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance # # The number of snapshots to retain in dataDir # autopurge.snapRetainCount=3 # Purge task interval in hours # Set to "0" to disable auto purge feature <br> #autopurge.purgeInterval=1 dataLogDir=/home/myuser/zooA/log
|
tickTime:心跳時間,為了確保連接存在的,以毫秒為單位,最小超時時間為兩個心跳時間
initLimit:多少個心跳時間內,允許其他server連接並初始化數據,如果ZooKeeper管理的數據較大,則應相應增大這個值
clientPort:服務的監聽端口
dataDir:用於存放內存數據庫快照的文件夾,同時用於集群的myid文件也存在這個文件夾里(注意:一個配置文件只能包含一個dataDir字樣,即使它被注釋掉了。)
dataLogDir:用於單獨設置transaction log的目錄,transaction log分離可以避免和普通log還有快照的競爭
syncLimit:多少個tickTime內,允許follower同步,如果follower落后太多,則會被丟棄。
server.A=B:C:D:
A是一個數字,表示這個是第幾號服務器,B是這個服務器的ip地址
C第一個端口用來集群成員的信息交換,表示的是這個服務器與集群中的Leader服務器交換信息的端口
D是在leader掛掉時專門用來進行選舉leader所用
五、Zookeeper客戶端
ZooKeeper命令行工具類似於Linux的shell環境,不過功能肯定不及shell啦,但是使用它我們可以簡單的對ZooKeeper進行訪問,數據創建,數據修改等操作. 使用 zkCli.sh -server 127.0.0.1:2181 連接到 ZooKeeper 服務,連接成功后,系統會輸出 ZooKeeper 的相關環境以及配置信息。
命令行工具的一些簡單操作如下:
- 1. 顯示根目錄下、文件: ls / 使用 ls 命令來查看當前 ZooKeeper 中所包含的內容
- 2. 顯示根目錄下、文件: ls2 / 查看當前節點數據並能看到更新次數等數據
- 3. 創建文件,並設置初始內容: create /zk "test" 創建一個新的 znode節點“ zk ”以及與它關聯的字符串
- 4. 獲取文件內容: get /zk 確認 znode 是否包含我們所創建的字符串
- 5. 修改文件內容: set /zk "zkbak" 對 zk 所關聯的字符串進行設置
- 6. 刪除文件: delete /zk 將剛才創建的 znode 刪除
- 7. 退出客戶端: quit
- 8. 幫助命令: help
六、Java操作Zookeeper
6.1 Zookeeper說明
創建節點(znode) 方法:
create:
提供了兩套創建節點的方法,同步和異步創建節點方式。
口
同步方式:
參數1,節點路徑《名稱) : InodeName (不允許遞歸創建節點,也就是說在父節點不存在
的情況下,不允許創建子節點)
參數2,節點內容: 要求類型是字節數組(也就是說,不支持序列化方式,如果需要實現序
列化,可使用java相關序列化框架,如Hessian、Kryo框架)
參數3,節點權限: 使用Ids.OPEN_ACL_UNSAFE開放權限即可。(這個參數一般在權展
沒有太高要求的場景下,沒必要關注)
參數4,節點類型: 創建節點的類型: CreateMode,提供四種首點象型
PERSISTENT(持久節點)
PERSISTENT SEQUENTIAL(持久順序節點)
EPHEMERAL(臨時節點)
EPHEMERAL SEQUENTAL(臨時順序節點)
6.2 maven引入依賴
| <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.6</version> </dependency> |
6.3 Zookeeper客戶端連接
| public class ZookeeperDemo { /** * 集群連接地址 */ private static final String CONNECT_ADDR = "192.168.110.138:2181,192.168.110.147:2181,192.168.110.148:2181"; /** * session超時時間 */ private static final int SESSION_OUTTIME = 2000; /** * 信號量,阻塞程序執行,用戶等待zookeeper連接成功,發送成功信號, */ private static final CountDownLatch countDownLatch = new CountDownLatch(1);
public static void main(String[] args) throws IOException, InterruptedException, KeeperException { ZooKeeper zk = new ZooKeeper(CONNECT_ADDR, SESSION_OUTTIME, new Watcher() {
public void process(WatchedEvent event) { // 獲取時間的狀態 KeeperState keeperState = event.getState(); EventType tventType = event.getType(); // 如果是建立連接 if (KeeperState.SyncConnected == keeperState) { if (EventType.None == tventType) { // 如果建立連接成功,則發送信號量,讓后阻塞程序向下執行 countDownLatch.countDown(); System.out.println("zk 建立連接"); } } }
}); // 進行阻塞 countDownLatch.await(); //創建父節點 //String result = zk.create("/testRott", "12245465".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); //System.out.println("result:" + result); //創建子節點 String result = zk.create("/testRott/children", "children 12245465".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); System.out.println("result:"+result); zk.close(); }
} |
