大型WEB应用性能调优总结

声明
本文为Gleasy原创文章,转载请指明引自Gleasy团队博客

问题初级定位方法: 一感三看
一感,凭个人感觉,操作不流畅,有挫折感肯定有问题。
三看:
一看ajax请求的执行时间,网络条件好的情况下,超过400MS的肯定有问题;
二看静态内容(html,图片,js,css)等是否cache,没有cache肯定有问题;
三看同一个ajax请求的数量,如果连续有N个(N>3)以上同一个AJAX请求,肯定有问题;

问题深入定位方法
方法一:使用stopwatch,在程序中植入log记录执行时间,通过查看执行时间以定位出问题的代码段;
方法二:间隔重复可疑操作,观察记录CPU变化情况。用以观察是否有死循环或者大规模遍历。
方法三:恶意快速重复点击同一个功能按键20次,观察是否会重复发起后端请求20次,如果是,那么,也是有问题的。
方法四:使用SQL监控(druid)来观察每一个SQL执行次数,执行时间,从而发现热点问题

应用技巧
NO1. 弱化数据库
1.将数据库弱化为“存储”,避免使用数据库查询能力,尽量使用主键或唯一键进行精确读取动作,数据量不太大的表可以使用普通索引进行精确读取,避免使用范围查询(> < != between in),禁止使用like,禁止使用子查询,联合查询,exists查询;
2.范围查询和like查询,一律使用索引平台CloudIndex替代;
3.子查询,联合查询,exists查询:一律在应用层进行逻辑拼装(如果数据量太大,可以使用Map-Reduce进行多线程计算,如果再大可以使用cloudjob进行分布式调度)

NO2. 善用缓存
1.提高缓存命中率为终极目标;
2.容易忽视的缓存问题:大量访问己被删除数据,由于数据不存在,缓存肯定不命中,导致频频访问数据库;解决方法是对己删除的数据做特殊缓存标记;
3.对写入性能要求极为苛刻的场景可以使用redis缓存-存储切换的方式进行异步写入:写入redis(标记为存储),立刻返回,另起独立线程将写入数据同步至数据库,同步成功之后,将redis中相应数据标记为缓存。

NO3. 用好中间件
1. 对于写入性能要求苛刻(或写入并发量特别大的)且允许写入延迟的情况,使用CloudMQ中间件;比如发邮件,发微博,发留言等;
2. 定时任务(比如定时发送邮件,定时提醒),特别适合使用CloudJob中间件
3. 对于消耗性任务(比如执行时间长且任务量大,消耗CPU资源),可以使用CloudJob进行分布式任务调度,将众多大任务放到N台后台机器上执行;

NO4. 批量操作(从前端到后端)
1. 前端批量,针对大量重复调用某一接口的情况,由于AJAX的异步性,可以将N个请求合并成一个请求,串行执行AJAX,策略如下(伪代码):

var getDepartmentLinkByUid = function(uid,callback){
  if(loading){cache.push({uid:uid,callbackup:callback}); return;}
  loading = true;
  realGet();
}

var realGet = function(){
 var tmp = cache.splice(0);
 $.ajax({
    data:由tmp的uid拼接而成,
    success:function(dt){
      for(var i=0;i<tmp.length;i++){
        var uid = tmp[i].uid;
        var rdata = dd[tt];
        tmp[i].callback(rdata); 
      }
      if(cache.length>0)  realGet();
    }
  });
}

 

2. 缓存批量(承接上面的例子)

 objects = mget(uids);
 notcached = new ArrayList();
 for(uid:uids){
  if(objects 不包含uid) notcached.add(uid);
 } 

 

3. 数据库批量查询(承接上面的例子),批量更新缓存

 notcachedData = select * from department where uid in (notcached列表);
 mset(notcachedData 生成的 map);

 

此条目发表在 Java技术, 分布式技术, 前端技术, 数据库技术 分类目录,贴了 , , , 标签。将固定链接加入收藏夹。

发表评论