1. 程式人生 > >(一)zookeeper單機模式的安裝和使用

(一)zookeeper單機模式的安裝和使用

1、分散式常見問題

  • 容易出現死鎖
  • 容易活鎖,處於活鎖的執行緒都是非阻塞的,而且每個執行緒都搶不到資源,會造成cpu的耗費
  • 叢集的管理問題,比如某臺的宕機需要能夠檢測到
  • 叢集配置檔案的統一管理問題
  • 叢集中資訊更新通知問題,某一臺機器釋出一個資訊,能夠讓整個叢集的機器都知道
  • 管理叢集的選舉問題,管理叢集的機器本身也是一個叢集(例如zookeeper叢集),其中有一臺為主(選舉得到),其他為從。
  • 分散式鎖

2、Zookeeper定義

Zookeeper是一個分散式的協調服務框架,Zookeeper可以解決分散式環境常見的問題:統一命名服務,資訊配置管理,資料一致性,叢集管理,分散式鎖等等。

3、Zookeeper的安裝

  • 下載壓縮包:連結:https://pan.baidu.com/s/1NtffnJ0ttT475KSQqAKcSw  提取碼:0qp5
  • 解壓:tar -xf zookeeper-3.4.7.tar.gz
  • 建立配置檔案:zookeeper的配置檔案是conf/zoo.cfg,conf目錄下有一個配置檔案的樣本zoo_sample.cfg,複製該檔案並修改檔名為zoo.cfg即可
  • 更改配置檔案內容:單機模式配置如下,其中dataDir為儲存快照的目錄,建議修改為自定義目錄
# 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=/opt/zookeeper/tmp
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# 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
#autopurge.purgeInterval=1

4、zookeeper的資料結構

Zookeeper儲存資料的結構是一棵樹,如圖所示:

Zookeeper資料結構的特徵:

  • 有一個根節點 /,對於Zookeeper的操作都要基於根節點
  • 每個節點都叫做Znode節點,都可以建立自己的子節點,都可以儲存資料
  • 整個Znode樹會儲存在記憶體中,提高查詢速度。為了防止資料丟失,同時也會把Znode樹落到磁碟上,磁碟路徑即配置檔案zoo.cfg裡dataDir指定的目錄
  • Znode的路徑是全域性唯一的
  • 建立節點時,需指定初始化資料,否則建立報錯
  • Zookeeper是事務的概念,針對每個事務(建立,更新或刪除節點等),Zookeeper都會分配一個遞增的Zxid(事務id)。其中有cZxid(建立節點的事務id),mZxid(修改節點的事務id)

5、Zookeeper單機模式啟動,檢視,關閉

  • 進入bin目錄,啟動zookeeper:sh  zkServer.sh  start
  • 驗證是否啟動:jps命令檢視活動的java程序

  • 檢視狀態:sh  zkServer.sh  status

  • 停止服務:sh zkServer.sh stop

6、Zookeeper客戶端啟動及操作

小技巧:在客戶端中,使用命令:ctrl + l 清屏。

  • 進入bin目錄,啟動客戶端:sh zkCli.sh
  • 查詢節點 ls /     ls /zookeeper

  • 建立節點:create /node01 hello

建立了節點 node01,並初始化資料為 “hello” 

  • 檢視節點:get /node01

可以看出,當執行命令  create /node01 hello時,這就是一個寫的事務,會分配一個事務id,事務id是一個自增的id。

  • 修改節點資料:set /node01 hellodfr
  • 刪除節點:delete /node01 單個刪除,存在子節點則刪除失敗    rmr /node01 遞迴刪除,

7、zookeeper的節點型別

  • create /park01 "dateStr" 普通持久節點
  • create -e /park01 "dateStr" 普通臨時節點
  • create -s /park01 "dateStr" 順序持久節點 
  • create -e -s /park01 "dateStr" 臨時順序節點 
臨時節點

客戶端連線zookeeper服務並建立臨時節點後,若客戶端掉線,則臨時節點會消失。

該特性可以用來檢測叢集中,有哪些機器掛掉

順序節點

建立順序節點後,會在節點名稱後帶上一個自增的順序id

如建立節點 create -s /park01 ddff,真正建立的節點名稱為 park010000000009

8、通過程式碼操作zookeeper

  • 下載Zookeeper相關jar包:連結:https://pan.baidu.com/s/1ZlEBsshFOr_us44JpMGUpA  提取碼:5v0x
  • 建立Maven的java工程,pom.xml配置如下
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.dfr</groupId>
  <artifactId>zookeeper</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <dependencies>
  	 <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.10</version>     
     </dependency> 
     
   	 <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-simple</artifactId>
         <version>1.6.4</version>
         <scope>compile</scope>
     </dependency> 
      
     <dependency>
	 	 <groupId>org.apache.zookeeper</groupId>
		 <artifactId>zookeeper</artifactId>
	 	 <version>3.4.7</version>
	 </dependency>
		
  </dependencies>
  
  <build>
  </build>
</project>
  • jar包簡單瞭解:工程建立成功後,可以看到依賴的jar包

netty是一個網路通訊的框架,底層是基於NIO來寫的,zookeeper就是通過netty來與其他機器進行網路互動的。

  • Zookeeper的連線,和基本操作
package com.dfr.zookeeper;

import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.junit.Test;

public class TestDemo {
	@Test
	public void testConnect() throws Exception {
		
		
		//連線操作是非同步的(非阻塞連線),如果不做任何處理,可能導致還沒連線成功,testConnect方法執行緒就已經關閉了。
		//這裡使用遞減鎖來處理
		final CountDownLatch cdl = new CountDownLatch(1);
		
		//ip埠,連線超時時間,監聽者
		ZooKeeper zk = new ZooKeeper("39.107.244.148:2181", 3000, new Watcher() {

			@Override
			public void process(WatchedEvent event) {
				if(event.getState() == KeeperState.SyncConnected) {
					System.out.println("連線成功!");
					cdl.countDown();
				} 
			}
			
		});
		//遞減鎖沒減到0則阻塞
		cdl.await();
		
		//建立節點
		//引數:節點,儲存資料,許可權,節點型別
		zk.create("/gtt", "MsGao".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
		
		//修改節點資料
		//引數:節點,儲存資料,資料版本號
		//每更新一次,dataVersion + 1
		zk.setData("/gtt", "gttTWO".getBytes(), 0);
		
		//如果不需要確認當前資料版本,則傳入版本號為-1
		zk.setData("/gtt", "gtt0000".getBytes(), -1);
		
		//刪除資料
		//版本號傳-1,則直接刪除節點
		zk.delete("/gtt", -1);
		
		//獲取資料
		//引數:節點,監聽者,節點的狀態資訊如時間戳等
		byte[] byteDate = zk.getData("/dfr", null, null);
		System.out.println(new String(byteDate));
		
		//獲取子節點
		//引數:節點,監聽者
		List<String> list = zk.getChildren("/", null);
		
		for(String str : list) {
			System.out.println(str);
		}
		
		
	}
}
  • 對節點進行事件監聽

事件型別

程式碼示例如下,注意zookeeper中監聽預設是一次性的。要想永久監聽需要自己處理。

package com.dfr.zookeeper;

import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.junit.Test;

public class TestDemo2 {
	@Test
	public void test() throws Exception {
		
		
		//連線操作是非同步的(非阻塞連線),如果不做任何處理,可能導致還沒連線成功,testConnect方法執行緒就已經關閉了。
		//這裡使用遞減鎖來處理
		final CountDownLatch cdl = new CountDownLatch(1);
		
		//ip埠,連線超時時間,監聽者
		ZooKeeper zk = new ZooKeeper("39.107.244.148:2181", 3000, new Watcher() {

			@Override
			public void process(WatchedEvent event) {
				if(event.getState() == KeeperState.SyncConnected) {
					System.out.println("連線成功!");
					cdl.countDown();
				} 
			}
			
		});
		
		//對節點進行事件監聽,此處以getData方法為例,可以自行選擇監聽事件型別
		
		//zk的預設監聽機制是:一次性監聽
		/*zk.getData("/dfr", new Watcher() {
			
			@Override
			public void process(WatchedEvent event) {
				if(event.getType() == EventType.NodeDataChanged) {
					System.out.println("節點資料改變了!");
				}
			}
		}, null);
		
		while(true);
		*/
		
		//永久監聽
		//監聽事件的型別從EventType中選擇
		for(;;) {
			final CountDownLatch countdl = new CountDownLatch(1);
			
			zk.getData("/dfr", new Watcher() {
				
				@Override
				public void process(WatchedEvent event) {
					if(event.getType() == EventType.NodeDeleted) {
						System.out.println("節點資料刪除了!");
						countdl.countDown();
					}
				}
			}, null);
			
			countdl.await();
		}
		
	}
}