高并发


一:高并发高负载类网站关注点之数据库

没错,首先是数据库,这是大多数应用所面临的首个SPOF。尤其是Web2.0的应用,数据库的响应是首先要解决的。
一般来说MySQL是最常用的,可能最初是一个mysql主机,当数据增加到100万以上,那么,MySQL的效能急剧下降。常用的优化措施是M-S(主 -从)方式进行同步复制,将查询和操作和分别在不同的服务器上进行操作。我推荐的是M-M-Slaves方式,2个主Mysql,多个Slaves,需要注意的是,虽然有2个Master,但是同时只有1个是Active,我们可以在一定时候切换。之所以用2个M,是保证M不会又成为系统的SPOF。
Slaves可以进一步负载均衡,可以结合LVS,从而将select操作适当的平衡到不同的slaves上。
以上架构可以抗衡到一定量的负载,但是随着用户进一步增加,你的用户表数据超过1千万,这时那个M变成了SPOF。你不能任意扩充Slaves,否则复制同步的开销将直线上升,怎么办?我的方法是表分区,从业务层面上进行分区。最简单的,以用户数据为例。根据一定的切分方式,比如id,切分到不同的数据库集群去。

全局数据库用于meta数据的查询。缺点是每次查询,会增加一次,比如你要查一个用户nightsailer,你首先要到全局数据库群找到 nightsailer对应的cluster id,然后再到指定的cluster找到nightsailer的实际数据。
每个cluster可以用m-m方式,或者m-m-slaves方式。这是一个可以扩展的结构,随着负载的增加,你可以简单的增加新的mysql cluster进去。

需要注意的是:
1、禁用全部auto_increment的字段
2、id需要采用通用的算法集中分配
3、要具有比较好的方法来监控mysql主机的负载和服务的运行状态。如果你有30台以上的mysql数据库在跑就明白我的意思了。
4、不要使用持久性链接(不要用pconnect),相反,使用sqlrelay这种第三方的数据库链接池,或者干脆自己做,因为php4中mysql的链接池经常出问题。

二:高并发高负载网站的系统架构之HTML静态化
其实大家都知道,效率最高、消耗最小的就是纯静态化的 html页面,所以我们尽可能使我们的网站上的页面采用静态页面来实现,这个最简单的方法其实也是 最有效的方法。但是对于大量内容并且频繁更新的网站,我们无法全部手动去挨个实现,于是出现了我们常见的信息发布系统CMS,像我们常访问的各个门户站点 的新闻频道,甚至他们的其他频道,都是通过信息发布系统来管理和实现的,信息发布系统可以实现最简单的信息录入自动生成静态页面,还能具备频道管理、权限 管理、自动抓取等功能,对于一个大型网站来说,拥有一套高效、可管理的CMS是必不可少的。
  
  除了门户和信息发布类型的网站,对于交互性要求很高的社区类型网站来说,尽可能的静态化也是提高性能的必要手段,将社区内的帖子、文章进行实时的静态化,有更新的时候再重新静态化也是大量使用的策略,像Mop的大杂烩就是使用了这样的策略,网易社区等也是如此。
  
   同时,html静态化也是某些缓存策略使用的手段,对于系统中频繁使用数据库查询但是内容更新很小的应用,可以考虑使用html静态化来实现,比如论坛 中论坛的公用设置信息,这些信息目前的主流论坛都可以进行后台管理并且存储再数据库中,这些信息其实大量被前台程序调用,但是更新频率很小,可以考虑将这 部分内容进行后台更新的时候进行静态化,这样避免了大量的数据库访问请求高并发。

网站HTML静态化解决方案
当一个Servlet资源请求到达WEB服务器之后我们会填充指定的JSP页面来响应请求:

HTTP请求---Web服务器---Servlet--业务逻辑处理--访问数据--填充JSP--响应请求

HTML静态化之后:

HTTP请求---Web服务器---Servlet--HTML--响应请求

静态访求如下

Servlet:

public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    if(request.getParameter("chapterId") != null){
        String chapterFileName = "bookChapterRead_"+request.getParameter("chapterId")+".html";
        String chapterFilePath = getServletContext().getRealPath("/") + chapterFileName;
        File chapterFile = new File(chapterFilePath);
        if(chapterFile.exists()) {response.sendRedirect(chapterFileName);return;}//如果有这个文件就告诉浏览器转向  
        INovelChapterBiz novelChapterBiz = new NovelChapterBizImpl();
        NovelChapter novelChapter = novelChapterBiz.searchNovelChapterById(Integer.parseInt(request.getParameter("chapterId")));// 章节信息  
        int lastPageId = novelChapterBiz.searchLastCHapterId(novelChapter.getNovelId().getId(), novelChapter.getId());
        int nextPageId = novelChapterBiz.searchNextChapterId(novelChapter.getNovelId().getId(), novelChapter.getId());
        request.setAttribute("novelChapter", novelChapter);
        request.setAttribute("lastPageId", lastPageId);
        request.setAttribute("nextPageId", nextPageId);
        new CreateStaticHTMLPage().createStaticHTMLPage(request, response, getServletContext(),  
                chapterFileName, chapterFilePath, "/bookRead.jsp");
    }
}
生成HTML静态页面的类:

