使用.net實現ZooKeeper客戶端


最近在項目中用到ZooKeeper, 通過Java連接比較容易,.net項目就沒那么容易,尤其對於不熟悉Linux的開發人員,這里寫點搭建ZooKeeper測試環境的經驗,供參考。

背景知識:

Zookeeper的優點和用途就不再贅述,但是關於ZooKeeper的特點和原理還是要清楚,可以參考官方文檔:http://zookeeper.apache.org/doc/trunk/zookeeperOver.html

環境准備:

系統:對於ZooKeeper等等開源類的服務端軟件,運行環境通常都推薦Linux,所以,建議使用虛擬機安裝Linux系統,本文中使用VirtualBox 運行Ubuntu 14.04 ,並且需要安裝和配置好JDK。編譯ZooKeeperNet 需要在Windows下進行,使用VisualStudio。

虛機網絡:通常使用NAT 連接外網,使用網橋進行主機與虛間進行交互。由於公司的網絡有特殊限制,所以,我在筆記本上,使用了網橋橋接了筆記本的無線網卡,使用NAT連接有線網卡。由於主機上網也要通過公司的代理,所以也要在Ubuntu中設置相應的代理實現網絡訪問。

1. Ubuntu中安裝ZooKeeper

  1)下載

    http://mirror.bit.edu.cn/apache/zookeeper/  

    下載3.4.8  得到文件:zookeeper-3.4.8.tar.gz

      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服務的調用。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM