发表于: 2017-06-21 10:56:04
2 1054
今日完成
1 Jmeter测试
使用Jmeter对任务5的页面进行压力测试。
第一次测试100个进程10秒间隔的部署出去,每个发送10个请求。测试结果每秒可以处理90个请求,效果还不错。
第二次测试1000个进程,10秒间部署,每个发送10个请求,每秒能处理29个请求,性能下降的很明显
第三次测试,1000个进程,1秒中建立,每个发送10个请求,结果错误率到了8%,90% line已经6秒了。可以说已经不能接受了。Jmeter报错,一直不能结束测试。
第四次测试,10000个进程,同时部署,进程建立到2000个的时候jmeter报错说内存溢出,不能建立新进程了。13的错误率90%line17秒。
通过这几次测试大概感受是如果网站达到每秒有100个访问(一个访问应该有多个请求)就需要顾及性能问题了。正常访问的话100个访问每秒相当于6千个请求每分钟,能达到这个访问量的网站已经不算小网站了(大多数小网站都是一天几百个访问而已)。
2 学习使用memcached
在学习网络编程的过程中经常看到有关于caching的话题。像搜狐啊,阿里巴巴啊,亚马逊啊,京东啊,淘宝啊等等这些著名网站,每一时刻同时访问的用户都很多,遇到什么双11啊,什么什么节啊,瞬时访问量更是大的惊人,要建立能够应对这些高访问量问题的网站没有caching是无法做到的。可大多数网站并达不到这么大的访问量,真正的网络世界里,90%的网站的日访问量都很低,比如一些专业博主在网上说自己的平均日ip只有几百个。由此产生了两个问题,
- 什么量级的网站需要caching
- 怎么实现caching
我们通过下面的实验来尽可能回答上面两个问题。
1 网站测压
简单的网站测呀,我们像知道在不同访问量情况下网站的反应如何。比如同时1000人访问网站的情况下,网站用了多少秒处理每个访问,以及错误率是多少?使用Apache Jmeter可以完成这个测试。我们在SpringMvc环境下写一个简单的网页如下
1.1 Tomcat下简单页面的测试
在本机使用Jmeter模拟1,000个用户同时访问这个网页10次。测试结果显示每秒可以处理570个请求,错误率是9.67%。要注意的是错误率升高会导致Throughput增高,也就是说,如果访问数量降低,错误率也会降低,throughput也会降低。比如,如果只有500人同时访问,可能错误率降低到1%以下,throughput也降低到每秒400个左右(预测,结果下一次测试就打脸了)。
换了一个设置,在一秒里500个用户发送反问请求,循环10次。结果如下。每秒的Throughput到了2000多次。(要注意,这次测试把500个用户的创建平均分布在一秒里,而上一个测试1000个用户同时发出请求)
对于这个测试,需要额外考虑到的一些因素包括,
- 页面很简单,正常的页面会从数据库读信息,从本地静态文件读图片等信息,数据发送量会增大很多。所以Throughput一定达不到这个测试的结果。
- 这个测试是本机测试,在网络环境下,加上网络延迟,Throughput还会下降。
- 本机不是Linux服务器,而是mac,在linux下应该结果不同。(mac的硬盘是固态的,而且读写速度比较高)
保守的估计,如果是简单的页面,数据库访问量不是很大,图片不是很多的情况下,每秒500个访问以内的网站不需要caching(估计,需要真实数据佐证)。
1.2 插曲,测试Python Tornado下simple page的压力测试
Python下Tornado做服务器,通过tornado serve simple page的情况下,压力测试表现如何呢?我们用下面这段代码在Python tornado 服务器(web framework)里render simple page
测试设置了1000个用户同时发出请求,循环10次,和Java SpringMvc的第一个测试设置的条件一样。结果如下。
用第二个测试条件的结果如下。
两次测试结果的比较
测试项目 | 500用户1秒内均匀发请求 | 1000用户同时发请求 | ||
语言 | Java | Tornado | Java | Tornado |
平均处理时间 | 63 ms | 297 ms | 618 ms | 1122 ms |
中位处理时间 | 71 ms | 278 ms | 58 ms | 77 ms |
90% line | 100 ms | 522 ms | 1765 ms | 4207 ms |
错误率 | 0% | 0.10% | 9.65% | 12.80% |
Throughput | 2469/sec | 1113/sec | 570/sec | 531/sec |
注:90% line代表90%的请求在100ms内完成。
1.3 简单网页测试结论
通过这次对比可以看出JavaWeb和Python Tornado的性能比较中Java完胜。但Python的表现页并非过差。除此之外,对于简单内容的页面,如果访问峰值超过500访问每秒,就必须考虑使用caching来保证访问质量了。
2 使用MySql的网页压力测试
在MySql中建立一个Table存放一些信息如下,使用Java写一个网页展示这些信息。
简单的JSP页面显示如下
2.1 Jmeter测试
还使用1.1的测试设置,1000用户并发,和500用户1秒内平均请求,得到下面的结果。
1000用户同时发送请求,循环10次的结果显示,throughput 582/sec, 和相对应的1.1简单页面压力测试比 没有太多变化,但是错误率在使用MySql的时候达到了26%,比简单页面的9%升高了180%。实验证明在高压力下访问MySql数据库很容易出错。
500用户1秒内平均发送请求,循环10次的结果显示,throughput是911/秒,错误率0.22%。和1.1的简单页面测试比下降了64%. 主要是原因是要链接数据库。数据库链接使用了C3P0连接池,已经比每次请求都建立新的链接要好很多了。所以如果要caching数据库内容,throughput速度会有提升。
2.2 MySql页面测试结论
和简单页面测试比,由于需要增加对MySql的访问,Throughput和错误率都提高了。MySQL server设置在了本机,访问时没有网络的延迟。所以如果使用异地服务器,访问时间会更长。
3 Memcached 压力测试
我们把前面MySql的测试内容放到Memcached里面,然后进行压力测试。
3.1 Memcached入门
如果你不知道Memcached是干嘛的,就把它当作是内存里的一个NoSql数据库好了。和MySql一样,程序要用Memcached,也需要一个入口API。Java常见的入口API(称之为client)有以下2个,从搜索热度来看Spymemcached更热门些。
- java_memcached-release
- Spymemcached
使用Spymemcached很简单(参考下面的代码)
MemcachedClient client=new MemcachedClient( new InetSocketAddress("hostname", portNum)); //建立一个client对象(入口API)
c.set("someKey", 3600, someObject); // 储存一个信息
Object myObject=c.get("someKey"); // 获取一条信息.
要在我们的测试中使用Memcached,首先将Memcached安装在本机。在Java项目中引入Spymemcached的依赖。在项目中配置Client的bean。我在bean建立的时候就从数据库读取全部product信息。代码如下。
@Beanpublic MemcachedClient memcachedClient() throws Exception {ProductMapper mapper = productMapper();MemcachedClient c=new MemcachedClient(new InetSocketAddress("127.0.0.1", 11211));c.add("products", 60*10, mapper.selectAll());return c;}
我使用了Java code configuration从代码可以看到,我的memcached是装在本地的。在创建bean的时候就把数据库里面的全部product信息装入memcached(一共四条信息)。
在Controller,我们直接从memcached读取products。代码如下。
@RequestMapping(value = "/memcached_page1")public String memcachedPage1(Model model){model.addAttribute("products", (List<Product>) client.get("products"));return "mysql_page";}
访问url,一切正常。下一步就可以进入测试了。
3.2 Memcached网页压力测试
还使用前面的两种测试配置
- 1000个并发请求同时发出循环10次
- 500个请求在1秒内平均发出,循环10次
第一个测试的结果如下,1000个并发请求循环10次,throughput 达到640个每秒。和简单页面压力测试以及MySql压力测试的结果差异不大,比简单页面压力测试高,显著低于MySql压力测试的26%。
第二个测试,500个请求1秒内平均发出循环10次,throughput达到 1728访问/秒,低于简单页面的2600访问/秒,但显著高于MySql页面的911请求/秒。而且零错误率。
3.3 Memcached网页压力测试结论
使用了Memcached之后含有memcached储存信息的简单页面的访问速度已经比较接近简单页面的访问速度,和MySql页面相比性能有显著提高。
4 Redis网页压力测试
把同样的Product数据存入Redis,用同样的网页展示product数据,做压力测试。Redis把自己定义为一个运行在内存里的键值对(NoSql)数据库。而Memcached给自的定义是(分布式)的Caching系统。Redis支持多样性的数据结构。要是用Redis同样是第一步安装Redis到本地,然后在众多的API(驱动,client,叫啥都行)中选择一个。我使用Jedis。
4.1 Redis入门
首先安装Redis。然后在Java 项目中引入Jedis。目前版本是2.9.0. 有两种简易方法通过Jedis链接Redis。
4.1.1 方法1: Native方式。每次访问Redis时通过Jedis建立一个链接. 方法如下。这种方式每次访问都要建立链接关闭链接。之所以角Native的方法,就是最原始粗暴的方式。更实际的使用方式是下一种。
4.1.2 方法2:连接池方式。使用连接池链接Redis的方式更高效。使用Java try with resource的方法代码页更合理。具体代码如下。
让然,要在使用JedisPool之前创建以及配置一个JedisPool,具体代码如下。
这样就可以在Java程序里使用Redis了。Redis支持储存String,List,Hashes(就是Map/HashMap),Set,以及Sorted Set (以及 Bitmaps 和 HyperLogLogs)。可以看出来,Redis并不能直接储存Java Object。要储存JavaObject,需要把Object serialize以下,使用的时候再Deserialize。把POJO变成JSON储存会比Serialize成String储存更占空间,更耗费网络流量。
4.2 使用Redis储存Java Object (Serialize 和 Deserialize)
用最Java的方式写一个SerializationUtils class如下
package serializing;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.util.Base64;/*** Created by ProHaoLei on 6/21/17.*/public abstract class SerializationUtil {public static String serializeToString(Object obj) {String serializedObject = null;// serialize the objecttry {ByteArrayOutputStream bo = new ByteArrayOutputStream();ObjectOutputStream so = new ObjectOutputStream(bo);so.writeObject(obj);so.flush();serializedObject = Base64.getEncoder().encodeToString(bo.toByteArray());} catch (Exception e) {System.out.println(e);}return serializedObject;}public static Object deserializeFromString(String str){Object obj = null;try {byte b[] = Base64.getDecoder().decode(str);ByteArrayInputStream bi = new ByteArrayInputStream(b);ObjectInputStream si = new ObjectInputStream(bi);obj = si.readObject();} catch (Exception e) {System.out.println(e);}return obj;}}
4.3 SpringMvc 中配置 Redis 和 写Controller。
要在Spring里面配置的那个Bean(上面的bean)里面加上一段把Product list serialize了之后存入Redis的代码,这样访问页面的时候才有数据用。
我们还用原来的简单产品列表的页面。但是因为使用了Redis,要把拿回来的String 先Deserialize了才能变回List<Product>。具体代码如下。
@RequestMapping("/redis_page1")public String redisPage1(Model model) {try (Jedis jedis = jedisPool.getResource()) {List<Product> products =(List<Product>) SerializationUtil.deserializeFromString(jedis.get("products"));model.addAttribute("products", products);}return "mysql_page";}
4.4 Redis页面测压
还是使用相同的两个条件进行测试。第一个测试1000个并发访问,循环10次结果显示。Throughput到了728/秒,错误只有11.8%。两项指标都高于使用memcached。
第二个测试是500个请求1秒之内发出。结果显示Throughput和错误率都好于使用memcached。
4.5 Redis页面压力测试总结
Redis的表现(throughput 和 error%)要由于memcached(目测15%左右)。Redis支持更多的数据类型可以有比较灵活的应用。但是存储Java Object的时候需要做serialization。两个数据库都支持分布式,但使用方法各有不同。Redis给自己的定位是内存中的NoSQL数据库,而memcached给自己的定位是分布式Caching系统。但二者做Caching我会更倾向于使用Redis,因为Redis似乎有更活跃的社区而且Redis名字更一些。不过Memcached和Java结合起来使用也是很方便。
困难
总体来讲今天对很多支持进行了初级学习。知识面扩展好了多,接触了新的领域,但都是蜻蜓点水,没有深入学习。对于如何使用并不是很自信。结论也并不一定准确。时间有限,学Java的时候总是不停的再问自己:我到底应该学点什么?太多framework,到底应该学习多深(时间毕竟有限)
收获
学习了很多东西,通过测试对静态页面,MySql,Memcached,以及Redis有了一些认识。对网站性能要求有了一定的认识。使用Jmeter测压了Python tornado的网站以及Java SpringMVC的网站,对两种语言写网站的性能有了一点认识。
明日计划
学习Nginx分布式,争取完成任务6.
评论