天天看點

Zookeeper讀寫性能測試

package com.kiven.test;

import java.util.list;

import java.util.concurrent.countdownlatch;

import org.apache.log4j.propertyconfigurator;

import org.apache.zookeeper.createmode;

import org.apache.zookeeper.keeperexception;

import org.apache.zookeeper.watchedevent;

import org.apache.zookeeper.watcher;

import org.apache.zookeeper.watcher.event.keeperstate;

import org.apache.zookeeper.zoodefs.ids;

import org.apache.zookeeper.zookeeper;

public class test{

/**

*/

protected static string hosts = "172.16.217.148:2181";

* 連接配接的逾時時間, 毫秒

private final int session_timeout = 5000;

private countdownlatch connectedsignal = new countdownlatch(1);

protected static zookeeper zk;

private static string nodepath = "/test/test1";

//static string data = "a very long string about data to set to zookeeper";

static int threads = 10;    //線程數

static int runs = 1000;     //疊代次數

static int start = 0;       //none

static int size = 1024*4;   //寫入資料的大小,機關:位元組

static byte[] testdata;     //測試資料

public static void main(string[] args) throws exception {

propertyconfigurator.configure("log4j.properties");

//生成寫入的資料,大小size位元組

testdata = new byte[size];

for(int i=0;i<size;i++){

testdata[i] = 'a';

}

//連接配接

test.connect();

workerstat[] statarray = new workerstat[threads];

thread[] threadarray = new thread[threads];

workerstat mainstat = new workerstat();

mainstat.runs = runs * threads;

long begin = system.currenttimemillis();

for (int i = 0; i < threads; i++) {

statarray[i] = new workerstat();

statarray[i].start = start + i * runs;

statarray[i].runs = runs;

threadarray[i] = new setterthread(statarray[i]);

threadarray[i].start();

threadarray[i].join();

mainstat.settertime = system.currenttimemillis() - begin;

begin = system.currenttimemillis();

threadarray[i] = new getterthread(statarray[i]);

mainstat.gettertime = system.currenttimemillis() - begin;

workerstat totalstat = new workerstat();

system.out.println("test over!!");

system.out.println("thread("+threads+")\truns\tset time(ms)\tget time(ms)");

totalstat.runs = totalstat.runs + statarray[i].runs;

totalstat.settertime = totalstat.settertime + statarray[i].settertime;

totalstat.gettertime = totalstat.gettertime + statarray[i].gettertime;

system.out.println("total\t\t" + totalstat.runs + "\t"+ totalstat.settertime + "\t\t" + totalstat.gettertime);

system.out.println("avg\t\t" + runs + "\t" + totalstat.settertime/ threads + "\t\t" + totalstat.gettertime / threads);

system.out.println("tps\t\t\t" + 1000 * totalstat.runs/ totalstat.settertime + "\t\t" + 1000 * totalstat.runs/ totalstat.gettertime);

system.out.println("\nmain\t\t" + mainstat.runs + "\t"+ mainstat.settertime + "\t\t" + mainstat.gettertime);

system.out.println("tps\t\t" + 1000 * mainstat.runs/ mainstat.settertime + "\t\t" + 1000 * mainstat.runs/ mainstat.gettertime);

private static class workerstat {

public int start, runs;

public long settertime, gettertime;

public workerstat() {

start = runs = 0;

settertime = gettertime = 0;

private static class setterthread extends thread {

private workerstat stat;

setterthread(workerstat stat) {

this.stat = stat;

public void run() {

for (int i = stat.start; i < stat.start + stat.runs; i++) {

//寫入節點資料

try {

zk.setdata(nodepath, testdata, -1);

} catch (exception e) {

e.printstacktrace();

long end = system.currenttimemillis();

stat.settertime = end - begin;

private static class getterthread extends thread {

getterthread(workerstat stat) {

//讀取節點資料

zk.getdata(nodepath, false, null);

stat.gettertime = end - begin;

//===============================================================================

* 連接配接zookeeper server

public void connect() throws exception {

zk = new zookeeper(hosts, session_timeout, new connwatcher());

// 等待連接配接完成

connectedsignal.await();

*

* @author kiven

public class connwatcher implements watcher{

public void process(watchedevent event) {

// 連接配接建立, 回調process接口時, 其event.getstate()為keeperstate.syncconnected

if (event.getstate() == keeperstate.syncconnected) {

// 放開閘門, wait在connect方法上的線程将被喚醒

connectedsignal.countdown();

以下為各個參數的詳細說明:

path. znode的路徑.

data. 與znode關聯的資料.

acl. 指定權限資訊, 如果不想指定權限, 可以傳入ids.open_acl_unsafe.

指定znode類型. createmode是一個枚舉類, 從中選擇一個成員傳入即可.

* 建立持久化節點

public void create(string path, byte[] data) throws exception {

zk.create(path, data, ids.open_acl_unsafe, createmode.persistent);

system.out.println("建立節點:"+path);

system.out.println("=================");

*擷取節點資訊

*@author kiven

*@createdate 2013-01-16 15:17:22

*@param path

*@throws keeperexception

*@throws interruptedexception

public void getchild(string path) throws keeperexception, interruptedexception{

try{

list list=zk.getchildren(path, false);

if(list.isempty()){

system.out.println(path+"中沒有節點");

}else{

system.out.println(path+"中存在節點");

for(string child:list){

system.out.println("節點為:"+child);

}catch (keeperexception.nonodeexception e) {

* 設定節點資料

* @throws exception

public void setdata(string path,string data) throws exception{

zk.setdata(path, data.getbytes(), -1);

system.out.println("set data:"+"testsetdata");

* 讀取節點資料

public void getdata() throws exception{

system.out.println("get data:");

* 删除節點

* @param path

public void delete(string path) throws exception{

system.out.println("删除節點:"+path);

//如果版本号與znode的版本号不一緻,将無法删除,是一種樂觀加鎖機制;如果将版本号設定為-1,不會去檢測版本,直接删除;

zk.delete(path, -1);

* 關閉連接配接

public void close() {

zk.close();

} catch (interruptedexception e) {

  相關功能代碼中都已經注釋清楚。我們看一下測試下來的結果: 寫入資料: 

Zookeeper讀寫性能測試

  讀取資料:

Zookeeper讀寫性能測試

  由上兩張圖我們可以得知:

  1、寫入(set)資料時,單個線程執行是最快的,而讀取(get)資料則是4或5個線程并發是最快的。

  2、每個節點存儲的資料不能超過1m(在zookeeper預設配置的情況下,如果寫入的資料為1m會報錯,無法寫入資料,是以所有應用寫入的資料必須<1m)

  3、單個寫入資料的體積越大,處理速度越慢,響應時間越長。

  4、會管應用中寫入的資料最大的是16方畫面合成的時候,此時寫入的資料可能大于4k,另外16方畫面合成時候zk節點存放的資料(json)是包含大量空格和換行的(在zk節點中,空格和換行也是占大小的),是以建議壓縮json資料。

  5、測試過程中産生的log檔案對磁盤的消耗和占用較大,建議定時删除曆史log和shapshot

最新内容請見作者的github頁:http://qaseven.github.io/