大型网站技术架构之性能

1.1 网站性能测试

1.1.1 用户视角下的网站性能

用户在浏览器上直观感受的网站响应色度的快慢,用户感受到的时间,包括用户计算机和网站服务通信的时间,网站服务处理的时间,用户浏览器构造请假解析响应的时间。浏览器,带宽的不同直接影响用户感受

1.1.2 开发人员视角的网站性能

  响应延迟,系统吞吐量,并发处理能力,系统稳定性。主要手段是使用缓存加速数据读取,使用集群提高吞吐能力,使用异步消息加快请求响应及实现削峰,代码优化改善程序性能。

1.1.3 运维人员视角的网站性能

基础设施的性能,资源利用率,带宽,服务器硬件配置,数据中心网络架构,主要优化手段是建设优化骨干网,使用高性价比订制服务器,利用虚拟化技术优化资源利用率。

1.2 网站性能指标

1.2.1 响应时间

指应用执行一个操作需要的时间,包括从发出请求开始到收到最后请求所需的时间。响应时间是系统性能的重要指标,直观的反应了快慢。重复请求/请求数会得到响应时间

1.2.2 并发数

指系统能够同时处理请求的数目,对于网站而言,并发数即网站并发的用户数据,同时提交请求的用户数目。

一般而言 网站系统用户数目>网站在线用户数目>网站并发用户数目。

在产品设计初期,产品经理与运营人员就需要规划不同发展阶段的网站系统用户数,并已此为基础,根据产品特性和运营手段,推算在线用户数和并发用户数,这些指标将成为系统功能设计的重要依据。

现实中比如电商网站在活动促销的时候,由于并发用户数量过高,超过了网站的最大负载能力,所以响应速度会相对比较慢,客户等不急救疯狂的进行刷新,导致并发数更高,最后以服务器系统崩溃,用户浏览器显示”service is too busy” 而告终。出现这种情况原因就在于网站技术准备不充足,也可能是运营人员错误的评估了用户数导致的。

测试人员通过多线程模拟并发用户的办法来测试系统的并发能力,为了真实的模拟用户行为,测试程序并不是启动多线程不停的发送请求,而是在每两次请求之间加入一个随机等待时间,这个时间被称作思考时间

1.2.3 吞吐量

单位时间内系统处理请求的数量,体现系统的整体处理能力。可以用 “请求数/秒”

“页面数/秒”来衡量。也可以用 “访问人数/天”或者“处理业务数/小时”来衡量。

一般比较公认的吞吐量计量单位是 TPS(每秒处理的用户数),HPS(每秒处理请求数),QPS(每秒查询数)等等。

这个过程中系统吞吐量与相应时间的关系,系统吞吐量和响应时间,先是小幅度的提升,到达吞吐量极限用,系统吞吐量不增返回下载,响应时间快速上升,到达系统崩溃的点的时候,系统资源耗尽,系统吞吐量为零,失去响应。

用一个形象的例子来说明系统吞吐量(收费站费用),响应时间(车速),与请求数(车量)的关系。就像我们的高速公路上行车一样,请求数就等价于车辆,车辆少的时候,车速快,收费站收的费不多。随着车辆的增加,车速慢下来了,收费站收费增多。车辆再增加,车速更慢了,收费站的费用不增,反而因为堵车而下降了。当堵车太久,导致交通瘫痪的时候,收费站停止了收费,车也不行走了。所以网站性能优化应该提高系统吞吐量,最大限度的利用服务器资源。

1.2.4 性能计数器、

  System Load即系统负载,指当前正在被cpu执行或者等待CPU执行的进程数目的总和。 是反应系统忙闲程度的重要指标。完美情况是所有CPU都在使用,没有进程在等待。linux中使用top命令可以查看进程等待数。该值是三个浮点数表示1分钟,10分钟,15分钟的平均进程数。

1.2.5 性能测试方法

1.2.5.1性能测试

以系统初期设计规划的性能指标为目标,对系统不断施加压力,验证系统资源是否在可接受的范围内,是否达到性能预期的目标。

1.2.5.2负载测试

对系统不断的增加并发请求以增加系统压力,直到系统的某项或者多项性能达到安全临界值。如某种资源已经呈饱和状态,这时对系统不断施加压力,系统的处理能力不但没有提高,反而下降。

1.2.5.3压力测试

超过安全负载的情况系,对系统继续施加压力。直到系统崩溃不能再处理任何请求,以此获得系统最大压力承受能力。

1.2.6 稳定性测试

 特定硬件,软件,网络环境条件下,给系统加载一定的业务压力。使系统运行一段较长的时间,以此检测系统的稳定性。

1.2.6.1 并发用户吞吐量曲线