public class CreateStaticHTMLPage {
    /**
     * 生成静态HTML页面的方法
     * @param request 请求对象
     * @param response 响应对象
     * @param servletContext Servlet上下文
     * @param fileName 文件名称
     * @param fileFullPath 文件完整路径
     * @param jspPath 需要生成静态文件的JSP路径(相对即可)
     * @throws IOException
     * @throws ServletException
     */
    public void createStaticHTMLPage(HttpServletRequest request, HttpServletResponse response,ServletContext servletContext,String fileName,String fileFullPath,String jspPath) throws ServletException, IOException{
        response.setContentType("text/html;charset=gb2312");//设置HTML结果流编码(即HTML文件编码)  
        RequestDispatcher rd = servletContext.getRequestDispatcher(jspPath);//得到JSP资源  
        final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();//用于从ServletOutputStream中接收资源  
        final ServletOutputStream servletOuputStream = new ServletOutputStream(){//用于从HttpServletResponse中接收资源  
            public void write(byte[] b, int off,int len){
                byteArrayOutputStream.write(b, off, len);
            }
            public void write(int b){
                byteArrayOutputStream.write(b);
            }
        };
        final PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(byteArrayOutputStream));//把转换字节流转换成字符流  
        HttpServletResponse httpServletResponse = new HttpServletResponseWrapper(response){//用于从response获取结果流资源(重写了两个方法)  
            public ServletOutputStream getOutputStream(){
                return servletOuputStream;
            }
            public PrintWriter getWriter(){
                return printWriter;
            }
        };
        rd.include(request, httpServletResponse);//发送结果流  
        printWriter.flush();//刷新缓冲区,把缓冲区的数据输出  
        FileOutputStream fileOutputStream = new FileOutputStream(fileFullPath);
        byteArrayOutputStream.writeTo(fileOutputStream);//把byteArrayOuputStream中的资源全部写入到fileOuputStream中  
        fileOutputStream.close();//关闭输出流,并释放相关资源  
        response.sendRedirect(fileName);//发送指定文件流到客户端  
    }
}
三:高并发高负载类网站关注点之缓存、负载均衡、存储

缓存是另一个大问题,我一般用memcached来做缓存集群,一般来说部署10台左右就差不多(10g内存池)。需要注意一点,千万不能用使用
swap,最好关闭linux的swap。

负载均衡/加速
可能上面说缓存的时候,有人第一想的是页面静态化,所谓的静态html,我认为这是常识,不属于要点了。页面的静态化随之带来的是静态服务的
负载均衡和加速。我认为Lighttped+Squid是最好的方式了。
LVS <------->lighttped====>squid(s) ====lighttpd

上面是我经常用的。注意,我没有用apache,除非特定的需求,否则我不部署apache,因为我一般用php-fastcgi配合 lighttpd,
性能比apache+mod_php要强很多。

squid的使用可以解决文件的同步等等问题,但是需要注意,你要很好的监控缓存的命中率,尽可能的提高的90%以上。
squid和lighttped也有很多的话题要讨论,这里不赘述。


存储
 存储也是一个大问题,一种是小文件的存储,比如图片这类。另一种是大文件的存储,比如搜索引擎的索引,一般单文件都超过2g以上。
小文件的存储最简单的方法是结合lighttpd来进行分布。或者干脆使用Redhat的GFS,优点是应用透明,缺点是费用较高。我是指
你购买盘阵的问题。我的项目中,存储量是2-10Tb,我采用了分布式存储。这里要解决文件的复制和冗余。
这样每个文件有不同的冗余,这方面可以参考google的gfs的论文。
大文件的存储,可以参考nutch的方案,现在已经独立为hadoop子项目。

其他:
此外,passport等也是考虑的,不过都属于比较简单的了。
四:高并发高负载网站的系统架构之图片服务器分离
大家知道,对于Web 服务器来说,不管是Apache、IIS还是其他容器,图片是最消耗资源的,于是我们有必要将图片与页面进行分离,这是基本上大型网站都会采用的策略,他 们都有独立的图片服务器,甚至很多台图片服务器。这样的架构可以降低提供页面访问请求的服务器系统压力,并且可以保证系统不会因为图片问题而崩溃,在应用 服务器和图片服务器上,可以进行不同的配置优化,比如apache在配置ContentType的时候可以尽量少支持,尽可能少的LoadModule, 保证更高的系统消耗和执行效率。


利用Apache实现图片服务器的分离
缘由:
起步阶段的应用,都可能部署在一台服务器上(费用上的原因)
第一个优先分离的,肯定是数据库和应用服务器。
第二个分离的,会是什么呢?各有各的考虑,我所在的项目组重点考虑的节约带宽,服务器性能再好,带宽再高,并发来了,也容易撑不住。因此,我这篇文章的重点在这里。这里重点是介绍实践,不一定符合所有情况,供看者参考吧,
环境介绍:
WEB应用服务器:4CPU双核2G, 内存4G
  部署:Win2003/Apache Http Server 2.1/Tomcat6
数据库服务器:4CPU双核2G, 内存4G
  部署:Win2003/MSSQL2000
步骤:
步骤一:增加2台配置为:2CPU双核2G,内存2G普通服务器,做资源服务器
  部署:Tomcat6,跑了一个图片上传的简单应用,(记得指定web.xml的),并指定域名为 res1.***.com,res2.***.com,采用ajp协议
步骤二:修改Apache httpd.conf配置
  原来应用的文件上传功能网址为:
   1、/fileupload.html
   2、/otherupload.html
  在httpd.conf中增加如下配置

 
  ServerAdmin webmaster@***.com  
  ProxyPass /fileupload.html balancer://rescluster/fileupload lbmethod=byrequests stickysession=JSESSIONID nofailover=Off timeout=5 maxattempts=3     
  ProxyPass /otherupload.html balancer://rescluster/otherupload.html lbmethod=byrequests stickysession=JSESSIONID nofailover=Off timeout=5 maxattempts=3     
  #  
   
    BalancerMember ajp://res1.***.com:8009 smax=5 max=500 ttl=120 retry=300 loadfactor=100 route=tomcat1  
    BalancerMember ajp://res2.***.com:8009 smax=5 max=500 ttl=120 retry=300 loadfactor=100 route=tomcat2  
 
 
 

步骤三,修改业务逻辑:
  所有上传文件在数据库中均采用全url的方式保存,例如产品图片路径存成:http://res1.***.com/upload/20090101 /product120302005.jpg

现在,你可以高枕无忧了,带宽不够时,增加个几十台图片服务器,只需要稍微修改一下apache的配置文件,即可。

五:高并发高负载网站的系统架构之数据库集群和库表散列

