论坛首页 Java企业应用论坛

开发了一个高性能memcached java client

浏览 24358 次
该帖已经被评为良好帖
作者 正文
   发表时间:2008-10-22  
问题已经确定,在解析命令响应的时候使用了mina提供的TextLineDecoder,这东东可以把一个IoBuffer分成多个指定间隔符的字符串数组,而使用Serializable序列化的byte数组有些认为是特殊字符,无法识别成字符串。

多谢帮我发现问题,呵呵,所以说开源就是好!

不过我的初衷是觉得java自带的序列化/反序列化效率太低了,所以希望能够自己实现。不管怎么样,我使用TextLineDecoder还是太偷懒了,呵呵,回头改一下。

0 请登录后投票
   发表时间:2008-10-22  
其实JDK还提供了另一个接口Externalizable,相比使用Serializable的性能应该有提高。不知道对你有没有什么帮助
0 请登录后投票
   发表时间:2008-10-22  
Externalizable以前用过,比serialize快得多,但是比较麻烦,会要求每个结构都去实现这个接口,如果消息种类太多,那么开发工作量会比较大。不利于上层应用开发。

其实对于我这个框架来说,不关心是怎么进行序列化/反序列化的,我暴露byte[]出来,如果你关心效率,那么你可以用Externalizable或者hessian的序列化/反序列化,如果你不关心,那么就可以用serialize或者json,总之这属于接口友好性的领域。对项目本身影响不大。
0 请登录后投票
   发表时间:2008-10-22  
liuye 写道
uniseraph 写道
liuye 写道

get/set只能对字符串/字节操作,Object怎么办?另外,是不是没有考虑连接多个memcached服务器呀?


有数据了,再进行序列化和反序列化是很简单的。后续会包装一些接口。

连接多个服务器也是准备后续再做的,以现在的结构而言,支持起来很简单。

现在我正在考虑把单位时间内的多个get合并成一个gets操作,这样对系统性能提升应该有更大的帮助。


根据你的set/get写了read/write方法,对Object进行读写,write方法好像正常,但read方法在运行GetReponse rsp = (GetReponse) pool.send(command, true)时出错。代码如下:

	public Object read(String key) {

		GetCommand command = new GetCommand();

		command.setValue(key);

		GetReponse rsp = (GetReponse) pool.send(command, true);

		if (rsp != null && rsp.isSuccess()) {
			byte[] result = rsp.getResult();
			try {
				return bytes2Object(result);
			} catch (Exception e) {
				log.error(e.getMessage());
				e.printStackTrace();
			}

		}
		return null;
	}

	public void write(String key, Serializable value) {
		byte[] bytes = null;
		try {
			bytes = object2Bytes(value);
		} catch (Exception e) {
			log.error(e.getMessage());
			e.printStackTrace();
		}
		if (bytes != null) {
			SetCommand setCommand = new SetCommand();
			setCommand.setKey(key);
			setCommand.setValue(bytes);
			SetReponse rsp = (SetReponse) pool.send(setCommand, true);
			if (rsp != null && rsp.isSuccess()) {
			}
		}
	}

	public static Object bytes2Object(byte[] objBytes) throws Exception {
		if (objBytes == null || objBytes.length == 0) {
			return null;
		}
		ByteArrayInputStream bi = new ByteArrayInputStream(objBytes);
		ObjectInputStream oi = new ObjectInputStream(bi);
		return oi.readObject();
	}

	public static byte[] object2Bytes(Serializable obj) throws Exception {
		if (obj == null) {
			return null;
		}
		ByteArrayOutputStream bo = new ByteArrayOutputStream();
		ObjectOutputStream oo = new ObjectOutputStream(bo);
		oo.writeObject(obj);
		return bo.toByteArray();
	}





问题已经解决,主要是新增加了一个基于IoBuffer的协议解析器NormalReponseDecoder,取消了原来基于TextLineDecoder的LinedReponseDecoder。到现在为止已经有三种协议解析方法了,回头再做个测试,比较一下三个的区别。