如上图所示纵坐标表示系统的吞吐量,随着并发数据的不断增加,刚开始的时候就像在a~b这个区间里,系统的吞吐量会不断的增大,在b点的时候增大到我们设计的逾期目标,此时我们已经完成了性能测试。这个时候随着并发数量的继续增大,系统的吞吐量的增长逐渐放缓慢,直到达到如上图所示的c点最大值点,这是系统的最大负载点,也成为负载测试点。再次随着并发数量的不断增大系统的吞吐量不增返回下降了,直到达到资源的崩溃点d点,此时称为压力测试点。

1.2.6.2 并发用户响应时间曲线

随着并发用户的不断增长,系统的处理能力与用户访问的等待时间如上图所示,等待的响应时间将成一个线性平方阶的增长。

如上图所示是一个性能测试报告样例,随着并发数目的增长可以看出各个阶段的测试结果。

1.3网站性能优化

性能问题分析,先看处理的各个环节的日志,分析哪个环节响应的时间不合理,超过了逾期。性能因素先从内存,磁盘,网络,cpu入手,看是资源不足,还是代码设计不合理。

1.3.1 web前端性能优化

1.3.1.1减少http请求

手段有合并CSS,合并js,合并图片。通过把浏览器一次访问请求的多个CSS文件,JS文件合并成一个,减少页面端的请求加载。通过把多个图片合并成一个进行请求,再通过CSS来偏移鼠标点击操作,响应用户的请求。使用浏览器缓存策略的网站,如果要更新10个图片,不宜一次更新,10个图标文件,而应逐个更新,避免缓存失效,批量更新给服务器造成负载棸增,网络堵塞的情况。

1.3.1.2启用压缩

在服务器断对文件进行压缩,在浏览器断对文件进行解压,对CSS,HTML.javascipt启用gzip的压缩策略,进行压缩。

1.3.1.3 css放上面,js放在下面

浏览器加载完整个CSS后会对网页进行渲染,最好的做法是将css放在上面。让浏览器尽快下载CSS,最快的速度给用户渲染静态页面。js则与之相反。js加载完以后会立即执行,造成页面加载缓慢,所以要放在页面的底部。

1.3.1.4减少cookies的数据传输。

由于再发送请求的时候,浏览器会带上cookies进行传输,网络传输过程中由于cookies中携带了大量的数据,所以哪些数据应该写入cookies中应该慎重进行考虑。减少cookies中数据量的传输。另一方面,对于静态资源的访问,发送cookies是没有意义的。所以尽量使用动静分离的技术,把静态资源的请求域名,与动态数据请求的域名分开,减少cookies的传输次数。

1.3.1.5使用浏览器缓存

对于一个网站而言,css,js,图片,logo等的静态资源更新的频率比较低。而这些文件几乎是每次http请求都需要的,通过设置httpcache-controlexpires属性,可以设定缓存,并且指定缓存的失效时间,失效天数。如果某个js文件有更新,就更新js文件的名字重新生成js,并更新html的引用。

1.3.1.6使用CDN加速

cdn本质上是一个缓存,把数据缓存在离用户访问最近的地方,可以使用户以最快的速度获取到缓存。

cdn可以缓存一些静态资源,如图片,文件, css,js脚本等等,但这些资源请求的频率很高,所以可以大大改善网页的打开速度。

1.3.1.7反向代理

反向代理服务器,位于机房的一侧,代理用户的请求。可以通过在反向代理服务器端配置缓存,静态内容缓存在反向代理服务器上,加速web请求的速度,减轻web访问的压力。

1.3.2应用服务器性能优化

1.3.2.1缓存的基本原理

缓存是指将数据缓存在,相对较高速度的存储介质中,供系统处理。一方面缓存速度快,可以减少数据访问的时间。一方面缓存的数据是经过计算处理得到的,不需要再次经过计算就可以直接获得。因此缓存还起到减少计算时间的作用。缓存的本质就是一个内存中的数组,链表,或者哈希表

如上图所示,其实缓存就可以理解成为内存,计算机可以快速读取的,灵活的存储空间。缓存主要用来存放那些读写比,比较高的数据。比如商品类目,菜单模块,热门词条,等这些数据,访问的次数大于更新的次数。还有就是经过一次计算,后面经常查询的数据。这样的数据应该放置到缓存提高访问效率。

使用缓存进行工作的时候,在用户进行数据查询的时候,先去缓存中进行查询,如果缓存中没有数据,再通过数据库进行查询,把数据库中查询出来的数据备份一份到缓存中,如果缓存中有数据就直接返回给客户,避免了访问数据库的操作。如果用户更新数据库的数据,为了避免数据库与缓存的不一致性,可以同步更新缓存或者删除缓存的数据。网站数据访问,遵循二八定律,80%的访问落在20%的数据上,所以要把这20%的数据缓存起来,改善性能,提高访问速度,减少存储的压力。不要滥用缓存,徒增系统的负担,一般来说缓存中的数据至少是读写比为21的数据。如果数据访问不遵循二八定律,没有访问热点,那么缓存就没有实际的意义。

使用缓存要保证缓存的可用性,当使用缓存的地方多了,数据库已经习惯了缓存的存在,如果有一天缓存发生雪崩,将可能由于大量的访问命中数据库,造成数据库,压力过大而雪崩。所以要构造分布式缓存集群。

当部分缓存雪崩以后,只是部分缓存数据丢失,而不影响数据库,不对数据库造成压力。最好在系统启动的时候就把热点数据加载好,这叫做缓存预热,这样等系统启动以后访问的速度自然就很高了。

1.3.3异步操作

使用消息队列将系统异步化,改善网站的系统性能。

如上图所示是不使用消息队列的情况。(图一)

如上图所示是添加了消息队列的情况(图二)

(1) 如上图一所示,不使用消息队列的情况下,用户请求的数据要写入数据库,写入成功以后再响应客户,造成响应的延迟,高并发的情况下给数据库造成了很大的压力。图二中消息经过消息队列,到达数据库。用户请求送入消息队列之后就可以直接返回,提高用户的响应。而且高并发的情况下数据通过消息队列排队入库,不会给数据库,造成很大的负载压力。

消息队列能够很好的削峰的作用,比如12306,淘宝网站的秒杀等等的高并发的场景,就可以通过消息队列来消除峰值,进行排队等待。

如上图所示是通过消息队列进行峰值消除的一个曲线图。由于消息队列中的数据写入数据库可能失败,所示要适当修正业务流程。有些重要的事情比如结订单提交,如果放入消息队列之后不能立即提示用户,计较成功,而可以通过异步邮件通知的方式,在后面通知客户。让能晚点做的事情尽量晚点做。

1.3.4使用集群

高并发场景下负载均衡策略为一个应用构建了一个由多台服务器组成的集群。将并发访问请求分发到多台服务器上去处理。避免一台服务器因负载压力过大而响应缓慢。使用户请求具有更好的响应延迟特性。

1.3.5代码优化

   由于线程比进程更轻量,占用更少的系统资源,切换代价更小,所以目前主要的web服务器都采用多线程的方式响应用户的请求。因此网站开发天然就是多线程的。

   为什么使用多线程,原因就在于IO阻塞与多CPU.IO操作的时候会被阻塞,并释放CPU等待IO操作完成。由于IO操作通常需要较长的时间,这时可以调度其他线程进行处理。比如一个16核的CPU要提高cpu的利用率,就得使用多线程。多线程的使用要注意线程安全问题。不管有没有进行多线程编程,用户的访问都是并发的提交的,所有资源的访问都可能是并发的访问。线程安全的办法

1.3.5.1 将对象设计成无状态的对象

所谓无状态对象是本身不存储信息的,比如servlet,贫血模式等等的。我们的IXXXService以及底层实现,都是无状态的,因为它们不存储信息。而UserMap等的本来就是用来存储数据的对象都是有状态的,要考虑并发问题。

1.3.5.2 使用局部对象

线程内部对象,会被每一个线程独立创建,除非有意识的将这些对象传递给其他线程,否则不会出现对象被多线程并发访问。并发访问资源时,通过锁的方式让多线程并发操作,转化为顺序操作。避免资源被同步修改。

1.3.5.3资源复用

系统运行时要尽量减少开销很大的资源被创建与销毁。从编程的角度,资源的复用主要有两种模式:单例模式与对象池。web开发中从servicedao的对象都是无状态的,所以用单例也是自然的事了。对象池模式通过复用对象实例,减少创建和销毁资源消耗,比如频繁的打开或者关闭数据库连接是宰难性的。应用程序数据库的连接基本都使用连接池的方式,连接池对象创建好以后放到对象池当中,应用程序连接的时候就从对象池中取出一个连接来,用完以后再把连接放回去。再创建线程去处理负载业务的时候,可以才采用线程池的方式,提高资源的复用。

1.3.5.4 数据结构

在不同的场景下,合理使用不同的数据结构,可以改善程序的性能。比如我们的hash表,并发下的hash表等等的。在这个时间宝贵的年代,我们应该牺牲空间来换取时间。

1.3.5.5 垃圾回收

JVM虚拟机可以分为,堆区,栈区,方法区等等的,理解JVM的内存模型,有助于提高我们解决问题的能力与性能优化的能力。

JVM将应用程序的堆空间分为年轻代与老年代,又将年轻代分为eden,from,to区,新建对象总是在eden区被创建,eden区满了以后会触发一次yuongGC,通过复制算法复制到from区。整个eden区都是未被使用的空间,可以继续创建对象。再满,再触发一次GC,把在使用的eden中与from中的对象复制到to区。下一次GC又从to区复制到from区,这样来回的复制,达到阈值以后,对象还未释放,就复制到Old Generation区。当Old中的空间用完以后,就会触发一次Full GC,进行全量回收,全量回收的影响相对比较大,容易出现 java界所谓的stop the world的现象。

1.3.6 存储性能的优化

加索引

加物化视图


猜你喜欢

转载自blog.csdn.net/worn_xiao/article/details/80779202