发表于: 2018-01-30 11:38:09
2 672
今天完成的事情
1.任务的验收标准
(1)首先是系统可以在500ms返回时的tps:
经过很多次变更调试,最终确定全部请求时键500ms以内的线程数最大是22,最大循环次数1:
也尝试了微调,比如23线程:
也就不满足条件了,也尝试稍微加上一次循环,也就是22线程2次循环:
也已经不符合条件。
那么符合条件的就是22线程1s启动循环1次,它的tps视图:
因为线程数和循环数都很小,总请求就很少,所以它是一条直线。那就得出结论了,系统可以再500ms内返回时的tps是18.3。
(2)系统宕机时候的负载:
首先我得定义宕机,我认为测试被迫停止或者就是宕机,没有按照设置跑完就宕机了。
100线程1s启动的情况:
虽然没有宕机,但是响应时间已经非常的长了,但是这还没宕机,调到200线程:
虽然各个参数都挺惨,但是仍然没有宕机,接下来调到300线程:
嗯。。还没有,直接加到500线程:
已经卡住了,并且出现了错误,在观察过程中错误率一直在波动,是因为错误在不断的出现,可以认为此时已经宕机了。
于是结论是:500线程1s启动的时候宕机了。
(3)TPS稳定时的响应时长:
那么调整线程数,达到让tps稳定:
可以看到除了画圈的部分,整体比较稳定,分别对应的是0-20s和49-59s以及1.19-1.39s,那么查看这几个区间的响应时间:
那么可以看到这写区间的响应时间,但是这个图并不是很好,因为刻度太大了,我们只能估摸着来,稳定的时候大概在1.5s左右,不过很多值是小于这个数的
2.那么接下来就是模拟缓存穿透的情况:想想一想要怎么模拟,而且缓存穿透是什么?
这样说吧,本来存在缓存的时候,请求会从环中取出数据,而有的时候突然跑到了数据库中去拿数据,就是缓存穿透了,缓存没能拦住这个请求。也就是说要创走啊这样一个情况:让请求又从缓存拿的,有从数据库拿的,然后对比一下情况。看看缓存穿透的时候会发生些什么。
那么需要在代码里面更改一些,加上一个判断,来查看一波
public static int i = 0;//定义全局静态变量,来保存数据
public List<Pros> getAllPros(){
i++;
System.out.println(i);
List<Pros> pross;
if (redisUtil.get("pross") != null&&i%9!=0){
pross = (List<Pros>)redisUtil.get("pross");
System.out.println("从缓存中取到的哦");
// return pross;
}else{
pross = pageDao.getAllPros();
redisUtil.set("pross",pross);
System.out.println("从数据库取到的哦");
// return pross;
}
return pross;
}
这样的话,只有9的倍数次访问的时候才会模拟击穿缓存。
很清晰。
然后在使用jmeter测试的时候效果并不直观,数据太过笼统,于是选择了postman来测试:
这是一次缓存穿透的响应时间。然后下面是直接使用缓存的:
然后赶上下一次的穿透:
还是比较直观的,大概20%的提升吧,而且我觉得在多线程访问的时候肯定效果更好。
附上简书链接,图都挂了:https://www.jianshu.com/p/7ef8000e1365
3.接下来开始准备提交任务
下面是官方的脑图:
任务名称:task6
成果链接:http://47.93.229.36/task6RedisDemo/
任务耗时:1.27-1.30共计四天,没有延期
任务脑图:
下面是官方的脑图:
任务总结:
a.任务进度在预期之内,都在计划之中
b.脑图对比,发现还是层次上有一些问题吧,关于知识点的梳理分类,稍有欠缺。
c.任务中碰到问题,在这里简单说一下:
按照任务要求的顺序来说吧:节点1的说明:程序挂掉的含义很模糊,各位大佬也没说出个标准来,只能按照自己顶的标准来进行。
节点2的说明:使用Memcached还是顺风顺水的,挺好使的,也很轻松,没什么好说的
节点3的说明:nginx的负载均衡,这个东西在任务二的时候已经做过,更是没啥好说的了,稍微注意下验证成功的方法吧,我是通过查看nginx的日志来判断的。
节点4的说明:节点4真的是问题比较难受,spring和redis的整合过程中真的碰到了很多很多的问题,不过都不是什么很难的东西,大家使用redis的时候注意jar包的版本就好了,完全没问题的。
大总结一下,其实这部分任务真的耗时挺短的,大家首先搞清楚压力测试是什么,然后缓存是什么,负载均衡是什么,结合我上面说到的问题,就可以比较轻松地通关。
4.正好借此总结一下知识点吧:
在任务六中涉及到的新的知识点也就是缓存了,毕竟压力测试这块儿是借用的工具来模拟,那接下来就说说缓存:
提到缓存,其他的存也要说一下:
外存:
也就是我们经常说的(CDEF盘的大小)外储存器是指除计算机内存及CPU缓存以外的储存器,此类储存器一般断电后仍然能保存数据。常见的外存储器有硬盘、软盘、光盘、U盘等,一般的软件都是安装在外存中
内存:
内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。计算机中所有程序的运行都是在内存中进行的,因此内存的性能对计算机的影响非常大。内存(Memory)也被称为内存储器,其作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。只要计算机在运行中,CPU就会把需要运算的数据调到内存中进行运算,当运算完成后CPU再将结果传送出来,内存的运行也决定了计算机的稳定运行,此类储存器一般断电后数据就会被清空
高速缓存:
高速缓存是用来协调CPU与主存之间存取速度的差异而设置的。一般情况下,CPU的工作速度高,但内存的工作速度相对较低,为了解决这个问题,通常使用高速缓存,高速缓存的存取速度介于CPU和主存之间。系统将一些CPU在近几个时间段经常访问的内容存入高速缓冲,当CPU需要使用数据时,先在高速缓存中找,如果找到,就不必访问内存了,找不到时,再找内存,这样就在一定程度上缓解了由于主存速度低造成的CPU“停工待料”的情况
简单讲就是,如果某些资源或者数据会被频繁的使用,而这些资源或数据存储在系统外部,比如数据库、硬盘文件等,那么每次操作这些数据的时候都从数据库或者硬盘上去获取,速度会很慢,会造成性能问题。
一个简单的解决方法就是:把这些数据缓存到内存里面,每次操作的时候,先到内存里面找,看有没有这些数据,如果有,那么就直接使用,如果没有那么就获取它,并设置到缓存中,下一次访问的时候就可以直接从内存中获取了。从而节省大量的时间,当然,缓存是一种典型的空间换时间的方案。
在Java中最常见的一种实现缓存的方式就是使用Map, 基本的步骤是:
先到缓存里面查找,看看是否存在需要使用的数据
如果没有找到,那么就创建一个满足要求的数据,然后把这个数据设置回到缓存中,以备下次使用
如果找到了相应的数据,或者是创建了相应的数据,那就直接使用这个数据。
也就是缓冲存储,我的理解就是假存储,并不会永久存在,只是在一段时间内可以使用,并且速度比较快,用它来保存数据读取数据都比较轻松。怒过因为学习的层面比较浅,很多东西还没涉及到。
既然知道了什么是缓存,就来了解一下使用的Memcached和redis,这两个东西吧:
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信。
上面就Memcached的定义了,连它做啥字都非常的清楚,在web项目中使用的时候要借助工具类:
import com.whalin.MemCached.MemCachedClient;
import com.whalin.MemCached.SockIOPool;
public class MemcachedUtil {
/**
* memcached客户端单例
*/
private static MemCachedClient cachedClient = new MemCachedClient();
/**
* 初始化连接池
*/
static {
//获取连接池的实例
SockIOPool pool = SockIOPool.getInstance();
//服务器列表及其权重
// 可以是多个服务器
String[] servers = {"127.0.0.1:11211"};
Integer[] weights = {3};
//设置服务器信息
pool.setServers(servers);
pool.setWeights(weights);
//设置初始连接数、最小连接数、最大连接数、最大处理时间
pool.setInitConn(10);
pool.setMinConn(10);
pool.setMaxConn(1000);
pool.setMaxIdle(1000*60*60);
//设置连接池守护线程的睡眠时间
pool.setMaintSleep(60);
//设置TCP参数,连接超时
pool.setNagle(false);
pool.setSocketTO(60);
pool.setSocketConnectTO(0);
//初始化并启动连接池
pool.initialize();
//压缩设置,超过指定大小的都压缩
// cachedClient.setCompressEnable(true);
// cachedClient.setCompressThreshold(1024*1024);
}
private MemcachedUtil(){
}
public static boolean add(String key, Object value) {
return cachedClient.add(key, value);
}
public static boolean add(String key, Object value, Integer expire) {
return cachedClient.add(key, value, expire);
}
public static boolean put(String key, Object value) {
return cachedClient.set(key, value);
}
public static boolean put(String key, Object value, Integer expire) {
return cachedClient.set(key, value, expire);
}
public static boolean replace(String key, Object value) {
return cachedClient.replace(key, value);
}
public static boolean replace(String key, Object value, Integer expire) {
return cachedClient.replace(key, value, expire);
}
public static Object get(String key) {
return cachedClient.get(key);
}
}
借助这个工具类就可以在项目中将数据加到缓存中:
@Autowired
public PageDao pageDao;
public List<Pros> getAllPros(){
System.out.println("要进入缓存了");
List<Pros> pross ;
if (MemcachedUtil.get("pross")!= null){
System.out.println("这说明有缓存啊");
pross = (List<Pros>) MemcachedUtil.get("pross");
return pross;
}else{
System.out.println("这说明没有缓存啊");
pross = pageDao.getAllPros();
MemcachedUtil.put("pross",pross,600);
return pross;
}
}
就像上面这样使用,加进缓存和从缓存中取出来。
嗯。。。好多东西都没有用到,我也不再这里赘述了。
在这就是redis的使用了,其实和上面的这个东西是一样的,只不过安装的整合的时候真的是费劲,注意版本号!
一定要全部对应好才可以使用!!!!!!!!!!!!!!!!!!!!!!
一定要全部对应好才可以使用!!!!!!!!!!!!!!!!!!!!!!
一定要全部对应好才可以使用!!!!!!!!!!!!!!!!!!!!!!
最后的话提一嘴负载均衡,这个东西没啥难的吧。。虽然我当时也快被虐哭了,但是返回来一看还是挺简单的。
好了,任务六就总结到这里吧。
5.开始搞任务七。。
完成了节点1:
新增了字段:
不过暂时不太清楚头像这块儿应该怎么处理。
6.然后帮助同学解决问题的时候虽然解决了问题,但是尝试例外的方法是失败了。
是template的语句拼接出现了问题,多亏明达大佬
在template的实体类里面插入Students students的时候对应的插入语句那块儿有个拼接:
jdbcTemplateObject.update( SQL,id,name,age);这是参数写全的情况用的
jdbcTemplateObject.update( SQL,student.getid(),student.getname(),student.getage());
这是参数只写Student student的情况。
涨了一波知识。
今天遇到的问题
发现自己没学习json,明天将json的相关知识补一补,之前涉及的太浅了。
今天的收获:
今天完成了任务六,查漏补缺,发现了欠缺的知识点,这块儿除了json已经没任何遗憾了。
明天计划的事情:
明天计划补上json的学习,然后继续深入任务7
评论