最近在項目中用到ZooKeeper, 經過Java鏈接比較容易,.net項目就沒那麼容易,尤爲對於不熟悉Linux的開發人員,這裏寫點搭建ZooKeeper測試環境的經驗,供參考。html
背景知識:java
Zookeeper的優勢和用途就再也不贅述,可是關於ZooKeeper的特色和原理仍是要清楚,能夠參考官方文檔:http://zookeeper.apache.org/doc/trunk/zookeeperOver.htmlnode
環境準備:git
系統:對於ZooKeeper等等開源類的服務端軟件,運行環境一般都推薦Linux,因此,建議使用虛擬機安裝Linux系統,本文中使用VirtualBox 運行Ubuntu 14.04 ,而且須要安裝和配置好JDK。編譯ZooKeeperNet 須要在Windows下進行,使用VisualStudio。github
虛機網絡:一般使用NAT 鏈接外網,使用網橋進行主機與虛間進行交互。因爲公司的網絡有特殊限制,因此,我在筆記本上,使用了網橋橋接了筆記本的無線網卡,使用NAT鏈接有線網卡。因爲主機上網也要經過公司的代理,因此也要在Ubuntu中設置相應的代理實現網絡訪問。web
1. Ubuntu中安裝ZooKeeperapache
1)下載vim
http://mirror.bit.edu.cn/apache/zookeeper/ api
下載3.4.8 獲得文件:zookeeper-3.4.8.tar.gzbash
2)在Ubuntu中解壓文件:
tar -zxvf zookeeper-3.4.8.tar.gz
3)初始化zookeeper 配置文件:
zookeeper 默認包含了配置文件,在 zookeeper-3.4.8/conf 目錄中,文件名是zoo_sample.cfg, 咱們須要的是zoo.cfg文件來運行zookeeper服務,因此,最簡單的辦法就是複製這個文件便可。
cp zoo_sample.cfg zoo.cfg
4)運行 zookeeper 服務:
#切換至zookeeper的bin目錄 rqing@rqing-VirtualBox:~/shared/tools/zookeeper-3.4.8/bin$ ls README.txt zkCli.cmd zkEnv.cmd zkServer.cmd zookeeper.out zkCleanup.sh zkCli.sh zkEnv.sh zkServer.sh #運行 zkServer.sh 啓動服務 rqing@rqing-VirtualBox:~/shared/tools/zookeeper-3.4.8/bin$ ./zkServer.sh start ZooKeeper JMX enabled by default Using config: /home/rqing/shared/tools/zookeeper-3.4.8/bin/../conf/zoo.cfg Starting zookeeper ... STARTED
5)運行zookeeper 客戶端進行驗證
#運行 zkCli.sh 啓動客戶端 rqing@rqing-VirtualBox:~/shared/tools/zookeeper-3.4.8/bin$ ./zkCli.sh Connecting to localhost:2181 2016-05-26 11:29:24,943 [myid:] - INFO [main:Environment@100] - Client environment:zookeeper.version=3.4.8--1, built on 02/06/2016 03:18 GMT 2016-05-26 11:29:24,962 [myid:] - INFO [main:Environment@100] - Client environment:host.name=rqing-VirtualBox 2016-05-26 11:29:24,962 [myid:] - INFO [main:Environment@100] - Client environment:java.version=1.8.0_91 2016-05-26 11:29:24,976 [myid:] - INFO [main:Environment@100] - Client environment:java.vendor=Oracle Corporation 2016-05-26 11:29:24,976 [myid:] - INFO [main:Environment@100] - Client environment:java.home=/media/sf_Shared/tools/jdk1.8.0_91/jre 2016-05-26 11:29:24,976 [myid:] - INFO [main:Environment@100] - Client environment:java.class.path=/home/rqing/shared/tools/zookeeper-3.4.8/bin/../build/classes:/home/rqing/shared/tools/zookeeper-3.4.8/bin/../build/lib/*.jar:/home/rqing/shared/tools/zookeeper-3.4.8/bin/../lib/slf4j-log4j12-1.6.1.jar:/home/rqing/shared/tools/zookeeper-3.4.8/bin/../lib/slf4j-api-1.6.1.jar:/home/rqing/shared/tools/zookeeper-3.4.8/bin/../lib/netty-3.7.0.Final.jar:/home/rqing/shared/tools/zookeeper-3.4.8/bin/../lib/log4j-1.2.16.jar:/home/rqing/shared/tools/zookeeper-3.4.8/bin/../lib/jline-0.9.94.jar:/home/rqing/shared/tools/zookeeper-3.4.8/bin/../zookeeper-3.4.8.jar:/home/rqing/shared/tools/zookeeper-3.4.8/bin/../src/java/lib/*.jar:/home/rqing/shared/tools/zookeeper-3.4.8/bin/../conf: 2016-05-26 11:29:24,976 [myid:] - INFO [main:Environment@100] - Client environment:java.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib 2016-05-26 11:29:24,977 [myid:] - INFO [main:Environment@100] - Client environment:java.io.tmpdir=/tmp 2016-05-26 11:29:24,977 [myid:] - INFO [main:Environment@100] - Client environment:java.compiler=<NA> 2016-05-26 11:29:24,977 [myid:] - INFO [main:Environment@100] - Client environment:os.name=Linux 2016-05-26 11:29:24,977 [myid:] - INFO [main:Environment@100] - Client environment:os.arch=amd64 2016-05-26 11:29:24,977 [myid:] - INFO [main:Environment@100] - Client environment:os.version=3.13.0-85-generic 2016-05-26 11:29:24,977 [myid:] - INFO [main:Environment@100] - Client environment:user.name=rqing 2016-05-26 11:29:24,977 [myid:] - INFO [main:Environment@100] - Client environment:user.home=/home/rqing 2016-05-26 11:29:24,977 [myid:] - INFO [main:Environment@100] - Client environment:user.dir=/media/sf_Shared/tools/zookeeper-3.4.8/bin 2016-05-26 11:29:24,986 [myid:] - INFO [main:ZooKeeper@438] - Initiating client connection, connectString=localhost:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@506c589e Welcome to ZooKeeper! 2016-05-26 11:29:25,244 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@1032] - Opening socket connection to server localhost/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error) JLine support is enabled 2016-05-26 11:29:25,577 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@876] - Socket connection established to localhost/127.0.0.1:2181, initiating session 2016-05-26 11:29:25,778 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@1299] - Session establishment complete on server localhost/127.0.0.1:2181, sessionid = 0x154e80a09410000, negotiated timeout = 30000 WATCHER:: WatchedEvent state:SyncConnected type:None path:null #運行 ls 命令查看zookeeper 節點 [zk: localhost:2181(CONNECTED) 0] ls / [zookeeper]
到這裏,zookeeper 的測試環境就已經搭建好了
更多操做,參見:http://zookeeper.apache.org/doc/trunk/zookeeperStarted.html
2. 編譯ZooKeeperNet
1)下載源代碼:
地址:https://github.com/ExactTargetDev/zookeeper/tree/et-develop
dotnet代碼在解壓後目錄的 zookeeper-et-develop\src\dotnet 下
直接使用VisualStudio編譯項目會報缺乏依賴的錯誤。
建議把下載後的文件放到主機與虛機的共享目錄中,便於後面使用ant下載依賴。
2)使用ant 下載依賴項, 在Ubuntu上操做
a. 下載並安裝ant: 下載地址:apache-ant-1.9.7-bin.tar.gz
b. 配置環境變量,修改 ~/.bashrc
$ vim ~/.bashrc 添加以下環境變量: ANT_HOME=~/shared/tools/apache-ant-1.9.7 export $ANT_HOME PATH=$ANT_HOME/bin:$PATH
c. 切換到 zookeeper-et-develop 目錄下,運行ant命令
$ ant
ant 命令會根據目錄中build.xml的配置執行依賴項下載,build.xml文件在zookeeper-et-develop目錄下。 可是,這時,構建會失敗,但並不影響,只要依賴項正常下載就夠了。
3)使用VisualStudio編譯項目ZooKeeperNet 。這時編譯便可成功。
3 編寫測試程序
上面編譯好了ZooKeeperNet,咱們就可使用了,建議引用項目而不是隻引用編譯好的dll,這樣更便於調試。
創建測試項目,個人習慣是編寫一個WinForm程序來作測試。
下面列出關鍵代碼:
1) 創建Watcher類:
class zkWatcher : IWatcher { public delegate void NodeChangeCallBack(string path); public delegate void ConnStateChangeCallBack(KeeperState state); public NodeChangeCallBack cbNodeChange; public ConnStateChangeCallBack cbConnection; /// <summary> /// 自定義構造函數以傳遞委託 /// </summary> /// <param name="cbConn">鏈接狀態回調</param> /// <param name="cbNode">節點變動回調</param> public zkWatcher(ConnStateChangeCallBack cbConn,NodeChangeCallBack cbNode) { this.cbConnection = cbConn; this.cbNodeChange = cbNode; } public void Process(WatchedEvent e) { if (e.Type == EventType.None) { this.cbConnection(e.State); } else if (e.Type == EventType.NodeDataChanged) { this.cbNodeChange(e.Path); } } }
2 窗體類
public partial class Form1 : Form { private ZooKeeper _zk; private string _defaultServer = "10.130.201.47:2181"; //默認服務地址,實爲Ubuntu中運行的zookeeper服務的地址。 public Form1() { InitializeComponent(); toolStripStatusLabel1.Text = "Not Connected"; this.tbServerAddr.Text = _defaultServer; } /// <summary> /// 創建鏈接 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { string zkConn = this.tbServerAddr.Text; try { zkWatcher w = new zkWatcher(ConnectionCallBack, NodeChangeCallBack); this._zk = new ZooKeeper(zkConn, new TimeSpan(0, 0, 0, 50000), w); //次操做爲異步的,須要經過Watcher獲取鏈接狀態 } catch (Exception ex) { MessageBox.Show("創建鏈接失敗!"); } } private void btnCreate_Click(object sender, EventArgs e) { //未實現 } /// <summary> /// 獲取節點,前提爲鏈接已經成功 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnGet_Click(object sender, EventArgs e) { try { StringBuilder sb = new StringBuilder(); string node = tbNode.Text; var stat = _zk.Exists(node, false); //是否存在 var data = _zk.GetData(node, false, stat); //獲取數據,若是沒有數據,會返回null //輸出節點值 sb.AppendLine("Value:"); if (data != null) { string value = System.Text.Encoding.Default.GetString(data); sb.AppendLine(value); } //輸出節點的子節點名 var childList = _zk.GetChildren(node, null); //獲取子節點 sb.AppendLine("Children:"); foreach (string child in childList) { sb.AppendLine(child); } tbResult.Text = sb.ToString(); //輸出節點值及自節點名 } catch (Exception ex) { //當鏈接狀態不爲已鏈接時,會觸發異常。 } } private void NodeChangeCallBack(string path) { //未實現 } /// <summary> /// 處理鏈接狀態變動 /// </summary> /// <param name="state"></param> private void ConnectionCallBack(KeeperState state) { this.toolStripStatusLabel1.Text = state.ToString(); } }
上面是節點查詢的實現,實際效果以下
以上經過ZooKeeperNet,實現了.Net對ZooKeeper服務的調用。