- 浏览: 26831 次
-
最近访客 更多访客>>
最新评论
-
davexin:
codeutil 写道
昨天听同学说他的memecache用的 ...
memcached java下性能测试报告、分析与问题讨论 -
MiMiEye:
<br/><strong>timely ...
memcached java下性能测试报告、分析与问题讨论 -
iunknown:
alin_ass 写道不是很喜欢memcache java c ...
memcached java下性能测试报告、分析与问题讨论 -
zzeric:
用memcached做集中session处理,是否容易造成单点 ...
memcached java下性能测试报告、分析与问题讨论 -
codeutil:
qq新做的网站:http://city.qzone.qq.co ...
memcached java下性能测试报告、分析与问题讨论
我的项目原来使用静态HashMap来实现Key->Object的缓存,并且实现脏数据刷新.由于项目要改成集群部署.在单个jvm里运行的静态Hash结构已经无法处理脏数据问题.所以准备使用memcached做分布式缓存来解决.
从网上搜索到的资料来看 memcached能够接受较大量的请求.但其javaclient 由于大量使用同步语句、hashmap,读取流没有使用bufferedStream。造成性能并不好
为此在我的项目里我参考memcached的协议,自己实现一个客户端功能。经过测试后发现一些问题。
测试环境1:
windows xp home
迅驰T2250
1G内存
jdk1.5
server: memcached-1.2.1 nt版本
client: 自己编写
用于传输的pojo 40个属性,序列化后为750个byte
测试client与server同台机器
测试方法
填充测试时填充10w个pojo。创建100个任务,每任务负责向memcached存储1000个pojo。
读取测试时读取10000个pojo 创建100个任务,每任务读取100个pojo。
平均值均按照线程内取平均值后,各线程再取平均值。
在进行上述测试的时候 cpu占用均在90%-100%,根据上述测试结果,开2个线程时效率最高。
thread count | write avg/per obj | write totall | read avg/per obj | read total |
10 | 2.404991 ms | 29s | 1.709544 ms | 2s |
5 | 0.704780 ms | 18s | 1.333013 ms | 2s |
2 | 0.262194 ms | 15s | 0.414683 ms | 2s |
测试环境2:
AIX5.2
IBM P650 Power4 1.5G(64bit) *4
内存8G
jdk1.4
memcached-1.2.1
libevnet1.1b
client自己编写
用于传输的pojo 40个属性,序列化后为750个byte
测试client与server同台机器
相同的测试方法。测试结果大跌眼睛 10线程时 读写速度为200ms/per object 比我的笔记本慢100倍。就没继续测试
测试环境3:
windows2000 server
xeon 1.5*4
内存8G
jdk1.5
测试时发现cpu占用不高于20%
thread count | write avg/per obj | write total | read avg/per obj | read total |
20 | 10.266615ns | 71s | 23.21283ns | 15s |
10 | 4.341574ns | 41s | 13.30084ns | 16s |
5 | 1.298717ns | 25s | 9.33258ns | 18s |
2 | 1.298717ns | 21s | 4.02503ns | 23s |
初步测试到这里 发现的问题
1.是暂时没有达到网上宣传的1.5w个对象/s (目前测试cpu为瓶颈)
2.是aix下效率低的可怕,对aix不太熟悉。应该有些设置的参数,这点还要向大家请教。
3.超过2个线程效率就开始低。没有发挥多线程的优势,不知道大家在使用过程中有没有发现这一点,还是说我写的MemBufferedDriver有问题。
我的期望是读写速度均能稳定在0.1毫秒左右,至少 1w obj/s 这样才有可能不影响到现有系统的效率
另外大家在java下使用memcached的时候效率怎么样都是怎么用的呢
下面贴下我的client的实现
memcached的协议可以参考memcache包的doc/protocol.txt
主要是socket初次打开后不关闭,直接存放到ThreadLocal中,与memcached保持一个长练接。每次使用的时候判断连接可用还是需要重新连接。
其他存储和读取实现memcached协议。使用BufferedStream。
序列化采用实现Serializable,直接使用ObjectStream来实现。(由于都是pojo简单数据对象,尝试过实现Externalizable接口自己实现序列化和使用750个byte的String 来序列化,发现性能相差不多故放弃)
MemBufferedDriver 为client实现
- public class MemBufferedDriver {
- /**
- * 存放 连到cacheserver的socket连接
- */
- private final static ThreadLocal sockPool = new ThreadLocal();
- private static String serverAddress = "localhost:11211";
- public static final byte[] BYTE_GET = new byte[]{103, 101, 116, 32};
- public static final byte[] BYTE_SET = new byte[]{115, 101, 116, 32};
- public static final byte[] BYTE_DELETE = new byte[]{100, 101, 108, 101, 116, 101, 32};
- public static final byte[] BYTE_CRLF = new byte[]{13, 10};
- public static final byte[] BYTE_SPACE = new byte[]{32};
- public static final String SERVER_STATUS_DELETED = "DELETED";
- public static final String SERVER_STATUS_NOT_FOUND = "NOT_FOUND";
- public static final String SERVER_STATUS_STORED = "STORED";
- public static final String SERVER_STATUS_ERROR = "ERROR";
- public static final String SERVER_STATUS_END = "END";
- public static final String SERVER_STATUS_VALUE = "VALUE";
- public static final String ENCODING_TYPE = "UTF-8";
- public static Socket getSocket() throws UnknownHostException, IOException {
- Socket s = (Socket) MemBufferedDriver.sockPool.get();
- if (s == null || s.isClosed()) {
- s = MemBufferedDriver.reconnect();
- MemBufferedDriver.sockPool.set(s);
- }
- return s;
- }
- private static Socket reconnect() throws UnknownHostException, IOException {
- String[] ip = MemBufferedDriver.serverAddress.split(":");
- return new Socket(ip[0], Integer.parseInt(ip[1]));
- }
- public Map getMulti(String[] keys) {
- Map map = new HashMap();
- if (keys == null || keys.length <= 0) return map;
- for (int i = 0; i < keys.length; i++) {
- Object o = get(keys[i]);
- if (o != null) map.put(keys[i], o);
- }
- return map;
- }
- public Object[] getMultiArray(String[] keys) {
- if (keys == null || keys.length <= 0) return null;
- Object[] o = new Object[keys.length];
- for (int i = 0; i < keys.length; i++)
- o[i] = get(keys[i]);
- return o;
- }
- public boolean set(String key, Object obj) {
- try {
- if (obj == null || key == null || "".equals(key)) throw new Exception("对象和key 不能为空");
- Socket s = MemBufferedDriver.getSocket();
- BufferedInputStream in = new BufferedInputStream(s.getInputStream());
- BufferedOutputStream out = new BufferedOutputStream(s.getOutputStream());
- key = encodeKey(key);
- int flag = 0;
- //序列化对象
- byte[] bs = object2Byte(obj);
- out.write(MemBufferedDriver.BYTE_SET); //write cmd
- out.write(key.getBytes()); //write key
- out.write(MemBufferedDriver.BYTE_SPACE);
- out.write(String.valueOf(flag).getBytes()); //write flag
- out.write(MemBufferedDriver.BYTE_SPACE);
- out.write("0".getBytes()); //write expire date
- out.write(MemBufferedDriver.BYTE_SPACE);
- out.write(String.valueOf(bs.length).getBytes()); //object length
- out.write(MemBufferedDriver.BYTE_CRLF);
- out.write(bs);
- out.write(MemBufferedDriver.BYTE_CRLF);
- out.flush();
- String ret = readLine(in);
- return MemBufferedDriver.SERVER_STATUS_STORED.equals(ret);
- } catch (Exception e) {
- System.out.println(e.getMessage());
- return false;
- }
- }
- public Object get(String key) {
- try {
- Socket s = MemBufferedDriver.getSocket();
- InputStream in = s.getInputStream();
- OutputStream out = s.getOutputStream();
- key = encodeKey(key);
- out.write(MemBufferedDriver.BYTE_GET);
- out.write(key.getBytes());
- out.write(MemBufferedDriver.BYTE_CRLF);
- out.flush();
- return getObjectFromStream(in, out);
- } catch (Exception e) {
- System.out.println(e.getMessage());
- return null;
- }
- }
- public boolean delete(String key) {
- try {
- Socket s = MemBufferedDriver.getSocket();
- InputStream in = s.getInputStream();
- OutputStream out = s.getOutputStream();
- key = encodeKey(key);
- out.write(MemBufferedDriver.BYTE_DELETE);
- out.write(key.getBytes());
- out.write(MemBufferedDriver.BYTE_CRLF);
- out.flush();
- String ret = readLine(in);
- return MemBufferedDriver.SERVER_STATUS_DELETED.equals(ret) || MemBufferedDriver.SERVER_STATUS_NOT_FOUND.equals(ret);
- } catch (Exception e) {
- return false;
- }
- }
- private Object getObjectFromStream(InputStream in, OutputStream out) throws IOException, ClassNotFoundException {
- String cmd = readLine(in);
- if (cmd.startsWith(MemBufferedDriver.SERVER_STATUS_VALUE)) {
- //return object
- String[] part = cmd.split(" ");
- String para = part[2];
- int length = Integer.parseInt(part[3]);
- byte[] bs = new byte[length];
- int count = 0;
- while (count < bs.length) count += in.read(bs, count, (bs.length - count));
- if (count != bs.length)
- throw new IOException("读取数据长度错误");
- readLine(in);
- String endstr = readLine(in);
- if (MemBufferedDriver.SERVER_STATUS_END.equals(endstr))
- return this.byte2Object(bs);
- else
- System.out.println("结束标记错误");
- }
- return null;
- }
- private String encodeKey(String key) throws UnsupportedEncodingException {
- return URLEncoder.encode(key, MemBufferedDriver.ENCODING_TYPE);
- }
- private String readLine(InputStream in) throws IOException {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- boolean eol = false;
- byte[] b = new byte[1];
- while (in.read(b, 0, 1) != -1) {
- if (b[0] == 13) eol = true;
- else if (eol && b[0] == 10) break;
- else
- eol = false;
- bos.write(b, 0, 1);
- }
- if (bos.size() == 0) return null;
- return bos.toString().trim();
- }
- private byte[] object2Byte(Object o) throws IOException {
- ByteArrayOutputStream b = new ByteArrayOutputStream();
- new ObjectOutputStream(b).writeObject(o);
- return b.toByteArray();
- }
- private Object byte2Object(byte[] b) throws IOException, ClassNotFoundException {
- return new ObjectInputStream(new ByteArrayInputStream(b)).readObject();
- }
- public static void main(String[] args) throws Exception {
- MemBufferedDriver m = new MemBufferedDriver();
- System.out.println(m.set("a", "DsSD"));
- System.out.println(m.get("a"));
- }
- public static void setServerAddress(String serverAddress) {
- MemBufferedDriver.serverAddress = serverAddress;
- }
- }
java 代码
写入测试类
- public class Fill2Server extends Thread {
- public static int THREAD_COUNT = 2;
- public static Queue queue = new Queue();
- MemBufferedDriver md = new MemBufferedDriver();
- public static void main(String[] args) throws Exception {
- int size ;
- if (args.length == 3 && args[0] != null && args[1] != null) {
- MemDriver.setServerAddress(args[0]);
- size = Integer.parseInt(args[1]);
- THREAD_COUNT = Integer.parseInt(args[2]);
- new Fill2Server().doFill(size);
- } else
- System.out.println("参数1 连接服务器地址 ipaddress:port ,参数2填充数量,不能小于10000,参数3为使用的线程数");
- }
- private void doFill(int size) throws InterruptedException {
- int taskCount = size / 1000; //每个线程负责填充1000的对象
- for (int i = 0; i < taskCount; i++) {
- Task t = new Task();
- t.setTaskId(String.valueOf(i));
- queue.add(t);
- }
- long time = System.currentTimeMillis();
- Thread tr[] = new Thread[THREAD_COUNT];
- for (int i = 0; i < THREAD_COUNT; i++) {
- FillThread ft = new FillThread();
- (tr[i] = new Thread(ft)).start();
- }
- //监控填充完成
- while (true) {
- boolean flag = true;
- for (int i = 0; i < THREAD_COUNT; i++)
- flag &= tr[i].isAlive();
- if (!flag) break;
- Thread.sleep(1000);
- }
- time = System.currentTimeMillis() - time;
- System.out.println("任务完成,共用" + (time / 1000) + "s");
- }
- class FillThread implements Runnable {
- public void run() {
- Task task;
- while (true) {
- task = (Task) queue.get();
- if (task == null) break;
- long time = System.nanoTime();
- for (int i = 0; i < 1000; i++) {
- TestBO b = new TestBO();
- md.set(task.getTaskId() + i, b);
- }
- time = System.nanoTime() - time;
- System.out.println(Thread.currentThread().getName() + " avg " + (time / 1000) + " ns ");
- }
- }
- }
- }
读取的测试方法
- public class GetFromServer extends Thread {
- public static int THREAD_COUNT = 2;
- public static Queue queue = new Queue();
- MemDriver md = new MemDriver();
- public static void main(String[] args) throws Exception {
- int size;
- if (args.length == 3 && args[0] != null && args[1] != null) {
- MemDriver.setServerAddress(args[0]);
- size = Integer.parseInt(args[1]);
- THREAD_COUNT = Integer.parseInt(args[2]);
- new GetFromServer().doFill(size);
- } else
- System.out.println("参数1 连接服务器地址 ipaddress:port ,参数2读取数量不能小于1000,参数3为使用的线程数");
- }
- private void doFill(int size) throws InterruptedException {
- int taskCount = size / 100; //每个线程负责填充1000的对象
- for (int i = 0; i < taskCount; i++) {
- Task t = new Task();
- t.setTaskId(String.valueOf(i));
- GetFromServer.queue.add(t);
- }
- long time = System.currentTimeMillis();
- Thread tr[] = new Thread[GetFromServer.THREAD_COUNT];
- for (int i = 0; i < GetFromServer.THREAD_COUNT; i++) {
- GetFromServer.FillThread ft = new GetFromServer.FillThread();
- (tr[i] = new Thread(ft)).start();
- }
- //监控填充完成
- while (true) {
- boolean flag = true;
- for (int i = 0; i < GetFromServer.THREAD_COUNT; i++)
- flag &= tr[i].isAlive();
- if (!flag) break;
- Thread.sleep(1000);
- }
- time = System.currentTimeMillis() - time;
- System.out.println("任务完成,共用" + (time / 1000) + "s");
- }
- class FillThread implements
评论
我使用memcache的java client来取代Java自己的HttpSession机制,然后对一个实际的web项目使用loadrunner进行压力测试,模拟20个用户,50个用户同时使用。压力测试结果表明,使用memcache取代httpsession几乎没有性能损失。(memcache java client要开socket pool)
请问 Robbin, 你是怎么取代Java自己的HttpSession的?重写HttpSession ? 还是加HttpSessionListener ?
我使用memcache的java client来取代Java自己的HttpSession机制,然后对一个实际的web项目使用loadrunner进行压力测试,模拟20个用户,50个用户同时使用。压力测试结果表明,使用memcache取代httpsession几乎没有性能损失。(memcache java client要开socket pool)
昨天听同学说他的memecache用的是12G内存.存储大约1000万个键值对,查询速度很快.
系统使用的是什么语言体系 memcached server跑在什么os下的呢,client用的什么 server的参数咋配的呢
使用场景是什么。能介绍一下么
Memcached 的Java Client在02-28-2007发布了更新版本。据自己说性能有提高。
不知LZ有没测试过自己写的Client及官方的JavaClient的差别呢?
昨天听同学说他的memecache用的是12G内存.存储大约1000万个键值对,查询速度很快.
系统使用的是什么语言体系 memcached server跑在什么os下的呢,client用的什么 server的参数咋配的呢
使用场景是什么。能介绍一下么
昨天听同学说他的memecache用的是12G内存.存储大约1000万个键值对,查询速度很快.
这样应该不行吧。
你的client线程再多,都阻塞在一个socket通道上了。你试试多开几个memcached server(同一机器上可以不同端口),再看看效果?
从测试结果上看 在win2000 4C 8G上跑效率依然没有提高,cpu负荷很低, 瓶颈是在sock上,但具体瓶颈是在哪里呢。
另外aix下结果非常差,是不是有参数需要设置呢
相关推荐
5. **线程安全**:考虑到多线程环境,Java Memcached客户端库应该设计为线程安全的,确保在并发环境下正确操作,避免数据竞争和同步问题。 6. **性能优化**:2.0.1版本可能包含了一些性能增强,比如批量操作支持、...
7. **测试与优化**:对封装好的Memcached接口进行测试,确保其功能正确无误。同时,根据实际使用情况,可能需要对连接池、并发控制等方面进行优化。 **技术文档要点** 1. **基本概念**:介绍Memcached的基本原理、...
8. **工具与框架**:利用性能分析工具(如JProfiler, YourKit等)和性能测试工具(如JMeter, Gatling等)可以帮助识别瓶颈并进行优化。此外,Spring框架等也可能被提及,讲解如何利用其特性来提升性能。 9. **JVM...
"cache-test"可能是一个测试文件或者测试目录,它可能包含了作者对这三种缓存系统进行的一些性能测试代码或结果,用来比较和评估它们在不同场景下的表现。 **知识点详述** 1. **Memcached** - 是一个分布式内存...
【标题解析】 "Tomcat-Memcached所需jar包"这个标题揭示了我们要讨论的核心内容。Tomcat是一款广泛使用的开源Java应用服务器,而...然后,通过编程接口存取缓存数据,进行性能测试和调优,以确保系统的稳定性和效率。
7. **测试成功**:在实际部署前,通常需要进行功能测试和性能测试,确保session的存储和恢复能够正常工作,同时检查是否对应用性能产生负面影响。 8. **分布式session管理**:通过memcached,即使在服务器集群中,...
最近一直在做一个项目的前期设计工作,考虑到后期系统的扩展和性能问题也找了很多解决方法,有一个就是用到了数据库的缓存工具memcached(当然该工具并不仅仅局限于数据库的缓存)。先简单的介绍下什么是memcached。...
标题 "tomcat7整合memcached所需jar包" 暗示了我们要讨论的是如何在Tomcat 7这个流行的Java应用服务器上集成Memcached,一个分布式内存对象缓存系统。这个过程通常涉及到添加必要的jar包到Tomcat的类路径中,以便...
在本项目中,我们主要探讨的是如何将Spring Cache与memcached进行整合,以提升应用程序的性能和效率。Spring Cache是Spring框架的一部分,它提供了一种抽象的缓存管理机制,可以方便地集成到各种缓存解决方案中,如...
接下来,我们将讨论如何在Java中使用Memcached。常见的Java Memcached客户端库有spymemcached和xmemcached。这里以spymemcached为例,因为其简单易用和广泛支持。 1. 添加依赖 在你的项目中,你需要引入...
- **基于libevent的事件处理**:使用libevent库封装操作系统底层的事件处理功能,确保了高并发下的高效性能。 - **内置内存存储**:所有数据均存储于内存中,这虽然牺牲了一定程度的数据持久性,但极大地提升了数据...
2. **Java Web架构分析**:讨论了Java Web应用的常见架构模式,包括Servlet、JSP、Spring MVC等,以及它们对性能的影响。 3. **JVM优化**:深入讲解Java虚拟机(JVM)的内部工作原理,包括垃圾回收机制、类加载、...
8. **性能监控与调优**:通过使用如JMeter、Prometheus、Grafana等工具进行性能测试和监控,了解如何分析并优化系统性能。 9. **持续集成与自动化部署**:Git、Docker、Jenkins等工具的使用,以及CI/CD流程的建立,...
本知识点聚焦于如何在Windows环境下,利用Nginx作为反向代理,Memcached进行session共享,以及Tomcat作为Java应用服务器来搭建这样一个集群。这个配置确保了用户在集群中的任何一台服务器上的操作都能被其他服务器...
缓存是提升系统性能的重要手段,课程将讲解Redis和Memcached的使用,以及如何在Java中实现高效的缓存策略。 八、分布式锁 在分布式系统中,如何实现线程安全是关键问题。课程会探讨Zookeeper和RedLock等分布式锁的...
标题中的“基于mina的一个Memcached客户端首发”指出我们要讨论的是一个使用Apache MINA框架实现的Memcached客户端。Apache MINA是一个网络应用框架,主要用于简化开发高性能且高度可伸缩的网络应用程序,如服务器和...
学员将了解这两种数据库的特点,以及如何根据业务需求选择合适的存储解决方案,并进行性能测试。 6. **第147节:测试应用结合ActiveMQ的功能** - ActiveMQ是Apache出品的一个开源消息中间件,用于实现异步处理和...
Java开源BBS项目是一个基于Java技术实现的论坛系统,它为用户提供了一个在线讨论、分享信息和交流思想的平台。在Java社区中,这样的开源项目通常采用先进的技术和架构,旨在提高系统的可扩展性、稳定性和安全性。本...
Java 编写的 BBS 源码是一种基于 Java 语言实现的在线讨论平台,它提供了用户交流、发帖、回帖、搜索等功能。这个论坛系统是完全由 Java 语言构建的,利用了 Java 的面向对象特性、多线程以及网络编程能力。下面将...
9. **监控和日志**:例如使用ELK(Elasticsearch、Logstash、Kibana)堆栈进行日志管理和分析,以及Prometheus和Grafana进行性能指标监控,可以帮助开发者及时发现和解决问题。 10. **安全性**:Java安全框架如...