一启才福上线spider之后,开始关注程序的性能问题,比较典型的问题出了几个。
1、关于登录图片验证码,在非docker环境,共享session情况,服务器存储的是request中的param中,docker环境下,每次请求可能被不同的服务器处理,导致错误。最终使用通过本地cookie存储key_,然后存储/查询redis中的方式解决。
2、每日收益等接口数据响应时间长。
通过每日定时任务,保存数据的方式(接口数据静态化),减短响应时间。
3、系统容错耦合度高的问题
以收银台发的支付通知为例,需要多步处理。1、本地处理更新订单数据,2、通知产品中心支付接口。3、添加分销数据。4、发送邮件 5、更新用户新手状态 等,6返回状态码。
系统接了子渠道后,需要再添加一个功能,7、通知子渠道的通知状态,如果其中某一步出错,就需要产品中心不断的发定时通知,这显然是合理的。
通过本地订单状态,通过定时任务给子渠道发送订单状态。降低了系统之间的强依赖,减低了系统之间耦合度。
4、程序响应时间长的问题。
以收银台通知支付结果为例: 需要6-7步完成,考虑3把不相关的步骤多线程异步处理下。
1、考虑过时间监听器,给多个任务publishEvent方式分配不同的时间监听。
2、通过nio,设置缓冲区,比如rabbitMq消息队列方式去处理。
3、使用Furture方式,以下便是多线程一个简单应用。
比如,以做饭为例(假定步骤可能存在不合理),
1、从网上购买刀具,切菜板
2、去超市购买蔬菜,米面油
3、收到快递 及蔬菜到家后,开始做饭。
public class OnlineShopping implements Runnable{
private Knife knife;
@Override
public void run() {
System.out.println("第一步:下单");
System.out.println("第二步:等待送货");
try {
Thread.sleep(10000);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("第三步:快递送到");
knife=new Knife();
}
public Knife getKnife() {
return knife;
}
}
public class MarketShopping implements Runnable{
private Vegetable vegetable;
@Override
public void run() {
System.out.println("第一步:去超市");
System.out.println("第二步:挑选蔬菜");
try {
Thread.sleep(5000);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("第三步:菜带回家");
vegetable=new Vegetable();
}
public Vegetable getVegetable() {
return vegetable;
}
}
public class CommonCook {
public static void main(String[] args) throws InterruptedException{
//第一步
long startTime = System.currentTimeMillis();
OnlineShopping onlineShopping=new OnlineShopping();
Thread thread=new Thread(onlineShopping);
thread.start();
MarketShopping marketShopping=new MarketShopping();
Thread thread2=new Thread(marketShopping);
thread2.start();
thread.join();
thread2.join();
System.out.println("准备工作用时" + (System.currentTimeMillis() - startTime) + "ms,开始展示厨艺");
cook(onlineShopping.getKnife(),marketShopping.getVegetable());
System.out.println("饭做好总共用时" + (System.currentTimeMillis() - startTime) + "ms");
}
public static void cook(Knife knife,Vegetable vegetables){
try {
// 模拟做饭时间
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
第一步:下单
第二步:等待送货
第一步:去超市
第二步:挑选蔬菜
第三步:菜带回家
第三步:快递送到
准备工作用时10004ms,开始展示厨艺
饭做好总共用时20004ms
实现Runnable接口创建线程, 缺陷就是在执行完任务之后无法获取执行结果,使用thread.join(); 等待进程做完。
Callable
和 Runnable
都是执行的任务的接口,区别在于Callable
有返回值,而Runnable
无返回值。
下一篇,开始改造代码。