java web项目性能优化之五花八门
来源:互联网 发布:社交网络电影图解 编辑:程序博客网 时间:2024/05/24 15:36
最近是做了半年的项目到了最后测试准备上线了,流程走通后开始做一些性能测试,在此期间做了很多性能优化的工作,在此做下笔记,分享一下。交流一下,希望同道中人有新的东西欢迎补充。在此就不做太多的具体操作,主要还是从思路上出发。
性能优化主要从几个方面着手。
1.从架构设计的角度
现在的web项目不再像七八年前以前的项目单个的动态web工程就能满足性能的要求了,现如今项目只要是抱着一个美好前景的话,一般都会假设自己的项目未来是PB级数据量,亿级用户量,几万并发的赚暴的独角兽项目,无论是电商,新浪,搜狐等门户网站都会有大量数据,大量的用户,现在热门的物联网虽然用户量没有大规模,然而一堆一堆的传感器从不觉得累地同时访问你,产生大量的数据。
为此,要想你的系统在满足要求的情况下扛住压力实现高可用,靠提高硬件已经性价比上不能接收。如下是一张简单流行的分布式架构图,不全面,只用来说明一下性能方面相关:
上图web服务器一般以集群的形式,用lvs,Nginx等开源工具做反向代理和API层的负载均衡。业务层service可以用Dubbo等RPC框架实现分布式调用,达到多节点同时处理计算,现在又有一种新的趋势,以springboot框架做微服务进行服务间以restful接口调用,两种形式各有千秋,前者较后都就目前来说更流行一些,在此只关注对性能相关的话题。
另外,使用redis,memcache等开源工具做缓存对性能也有较大的提高,当然也会有一些管理难的代价,管理不好经常出现数据不一致。
2.从数据库的角度
关系形数据库在数据量达到一定规模查询效果较差,像一些操作纪录等数据可以用elasticsearch,redis,mongodb等nosql非关系形数据库来存储,查询性能比关系形数据库好很多,但是比如金钱,订单,用户信息等“贵重”信息只能用关系形数据库来存储。关系形数据库性能提高常的方法一般包括建立索引,视图等。有些数据库如mysql官方还提供代理工具实现水平拆分,垂直拆分等,Mysql proxy代理工具可以实现数据库的读写分离,都能一定程序提高关系数据库的性能。
3.从代码的角度
进入一家新公司后,一般架构都已经定了,为了性能动架构的机会不是很多,除非决定整个项目重构,难道在性能方面就没有办法了吗?答案是否定的,java真的是一门神奇的语言,可能简洁度上不如php语言,性能不如c++,api没有scala丰富,也没有golang那么高效,然而java是最中庸的,综合实力最强。在此为java点个赞,好了,还是上代码吧。
比如有个需求,第一步要调用北京总公司的中控服务器拿token等验证信息,平均耗时要1秒,调本系统查询订单处理要2秒,调百度上传图片要2秒,调阿里支付要3秒,有一个方法里面全部完成这些操作,普通的写法如下:
package com.web.service.back.impl;import java.util.concurrent.TimeUnit;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;@Controllerpublic class PayOrder { @RequestMapping("pay") @ResponseBody public Boolean payGood(String userName, String password, double money) throws InterruptedException { String token = getToken(userName, password);// 1秒 String url = upLoadPic();// 2秒 double totalFee = dealOrder(userName);// 返回总金额 2秒 payMoney(totalFee);//3秒 return true; } private String upLoadPic() throws InterruptedException { TimeUnit.SECONDS.sleep(2); return "url"; } private void payMoney(double totalFee) throws InterruptedException { TimeUnit.SECONDS.sleep(3); } private double dealOrder(String userName) throws InterruptedException { double sum = 0; for (int i = 0; i < 20; i++) { TimeUnit.MILLISECONDS.sleep(100);// 模拟处理单个订单消耗00毫秒,20个订单为2秒 sum += i * 50.00; } return sum; } private String getToken(String userName, String password) throws InterruptedException { TimeUnit.SECONDS.sleep(1);// 模拟调用时间为2秒 return "123456"; }}这样的结果有点吓人,总的消耗时间为 1+2+2+3 =8秒,这在生产环境是不能被忍受的。上面代码是串行运行,我们可以做以下处理
@RequestMapping("pay") @ResponseBody public Boolean payGood(String userName, String password, double money) throws InterruptedException { ExecutorService pool = Executors.newCachedThreadPool(); Future<Double> totalFeeFuture = pool.submit(new Callable<Double>() { @Override public Double call() throws Exception { return dealOrder(userName);// 返回总金额 2秒 } }); Future<String> tokenFuture = pool.submit(new Callable<String>() { @Override public String call() throws Exception { return getToken(userName, password);// 2秒 } }); Future<String> picUrlFuture = pool.submit(new Callable<String>() { @Override public String call() throws Exception { return upLoadPic();// 2秒 } }); pool.submit(new Runnable() { @Override public void run() { try { payMoney(totalFeeFuture.get(2, TimeUnit.SECONDS));// 设置超时设置 } catch (InterruptedException | ExecutionException | TimeoutException e) { e.printStackTrace(); } // 3秒 } }); try { String url = picUrlFuture.get(2, TimeUnit.SECONDS); tokenFuture.get(2, TimeUnit.SECONDS); } catch (ExecutionException | TimeoutException e) { e.printStackTrace(); } return true; }
@RequestMapping("pay") @ResponseBody public Boolean payGood(String userName, String password, double money) { try { CompletableFuture<Double> totalFeeFuture = CompletableFuture.supplyAsync(() -> dealOrder(userName)); CompletableFuture<String> tokenFuture = CompletableFuture.supplyAsync(() -> getToken(userName, password)); CompletableFuture<String> picUrlFuture = CompletableFuture.supplyAsync(() -> upLoadPic()); CompletableFuture.runAsync(() -> payMoney(totalFeeFuture.get(2, TimeUnit.SECONDS))); String token = tokenFuture.get(); String url = picUrlFuture.get(); } catch (InterruptedException | ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } return true; }
private double dealOrder(String userName) throws InterruptedException { double sum = 0; for (int i = 0; i < 20; i++) { TimeUnit.MILLISECONDS.sleep(100);// 模拟处理单个订单消耗00毫秒,20个订单为2秒 sum += i * 50.00; } return sum; }处理订单是在一个串行20次循环中处理,感觉也糟糕透了。下面提供两程优化。第一种countDownLatch
double sum = 0; private double dealOrder(String userName) throws InterruptedException { CountDownLatch latch = new CountDownLatch(20); ExecutorService pool = Executors.newFixedThreadPool(10); pool.execute(new Runnable() { AtomicInteger i = new AtomicInteger(0); @Override public void run() { sum += i.doubleValue()*50.00; i.incrementAndGet(); latch.countDown(); } }); latch.await(); return sum; }
这里await()方法会阻塞.
private double dealOrder(String userName) throws InterruptedException { double sum = IntStream.rangeClosed(0, 20).parallel().asDoubleStream().map((i) -> i*50.00).reduce(0, Double::sum); return sum; }
- java web项目性能优化之五花八门
- java性能优化之java web项目性能优化(一)
- web项目性能优化
- Web项目性能优化之减少HTTP请求次数优化
- Web项目性能优化之减少HTTP请求次数优化
- Java Web性能优化
- Java Web性能优化
- Java Web 项目优化
- Java Web性能优化原则
- Java 之性能优化
- 【java】itoo项目实战之hibernate 懒加载优化性能
- java web 性能优化----浏览器优化
- 高性能web网站优化项目
- web开发性能优化---项目架构篇
- web项目的性能优化原则
- web开发性能优化---项目架构篇
- web项目性能优化(整理)
- java web项目优化过程
- 机器学习精简教程之九——用scikit-learn的网格搜索快速找到最优模型参数
- Android-UI绘制分析01
- Nginx无法启动也不报错
- 安卓 类似美团等菜单的 使用
- HCI CONFIGURATION PARAMETERS
- java web项目性能优化之五花八门
- Base64转换成流
- Wormholes(最短路)
- 一个开源轮播图控件,非常好用
- Android学习之将一个Activity设置main Activity
- OpenCV学习(12) 图像的腐蚀与膨胀(3)
- caffe源码追踪-- Google Protocol Buffer
- Android bindservice失败解决方法
- H5开发技术将不断突破