大型网站都有复杂的应用,这些应用必须使用数据库,那么在面对大量访问的时候,数据库的瓶颈很快就能显现出来,这时一台数据库将很快无法满足应用,于是我们需要使用数据库集群或者库表散列。
  
  在数据库集群方面,很多数据库都有自己的解决方案,Oracle、Sybase等都有很好的方案,常用的MySQL提供的Master/Slave也是类似的方案,您使用了什么样的DB,就参考相应的解决方案来实施即可。
  
   上面提到的数据库集群由于在架构、成本、扩张性方面都会受到所采用DB类型的限制,于是我们需要从应用程序的角度来考虑改善系统架构,库表散列是常用并 且最有效的解决方案。我们在应用程序中安装业务和应用或者功能模块将数据库进行分离,不同的模块对应不同的数据库或者表,再按照一定的策略对某个页面或者 功能进行更小的数据库散列,比如用户表,按照用户ID进行表散列,这样就能够低成本的提升系统的性能并且有很好的扩展性。sohu的论坛就是采用了这样的 架构,将论坛的用户、设置、帖子等信息进行数据库分离,然后对帖子、用户按照板块和ID进行散列数据库和表,最终可以在配置文件中进行简单的配置便能让系 统随时增加一台低成本的数据库进来补充系统性能。


集群软件的分类:
一般来讲,集群软件根据侧重的方向和试图解决的问题,分为三大类:高性能集群(High performance cluster,HPC)、负载均衡集群(Load balance cluster, LBC),高可用性集群(High availability cluster,HAC)。
高性能集群(High performance cluster,HPC),它是利用一个集群中的多台机器共同完成同一件任务,使得完成任务的速度和可靠性都远远高于单机运行的效果。弥补了单机性能上的不足。该集群在天气预报、环境监控等数据量大,计算复杂的环境中应用比较多;
负载均衡集群(Load balance cluster, LBC),它是利用一个集群中的多台单机,完成许多并行的小的工作。一般情况下,如果一个应用使用的人多了,那么用户请求的响应时间就会增大,机器的性能也会受到影响,如果使用负载均衡集群,那么集群中任意一台机器都能响应用户的请求,这样集群就会在用户发出服务请求之后,选择当时负载最小,能够提供最好的服务的这台机器来接受请求并相应,这样就可用用集群来增加系统的可用性和稳定性。这类集群在网站中使用较多;
高可用性集群(High availability cluster,HAC),它是利用集群中系统 的冗余,当系统中某台机器发生损坏的时候,其他后备的机器可以迅速的接替它来启动服务,等待故障机的维修和返回。最大限度的保证集群中服务的可用性。这类系统一般在银行,电信服务这类对系统可靠性有高的要求的领域有着广泛的应用。
2 数据库集群的现状
数据库集群是将计算机集群技术引入到数据库中来实现的,尽管各厂商宣称自己的架构如何的完美,但是始终不能改变Oracle当先,大家追逐的事实,在集群的解决方案上Oracle RAC还是领先于包括微软在内的其它数据库厂商,它能满足客户高可用性、高性能、数据库负载均衡和方便扩展的需求。
Oracle’s Real Application Cluster (RAC)
Microsoft SQL Cluster Server (MSCS)
IBM’s DB2 UDB High Availability Cluster(UDB)
Sybase ASE High Availability Cluster (ASE)
MySQL High Availability Cluster (MySQL CS)
基于IO的第三方HA(高可用性)集群
当前主要的数据库集群技术有以上六大类,有数据库厂商自己开发的;也有第三方的集群公司开发的;还有数据库厂商与第三方集群公司合作开发的,各类集群实现的功能及架构也不尽相同。
RAC(Real Application Cluster,真正应用集群)是Oracle9i数据库中采用的一项新技术,也是Oracle数据库支持网格计算环境的核心技术。它的出现解决了传统数据库应用中面临的一个重要问题:高性能、高可伸缩性与低价格之间的矛盾。在很长一段时间里,甲骨文都以其实时应用集群技术(Real Application Cluster,RAC)统治着集群数据库市场

六:高并发高负载网站的系统架构之缓存

缓存一词搞技术的都接触过,很多地方用到缓存。网站架构和网站开发中的缓存也是非常重要。这里先讲述最基本的两种缓存。高级和分布式的缓存在后面讲述。
  架构方面的缓存,对Apache比较熟悉的人都能知道Apache提供了自己的缓存模块,也可以使用外加的Squid模块进行缓存,这两种方式均可以有效的提高Apache的访问响应能力。

   网站程序开发方面的缓存,Linux上提供的Memory Cache是常用的缓存接口,可以在web开发中使用,比如用Java开发的时候就可以调用MemoryCache对一些数据进行缓存和通讯共享,一些大型社区使用了这样的架构。另外,在使用web语言开发的时候,各种语言基本都有自己的缓存模块和方法,


适用scan检测,查看内存,CPU, IO适用情况。查看数据库链接有没有满,查看表有没有被长期锁定。

一个Web应用,不管是何种语言开发,粗略的结构无非是三层:
1. 页面模板
可以是JSP、ASP、PHP等页面技术,根据数据生成最终的 HTML页面,性能关键指标只有一个,页面的渲染速度。综合各种页面技术而言,渲染速度相差不会太大,10倍以内。

2. 业务逻辑
用于根据业务需要将数据库中的数据读取到内存中,以便通过页面模板渲染成HTML页面。这里面可能还包括缓存、连接池等技术。

3. 数据库
就是数据库,负责执行SQL查询并返回查询结果。

我们假设用户访问一个页面,也就是请求一个URL地址,然后得到内容,所需要的时间是3秒钟。其中大部分时间可能用在网络传输上,而真正页面执行并生成HTML内容所需的时间是很小的,这里假设需要100毫秒。

相当于用户花了两秒多钟在传输数据上,这部分时间如果能缩减,可以大大提升访问的速度,但是这部分一般也难以提升了,因为取决于用户本身的网络情况,服务器的网络情况以及中间整个路由的情况。对于一个网站来说,能做的就是尽可能的提升服务器的带宽,或者使用CDN来减少中间路由环节,很不幸的是,这个成本很高。

好吧,前面提到的更多是非技术因素,假设你已经耗费巨资解决了这个问题,然后突然发现网络太快了,可是服务器顶不住了,生成一个页面居然要100毫秒,才几十个并发用户就差点要把服务器搞崩溃了。

于是来到了本文的重点部分——找出应用的性能瓶颈。

前面我们提到的结构中的三层:页面模板,业务逻辑和数据库,根据经验值,在这100毫秒中,三个部分占用的时间差不多为:页面模板(5%)、业务逻辑+数据库(95%)。

几个准则:

1. 没必要去优化页面模板,这都是一些很成熟的技术,就算你好不容易提升了10%的性能,这10%在整个页面的执行过程中只占了0.5%的比例,微乎其微,等于是前面例子中的4车道变8车道的傻瓜,我们不要去充当傻瓜。

2. 一般瓶颈所在以及相应处理办法
    * 数据库连接:使用连接池来减少连接次数
    * 重复的数据库查询:使用缓存来避免重复的数据库查询
    * 慢查询:使用索引来提升查询速度,使用连接查询替换子查询等

简简单单的三条,里面却包含了很深的功夫,特别是在数据库查询优化上。

你必须在充分解决了这些应用程序所属的性能瓶颈之后,再去考虑系统级别的优化。

一些常用系统级别优化包括:

1. 静态文件和动态页面分开处理 .JS/CSS文件压缩。前台的gzip技术,页面的缓存技术
2. 应用服务器的集群
3. 数据库的集群 EXPLAIN 看看 SQL 语句,是否使用上了索引。

不要本末倒置,一个性能很差的应用程序,你就算集群了100个节点,也不会有什么效果。

所以Web网站优化三部曲:应用程序优化、系统结构优化、网络优化。

时常看到高并发的问题,但高并发其实是最不需要考虑的东西。为何,他虚无缥缈,很少有网站真的需要这些东西,而且其中很多技术,其实你已经在用了。有这个意识就够了,不需要时刻盯着这个问题。只有很少的网站真的能达到高并发。

简单做一个归纳,从低成本、高性能和高扩张性的角度来说有如下处理方案:
  1、HTML静态化
  2、图片服务器分离
  3、数据库集群和库表散列
  4、缓存
   5、镜像
   6、负载均衡;一个典型的使用负载均衡的策略就是,在软件或者硬件四层交换的基础上搭建squid集群,这种思路在很多大型网站包括搜索引擎上被采用,这样的架构低成本、高性能还有很强的扩张性,随时往架构里面增减节点都非常容易。

下面也是一个总结,跟上面部分相同。
高并发时,性能瓶颈及当前常用的应对措施


1.数据库瓶颈。Mysql并发链接100

2.apache 并发链接1500

3.程序执行效率



1.有数据库瓶颈时,当前处理方案无外乎 主从,集群。增加cache(memcached).

如:手机之家新系统介绍及架构分享(http://www.slideshare.net/Fenng/ss-1218991?from=ss_embed)

就是在cache层做优化

又拍网架构(http://www.bopor.com /?p=652)

是以增加数据库,分表分库的方法解决。

Sina增加了mq(消息队列)来分发数据。

还有风站用了key-value的数据库。其实这可以理解成一个持久化的缓存。



2.apache瓶颈。

增加服务器。负载均衡。如sina的F5

由于进程数的限制。会把一些基本不变的代码挪出来放到单独的服务器。如css/js/图片。

国内成功的案例是tom的cdn


又如nginx的横空出世和squid的反向代理都是基于这个原因出来的。


3.php的执行效率。原因有多个。

1).本身的效率低。

解决的成功案例是Zend Optimizer 和 facebooke的hiphop

Taobao是把php代码编译成模块解决效率问题。

2). 数据库查询效率问题。如可能有order by ,group by 等Sql数据问题。

这个其实应该归结到数据库设计问题。


解决的办法是建立正确的索引。增加memcache.。

对like表 用专用的sphinx.和lucence 等搜索服务。

程序员都应该会用explain对sql语句作分析。

性能测试的概念是什么,基本目的是什么,我想大家都基本清楚,不作详述,总之,性能测试只是测试过程中的一种方式,帮助我们的功能更好的运行,如果功能测试是可用,易用,满足需求、用户使用为目的,性能测试无非就是让这些目的更流畅。没有什么专业的概念,无非实现两个字:好用!

  所以,性能测试这种测试方式在发生过程中,其中一个过渡性的工作,就是对执行过程中的问题,进行定位,对功能的定位,对负载的定位,最重要的,当然就是问题中说的“瓶颈”,接触性能测试不深,更非专家,自己的理解,瓶颈产生在以下几方面:

  1、网络瓶颈,如带宽,流量等形成的网络环境。

  2、应用服务瓶颈,如中间件的基本配置,CACHE等。

  3、系统瓶颈,这个比较常用:应用服务器,数据库服务器以及客户机的CPU,内存,硬盘等配置。

  4、数据库瓶颈,以ORACLE为例,SYS中默认的一些参数设置。

  5、应用程序本身瓶颈。

  以上几方面分别唠叨几句。

  针对网络瓶颈,现在冒似很少,不过也不是没有,首先想一下如果有网络的阻塞,断网,带宽被其他资源占用,限速等情况,应用程序或系统会是什么情况,针对WEB,无非是超时,HTTP400,500之类的错,针对一些客户端程序,可能也是超时,掉线,服务器下发的,需要服务器返回的信息获取不到还有一种更明显的情况,应该就是事务提交慢,如果封装事务的代码再不完善,一般造成的错误,无非就是数据提交不完整,或者因为网终原因+代码缺陷造成重复性提交。如此综合下来,肯定是考虑网络有瓶颈,然后考虑网络有问题时,怎样去优化,是需要优化交互的一些代码,还是接口之类的。

  应用服务的瓶颈的定位,比较复杂,学习中,不过网上有很多资料可以参考的。一般像tomcat,weblogic之类的,有默认的设置,也有经过架构和维护人员进行试验调试的一些值,这些值一般可以满足程序发布的需要,不必进行太多的设置,可能我们认识的最基本的就是JAVA_OPTS的设置,maxThreads,time_out之类的参数我们做借助LR,Jemeter或webload之类的工具,执行性能测试,尤其是对应用服务造成了压力,如果应用服务有瓶颈,一般我们设置的log4j.properties,日志都会记录下来。然后根据日志,去进一步确定应用服务的问题。

  系统瓶颈,这个定位虽说比较复杂,但是有很多前辈的经验值参考,不作说明,相信用LR的同行,也可以从性能记数器中得出一些指标值,加上 nagios,cacti,可以很明显的看出系统哪些资源够用,哪些资源明显不够用。不过,一般系统瓶颈的造成,是因为应用程序本身造成的。关于这点儿的分析和定位,就需要归入应用程序本身瓶颈分析和定位了。

  现在基本所有的东东,都离不开数据库这个后台,数据库的瓶颈实在是不知道是什么概念,数据库管理员的工作,数据库管理员日常做的工作,可能就是有瓶颈定位的工作,比如:查询一下V$sys_event,V$sysstat,v$syssql之类的表,比对一下日常正常情况下的监控数据,看一下有没有异常等。其他方面,我也不是太了解。

  应用程序瓶颈,这个是测试过程中最需要去关注的,需要测试人员和开发人员配合执行,然后定位,我这儿做的大都是执行性的,比如会有脚本去运行,开发人员会结合jprofiler之类的工具,去看一下堆遍历,线程剖析的情况确定哪儿有问题。大致是这样,没有实际操作过。

  ------------------------------------

  逐步细化分析,先可以监控一些常见衡量CPU,内存,磁盘的性能指标,进行综合分析,然后根据所测系统具体情况,进行初步问题定位,然后确定更详细的监控指标来分析。

  怀疑内存不足时:

  方法1:

  【监控指标】:Memory Available MBytes ,Memory的Pages/sec, page read/sec, Page Faults/sec

  【参考值】:

  如果 Page Reads/Sec 比率持续保持为 5,表示可能内存不足。

  Page/sec 推荐00-20(如果服务器没有足够的内存处理其工作负荷,此数值将一直很高。如果大于80,表示有问题)。

  方法2:根据Physical Disk 值分析性能瓶颈。

  【监控指标】:Memory Available MBytes ,Pages read/sec,%Disk Time 和 Avg.Disk Queue Length

  【参考值】:%Disk Time建议阈值90%

  当内存不足时,有点进程会转移到硬盘上去运行,造成性能急剧下降,而且一个缺少内存的系统常常表现出很高的CPU利用率,因为它需要不断的扫描内存,将内存中的页面移到硬盘上。
怀疑内存泄漏时

  【监控指标】:Memory Available MBytes ,Process\Private Bytes和Process\Working Set,PhysicalDisk/%Disk Time

  【说明】:

  Windows资源监控中,如果Process\Private Bytes计数器和Process\Working Set计数器的值在长时间内持续升高,同时Memory\Available bytes计数器的值持续降低,则很可能存在内存泄漏。内存泄漏应该通过一个长时间的,用来研究分析当所有内存都耗尽时,应用程序反应情况的测试来检验。

  CPU分析

  【监控指标】:

  System %Processor Time CPU,Processor %Processor Time CPU

  Processor%user time 和Processor%Privileged Time

  system\Processor Queue Length

  Context Switches/sec 和%Privileged Time

  【参考值】:

  System\%Total processor time不持续超过90%,如果服务器专用于SQL Server,可接受的最大上限是80-85% ,合理使用的范围在60%至70%。

  Processor %Processor Time小于75%

  system\Processor Queue Length值,小于CPU数量的总数+1

  CPU瓶颈问题

  1、System\%Total processor time如果该值持续超过90%,且伴随处理器阻塞,则说明整个系统面临着处理器方面的瓶颈。

  注:在某些多CPU系统中,该数据虽然本身并不大,但CPU之间的负载状况极不均衡,此时也应该视作系统产生了处理器方面的瓶颈。

  2、排除内存因素,如果Processor %Processor Time计数器的值比较大,而同时网卡和硬盘的值比较低,那么可以确定CPU 瓶颈。(内存不足时,有点进程会转移到硬盘上去运行,造成性能急剧下降,而且一个缺少内存的系统常常表现出很高的CPU利用率,因为它需要不断的扫描内存,将内存中的页面移到硬盘上。)

  造成高CPU使用率的原因:

  频繁执行程序,复杂运算操作,消耗CPU严重。

  数据库查询语句复杂,大量的 where 子句,order by, group by 排序等,CPU容易出现瓶颈。

  内存不足,IO磁盘问题使得CPU的开销增加

  磁盘I/O分析

  【监控指标】:PhysicalDisk/%Disk time,PhysicalDisk/%Idle Time,Physical Disk\ Avg.Disk Queue Length, Disk sec/Transfer

  【参考值】:%Disk Time建议阈值90%

  Windows资源监控中,如果% Disk Time和Avg.Disk Queue Length的值很高,而Page Reads/sec页面读取操作速率很低,则可能存在磁盘瓶径。

  Processor%Privileged Time该参数值一直很高,且如果在 Physical Disk 计数器中,只有%Disk time 比较大,其他值都比较适中,硬盘可能会是瓶颈。若几个值都比较大, 那么硬盘不是瓶颈。若数值持续超过80%,则可能是内存泄露。如果 Physical Disk 计数器的值很高时该计数器的值(Processor%Privileged Time)也一直很高, 则考虑使用速度更快或效率更高的磁盘子系统。

  Disk sec/Transfer 一般来说,该数值小于15ms为最好,介于15-30ms之间为良好,30-60ms之间为可以接受,超过60ms则需要考虑更换硬盘或是硬盘的RAID 方式了。

  ---------------------------------------------

  Average Transaciton Response Time(事务平均响应时间)随着测试时间的变化,系统处理事务的速度开始逐渐变慢,这说明应用系统随着投产时间的变化,整体性能将会有下降的趋势。
Transactions per Second(每秒通过事务数/TPS)当压力加大时,点击率/TPS曲线如果变化缓慢或者有平坦的趋势,很有可能是服务器开始出现瓶颈。

  Hits per Second(每秒点击次数)通过对查看“每秒点击次数”,可以判断系统是否稳定。系统点击率下降通常表明服务器的响应速度在变慢,需进一步分析,发现系统瓶颈所在。

  Throughput(吞吐率)可以依据服务器的吞吐量来评估虚拟用户产生的负载量,以及看出服务器在流量方面的处理能力以及是否存在瓶颈。

  Connections(连接数)当连接数到达稳定状态而事务响应时间迅速增大时,添加连接可以使性能得到极大提高(事务响应时间将降低)。

  Time to First Buffer Breakdown(Over Time)(第一次缓冲时间细分(随时间变化))可以使用该图确定场景或会话步骤运行期间服务器或网络出现问题的时间。

  碰到过的性能问题:

  1. 在高并发的情况下,产生的处理失败(比如:数据库连接池过低,服务器连接数超过上限,数据库锁控制考虑不足等)。

  2. 内存泄露(比如:在长时间运行下,内存没有正常释放,发生宕机等)。

  3. CPU使用偏离(比如:高并发导致CPU使用率过高)。

  4. 日志打印过多,服务器无硬盘空间。

  如何定位这些性能问题:

  1. 查看系统日志,日志是定位问题的不二法宝,如果日志记录的全面,很容易通过日志发现问题。

  比如,系统宕机时,系统日志打印了某方法执行时抛出out of memory的错误,我们就可以顺藤摸瓜,很快定位到导致内存溢出的问题在哪里。

  2. 利用性能监控工具,比如:JAVA开发B/S结构的项目,可以通过JDK自带的Jconsole,或者JProfiler,来监控服务器性能,Jconsole可以远程监控服务器的CPU,内存,线程等状态,并绘制变化曲线图。

  利用Spotlight可以监控数据库使用情况。

  我们需要关注的性能点有:CPU负载,内存使用率,网络I/O等。

  3. 工具和日志只是手段,除此之外,还需要设计合理的性能测试场景。

  具体场景有:性能测试,负载测试,压力测试,稳定性测试,浪涌测试等。

  好的测试场景,能更加快速的发现瓶颈,定位瓶颈。

  4. 了解系统参数配置,可以进行后期的性能调优。

  除此以外,还想说个题外话,就是关于性能测试工具的使用问题。

  在刚开始用Loadrunner和JMeter的时候,做高并发测试时,都出现过没有把服务器压垮,这两个程序自己先倒下的情况。

  如果遇到这个问题,可以通过远程调用多个客户端的服务,分散性能测试工具客户端的压力来解决。

  说这个的目的是想说,做性能测试的时候,我们一定要确保瓶颈不要发生在我们自己的测试脚本和测试工具上。

岑文初:模块化来降低耦合性时如何把握模块划分的粒度?如何权衡复用性与粒度过细导致依赖复杂的矛盾?

杨海朝:耦合性是影响软件系统复杂程度和设计质量的重要因素,模块化设计的目标是建立模块间耦合度尽可能松散的系统,通过尽量使用数据耦合,少用控制耦合,限制公共耦合的范围和一定要避免使用内容耦合来降低接口的复杂性。

在系统架构中模块化设计对于降低耦合性有非常重要的作用,相关的功能合在一起,不相关的功能分离开来。

模块划分的粒度决定着最终划分结果的合理性和有效性。模块划分的粒度越细,越易于定义和开发,但随着模块数的增加,模块之间的接口也随之增加,使得各个模块在组装成系统消耗的时间增加,同时加大了整个系统测试的复杂度。模块划分的粒度越粗,越有利于整个系统的组装,整个系统的测试复杂度也降低,但整个系统的灵活性下降,难以满足用户对系统的多样性需求。岑文初

模块划分的粒度是一个不太容易把握的问题,不同的产品和项目有不同的划分粒度方法。模块化的粒度需要根据模块的三大特征(相对独立性、互换性、通用性)来把握。每个模块的聚合度越高,耦合性就越低,反之亦然。在做模块划分时,应使模块之间尽可能独立,块内联系尽可能大,块间联系尽可能小,功能模块逐层分解和细化,直至形成若干容易编写的模块。同时还需要结合模块的功能、模块的规模、模块的出入口等诸多因素综合考虑。模块划分的粒度越小,通用范围广,可在较多应用进行复用,但其较小的粒度组装过程烦琐,会导致复用效率降低。反之,模块划分的粒度越大,组装的步骤越少,可复用效率越
高,但其复用范围受到限制。

岑文初:如何处理高并发系统中缓存失效的场景?回答嘉宾杨海朝

杨海朝:从硬件到操作系统,从系统软件到应用软件,我们随处都可以看到缓存的身影。缓存在Web2.0网站中发挥着越来越重要的作用,特别是大流量的高并发系统。缓存在带来性能提升和支持高并发的同时,也带来另一个问题,如果缓存宕机导致所有的缓存失效,所有的流量都压到后端的服务上,例如数据库层。这时,后端服务因为压力过大无法提供服务或快速响应,缓存因为等待后端请求的响应而“热”不起来,最终导致“雪崩” 问题。在高并发系统中,解决缓存失效有以下三个思路。

使用Consistent Hashing算法。把数据缓存分片,减少缓存宕机对服务的影响范围。 Consistent Hashing能最大限度地抑制Hash键的重新分布,同时要取得比较好的负载均衡的效果,需要在服务器数量比较少时,增加虚拟节点来保证服务器能均匀地分布在圆环上,最大限度地减小服务器增减节点时产生的缓存重新分布问题。

缓存多份。通过应用写多份缓存,或应用写一份缓存由中间件把此份缓存复制多份,在缓存宕机时能切换到另一份缓存上,减少缓存宕机对后端数据存储的影响。这种方式最好采用缓存之间的复制,减少应用开发的复杂度。

解决高并发系统中的缓存失效问题,需要结合业务逻辑进行综合考虑。

实现缓存持久化或半持久化。所谓的持久化就是定期把缓存里面的数据刷到磁盘,保存起来,在缓存失效时能保证大部分数据仍然有效,例如使用Redis或MemcacheDB把一些数据存到磁盘。可能有人会说:“是否在刷磁盘那一刻会影响缓存的高效性?”这可以考虑通过高端硬件(例如Fushion IO或SSD作为存储设备),来减少刷Cache过程中减少对服务的影响。

这些仅仅是实现的三个思路,各有利弊。解决高并发系统中的缓存失效问题,需要结合业务逻辑进行综合考虑。

岑文初:目前是如何做好应用的依赖监控的?例如依赖缓存,是否知道缓存的命中率情况、使用率等;依赖外部服务,是否知道外部服务的消耗时间、成功失败情况等。

杨海朝:应用监控日益成为保障系统安全运行不可或缺的工具,在提高系统可用率和故障的预警能力、最大限度地缩短故障修复时间方面,日益显示出其重要程度。

此外,对应用依赖的服务的监控也非常重要,目前可以建立一整套监控体系,这套监控体系不仅监控应用自身,同时也对外部服务进行监控。应用在调用依赖服务时,打印应用调用的详细日志,记录调用的返回时间,以及成功与否,同时要求外部或依赖服务提供一个统一的接口,用来返回每次调用消耗的时间以及失败率。通过对这些日志的实时分析来发送邮件和短信报警。

岑文初:系统是否有对内或者对外提供服务,如何管理服务的使用权限,如何做服务升级?

杨海朝:在系统中服务的使用权限至关重要,特别是既提供对内服务又提供对外服务的系统。

目前管理服务的使用权限,设置白名单是最简单的方式。通过设置白名单,只有在白名单里面的用户和来源IP才能访问服务,其他的都无权访问。外部调用服务也通过使用appkey的方式,简单地说是API接口的钥匙,只有通过这个钥匙才能打开API的大门,从而获取数据,同时对appkey的申请设置一系列流程来保证其安全性。根据这些appkey来设置不同的权限等级,控制对目标数据的访问以及调用频率。

通过使用Gearman系统进行“热”升级。在负载均衡设备的后端增加一个代理层,升级时通过对代理层的心跳探测页面修改,把落到这台机器上的流量切走,然后对这台机器进行升级,升级完之后进行测试,测试完成之后,再对某一区间机器进行升级,在某一个时间内测试没有问题,再对其他所有区间进行升级。提前准备好回退机制,保证每次升级对用户的影响最小,力求达到无缝升级。

岑文初:对于不同系统之间的耦合如何处理?比如前端系统要求快速响应大量的用户请求,但是依赖于后端的服务体系,而服务系统的瓶颈可能在数据库读写上,如何协同这样需求差异化系统工作?

杨海朝:不同系统之间的耦合性是指各个系统之间的互相依赖程度。需要熟悉各种耦合性的特性,为不同的系统之间选择合适的耦合性。

如果系统之间采用紧耦合,那么涉及对象与对象的直接通信,这些对象通常比在松耦合系统中交互更为频繁。假如两个对象位于不同系统中并且由不同的网络分开,则会导致性能和延迟问题。

如果系统之间采用松耦合以及基于消息的架构,客户端和服务端不需要知道对方如何实现。两端的消息协议符合协商,则客户端或服务器端的实现就可以根据需求进行变更,而不会互相影响。

松耦合提供了紧耦合所不能提供的许多优点,并且它有利于降低客户端和服务端之间的依赖性。例如采用异步策略。对于需要快速响应的系统,尽可能把过程变成异步的,减少请求者所经历的响应延时。如果系统A同步调用系统B,那么A和B是紧密耦合,而紧耦合的系统是需要共同进退,两个系统需要承担相同的量,并且如果B不可用,则A也不可用。如果系统A和系统B之间是异步的方式,不管是通过消息队列、多播消息、批处理还是其他实现方式,那么系统A和系统B是相互独立的,如果B宕机,A仍然能够继续提供服务,也即所谓的优雅降级策略。这种异步策略能把高并发的写入高峰变成一个平缓的写入速率,减少了硬件的部署成本,同时可以控制消息队列的写入速度以及优化队列来避免后端服务出现压力过高问题。

岑文初:对于系统优化,平时如何查找瓶颈,最后又如何确定优化后是有效的?可以的话请举例说明。

杨海朝:系统上线,首先对系统进行必要的压力测试,量化能承担的最大量。通过对客户端性能指标和非客户端性能指标进行收集,对系统的响应时间、并发用户数、吞吐量、硬件资源的表现等这些关键点进行分析,最终找到系统的性能瓶颈。

同时通过这些压力测试,确定系统在访问量不端增加时,可能出现瓶颈的组件。压力测试过程中输出详细的日志信息,然后对日志信息进行整理,分析各种组件的性能表现情况。

对于已经在线的系统,要部署好各种状态监控系统,最好以图形化的方式呈现出来。在出现性能瓶颈时,能通过这些状态监控信息,找到性能瓶颈点或将性能瓶颈缩短在一定的范围之内,然后对线上系统按逻辑功能进行划分,例如静态池、动态池、缓存层、数据库服务。修改每个功能模块以便输出详细的日志信息,对这些日志信息进行整理和分析,找到瓶颈所在,同时记录各个功能块的性能表现,在优化后,收集相同信息进行对比来确定优化前后的性能差别。对于单个模块可以通过一些
性能分析工具来对程序的性能进行分析,例如Rational Quantify。

下面以数据库的瓶颈分析为例。

    * 收集一天内所有的SQL语句,以及统计每种类型的语句占的比例。

    * 收集当前系统中CPU、内存、硬盘I/O的表现情况,分析硬件资源瓶颈。

    * 收集满日志并对其进行分析整理。

    * 确定每条SQL语句在数据库中的平均执行时间。

    * 对执行效率低、消耗硬件资源、响应慢并且频繁调用的SQL语句进行优化。

    * 将收集优化后的硬件资源表现情况和之前进行对比,最终量化优化提高的比例。

总之对于不同的系统,寻找性能瓶颈的步骤可能会有所不同,但都离不开对关键数据的收集和分析。


这是通过httpwatch检测得出来的,页面传输内容的大小为652154Byte,请求数为149次,也就是说加载一次页面就大概需要请求这么多次请求,传输这么大的内容,当然这里剔除缓存机制来分析的。

  场景设计:

  1、并发用户200

  2、每20秒加载10个用户

  3、全部用户加载完成之后,持续运行10分钟

  监控目标:TPS、响应时间、点击率、吞吐率、内存、CPU和网络带宽


那么性能是什么呢,性能是特定功能占用的时间和资源。他可以是功能的开销或者是同步运行功能的数目。Web性能测试就是模拟大量用户操作给网站造成压力,并评测web系统在不同负载和不同配置下能否达到已经定义的标准。性能测试更加关注分析和消除与软件结构中相关联的性能瓶颈。

  性能是每个软件系统必须考虑的指标,在性能测试中我们通常注意以下四方面数据:一、负载数据;二、数据流量;三、软件本身消耗资源情况;四、系统使用情况。由于性能测试的特殊性,一般情况下都是利用特殊的测试工具(如LoadRunner,TestManager,ACT 等)模拟多用户操作,对需要评测的系统造成压力。找出系统的瓶颈,并提交给开发人员进行修正。所以性能测试的目的是找出系统性能瓶颈并纠正需要纠正的问题。

  制定WEB性能测试的策略可以遵循对系统中最重要的模块,经常使用的模块,系统开销最大的地方(代码最复杂的部分),对用户来说最重要的部分进行测试。我们从整体的角度分析一下性能可能出现问题的地方,作为web程序不管是两层,还是多层系统架构的程序。系统都是通过http协议(超文本传输协议(HypertemxTransferProtocol,HTTP)是一个“请求-回应”的应用协议,这个协议支持一套固定的方法如 Get,Post,Put,Delete等)来传输数据,发送命令。中间的过程大致为客户端(浏览器)发送数据操作请求给服务器,服务器接收命令请求后进行处理,然后把结果返回给客户端,客户端处理响应结果。这个过程中客户端发送请求进行数据处理的过程一般不是系统的性能瓶颈,这个时候一般是大量用户同时操作,发送数据请求才是系统的瓶颈。系统的服务器硬件资源最有可能是软件系统的瓶颈。我们需要调整软件和环境(最优化响应时间和资源),确认应用和系统可以处理的高负载和压力条件。而这个时候系统硬件中最可能的是cpu造成的瓶颈。系统中其他硬件资源所造成的瓶颈,我们可以替换相应的硬件资源,进行调整。而系统中另一个瓶颈可能是服务器把处理数据发送给客户端,这个过程硬件资源就不可能是性能的限制因素,最有可能是带宽的原因。

  其实性能的问题大多数情况下是由于软件体系结构或设计不合理造成的,而不是编码引起的。如果在性能测试中发现CPU占用率居高不下,内存占用异常,经常报错的情况问题的时候,排除上边分析的原因外,应及时提交情况汇总给开发人员,让开发人员察看代码中出错环节是否有死循环等逻辑错误,检查应用部署后所使用的数据连接驱动是否有误或者代码未及时更新,查看数据库查询或者其他语句是否有异常,中断测试,只运行响应时间最长的页面并验证结果。分析系统可能的性能瓶颈。

  我们需要在测试中注意不同的带宽条件对测试结果所造成的结果,所以应该在性能测试前要制定系统性能标准,这样才能合理分析测试结果。把不同带宽的测试结果进行分析量化,找到测试系统瓶颈。

  一般性能测试中最常见的基本类型为基准测试,配置测试,负载测试,压力测试,我们知道在软件测试的过程中,不同阶段,不同类型所进行的性能测试关注测试目标是不同的,不同软件架构也决定了性能测试存在差异。这样就要对所进行的测试类型有一定的了解,才能更好的进行性能测试工作。下边是各种测试类型的具体概念:

  基准测试——把新服务器或者未知服务器的性能和已知的参考标准进行比较

  配置测试——确认服务器在不同的配置下性能的可接受性。(操作条件不变)

  负载测试——确认服务器在不同的负载条件下性能的可接受性。(操作条件不变)

  压力测试——确认服务器在异常或者极限的条件时性能的可接受性,例如,减少资源或大数量的用户。

  竞争测试——确认服务器可以处理多个客户对同一个资源的请求竞争

  通过系统基准测试提供的一定条件下服务器如何处理数据的基线,作为评估其他性能指标的参考数据起点。进行配置测试则是测试系统配置在不同的机器上能否正常运行。用配置测试来确保系统在多个平台上正常运行。而负载测试用来测试在不同负载条件下客户端或者服务器端的响应时间。帮助测试人员计算在限定时间内服务器响应处理的请求的最大数量的事务数。压力测试则是在极限条件下运行系统的过程,检查什么条件下服务器或者客户端崩溃。竞争测试则是在一台或者多台pc 上操作系统功能来模拟实际环境。

  部分测试人员可能面对的是一个已经发布的Web系统,这种情况如何进行性能测试呢。在没有进行测试之前,可以通过网站的管理人员收集测试数据,为以后进行性能测试做好准备,收集的信息包括每小时在线用户数量,平均每小时的在线用户数量,不同时段的在线用户峰值比较,收集被访问次数最多的的页面,系统正常运行时CPU的使用率。所有这些作为性能测试的依据,避免盲目进行性能测试。在不了解系统的真实情况下进行的性能测试,很可能是错误的测试。把过多的精力放在了错误的地方。那样测试结果就不具有真实性,并且会浪费大量的测试资源。

  而对于一个开发中的 web系统进行性能测试,就要根据开发目标和用户需求在体系结构的迭代过程中,不断调整测试目标,对系统性能有个很好的评估。那么如何才能成功的进行性能测试呢,我觉得进行性能测试前应有一个测试计划,这样才能保证性能测试有序的进行。下边给出了性能测试的一般步骤:

  ● 评估系统:在这个阶段,主要是明确确定系统期望目标,包括:确定系统功能,确定用户活动,确定系统架构,确定可接受的极限,验证可接受的极限,确定系统风险等。

  开发测试资源:进行性能测试的资源,主要覆盖三种活动:开发风险减低计划,开发测试策略,开发自动化脚本。

  ● 执行基准测试:利用基线对比将来的测试结果对系统评估负载,压力,竞争测试结果中的相关性能。主要通过压力场景验证自动化测试脚本的正确性。在测试周期早期中标示可见的性能指标。性能工程包括个体脚本基线,建立初始化基准。

  ● 分析测试结果:对结果进行分析是为了决定是否对系统继续进行测试,是否结果达到了期望值。这个阶段包含评估结果,确定是否是可接受的极限,确定是否继续进行测试,确定需求调整。

  ● 预定测试:强制验证系统性能,这些测试是必须执行的即使性能和需求都没有调整的情况下。它包含执行用户体验测试,执行稳定性测试,执行产品确认测试等活动。

  ● 结束测试:实际工作中由于软件架构和其他资源限制,软件无法继续优化,此时建议将测试资源转移,测试其他方面,避免测试资源浪费。
http://www.51testing.com/html/37/n-807737.html

http://www.51testing.com/html/11/n-808911.html
http://www.51testing.com/?uid-330435-action-viewspace-itemid-809969

http://www.51testing.com/?uid-70522-action-viewspace-itemid-809005

http://www.51testing.com/html/80/n-809880.html

http://www.51testing.com/html/92/n-809592-2.html



你可能感兴趣的:(技术)