代码已经提交到https://commons-client.googlecode.com/svn/branches/0.1.1 ,暂时不提主干,稳定以后再说。

测试代码如下:
public class Test {

	/**
	 * @param args
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException {
		ByteArrayOutputStream bo = new ByteArrayOutputStream();
		ObjectOutputStream oo = new ObjectOutputStream(bo);
		oo.writeObject(new Example(1, "hello"));
		byte[]  buffer = bo.toByteArray();
		
		MemcachedClient  mc = new MemcachedClient("10.2.224.34",11211,2);
		 mc.set("aaa", buffer);
		 byte[] result = mc.get("aaa" );
		 
		 boolean b = Arrays.equals(buffer, result);
		System.out.println(b);
		 
	}

	private static class Example implements Serializable {
		private int age;
		private String desc;

		public Example(int age, String desc) {
			super();
			this.age = age;
			this.desc = desc;
		}

	}
}

0 请登录后投票
   发表时间:2008-10-23  
贴一下测试代码:
public static void  main(String[] args){
//....
	MemcachedClient mc = new MemcachedClient(ip, port, size);

		CountDownLatch cdl = new CountDownLatch(thread);
		long t = System.currentTimeMillis();
		for (int i = 0; i < thread; i++) {
			new Thread(new TestRunnable(mc, i * 10000, cdl, repeat)).start();
		}

		try {
			cdl.await();
		} catch (InterruptedException e) {

		}

		long all = 2 * thread * repeat;
		long usingtime = (System.currentTimeMillis() - t);
		log
				.info(String
						.format(
								"thread num=%d, repeat=%d,size=%d, all=%d ,velocity=%d , using time:%d",
								thread, repeat, size, all, 1000 * all
										/ usingtime, usingtime));

		mc.pool.close();
}


static private class TestRunnable implements Runnable {

		private MemcachedClient mc;
		private CountDownLatch cd;
		int repeat;
		int start;

		public TestRunnable(MemcachedClient mc, int start, CountDownLatch cdl,
				int repeat) {
			super();
			this.mc = mc;
			this.start = start;
			this.cd = cdl;
			this.repeat = repeat;

		}

		public void run() {

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

				String key = Integer.toString(i);
				mc.set(key, key.getBytes());
				byte[] value = mc.get(key);
				if (log.isInfoEnabled()) {
					String result = new String(value);
					if (!result.equals(key)) {
						log.info(String
								.format("key:%s->result:%s", key, result));
						throw new IllegalStateException();
					}
				}

			}

			cd.countDown();
			// if (log.isDebugEnabled())
			// log.debug(String.format("%s count down", Thread.currentThread()
			// .getName()));
		}

	}



基本算法是:启动100个线程,每个线程循环10000次,每次发送两个操作,一个set一个get。100个线程全部退出,则记时结束。
0 请登录后投票
   发表时间:2008-10-27  
鼓励一下,之前我也尝试做过。
不过一个开源软件要取得成功,需要投入很多时间。还需要一些运作,和商业软件一样。
0 请登录后投票
   发表时间:2008-10-27  
这个项目值得研究,我想稳定之后,将来应该是一个趋势了,理论很简单,就是内存越大,机器越快,期望能有更大的发展空间!
0 请登录后投票
   发表时间:2008-10-28  
uniseraph 写道
liuye 写道

get/set只能对字符串/字节操作,Object怎么办?另外,是不是没有考虑连接多个memcached服务器呀?


有数据了,再进行序列化和反序列化是很简单的。后续会包装一些接口。

连接多个服务器也是准备后续再做的,以现在的结构而言,支持起来很简单。

现在我正在考虑把单位时间内的多个get合并成一个gets操作,这样对系统性能提升应该有更大的帮助。



应该优先实现“连接多个memcached服务器”
0 请登录后投票
   发表时间:2009-01-31  
简单看了一下源码,给后来要的朋友提醒:使用了jdk6里面String的str.getBytes(charset)方法,jdk5支持不了(我下载了jdk6后再看看)。顺便说一下,mina使用的是2.0版本。
不知道楼主可不可以改一下源码让JDK5也可以支持?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics