《大型网站技术架构》笔记:架构之高性能


一、性能测试指标和测试方法

  • 性能指标
  • 响应时间
    从发出请求开始到收到最后响应数据所需要的时间
  • 并发数
    是指系统同时处理请求的数目
  • 吞吐量
    单位时间内系统处理的请求数量
  • 性能计数器
    描述服务器或操作系统性能的一些数据指标,包括System Load、对象与线程数、内存使用、CPU使用、磁盘与网络I/O等指标。
  • 性能测试方法
  • 性能测试
  • 负载测试
  • 压力测试
  • 稳定性测试

二、Web前端性能优化

2.1 浏览器端

  • 减少HTTP请求
    主要手段是合并CSS、合并JavaScript、合并图片
  • 使用浏览器缓存
    通过设置HTTP头中的Cache-Control和Expires属性。通过对静态文件改名并更新Html中的引用实现。
  • 启用压缩
    在服务器端对文件进行压缩,在浏览器端对文件进行解压缩,可有效减少通信传输的数据量。但压缩会对服务器和浏览器产生一定压力,需要权衡。
  • CSS放在页面最上面,JavaScript放在页面最下面
  • 减少Cookie传输
    一是静态资源不要携带Cookie,而是尽量减小Cookie本身携带的数据量。

2.2 使用CDN加速

主要将静态资源(如图片、文件、CSS、JavaScript、静态网页等)放在网络服务提供商的本地机房中进行缓存

2.3 使用反向代理服务器

传统代理服务器位于浏览器一侧,代理浏览器将HTTP请求发送到互联网上。而反向代理服务器位于网站机房一侧,代理网站的Web服务器接受HTTP请求,来自互联网的所有访问请求必须经过代理服务再到达应用服务器。

反向代理可以实现的三个作用:

  • 保护网站安全:相当于在Web服务器和可能的网络攻击之间建立了一个屏障
  • 缓存:当静态内容第一次被访问后,就将静态内容缓存在反向代理服务器上,之后相同的静态内容请求可以直接从反向代理服务器返回,不必再到达应用服务器。也可以将像热门词条、帖子、博客等动态内容缓存在反向代理服务器上。
  • 实现负载均衡

三、应用服务器性能优化

3.1 分布式缓存

  • 缓存的基本原理
    缓存是指将数据存储在访问速度较快的存储介质中(如内存)。缓存的本质是一个内存Hash表,数据以一对key、value的形式存储在内存Hash表中--数据读写的时间复杂度为O(1)。
    缓存主要用来存放读写比(大于2)高、很少变化的数据。

  • 合理使用缓存
    ①频繁修改的数据不要放在缓存中;
    ②只缓存热点数据。内存有限,如果没有热点,大部分数据还没有被再次访问就被挤出缓存了;
    ③应用要容忍一定时间的数据不一致,如果数据更新后立即更新缓存,会带来更多系统开销和事务一致性问题;
    ④通过分布式缓存服务器集群提高缓存可用性
    ⑤缓存预热
    ⑥准备好应对缓存穿透(访问的数据不在缓存中,直接落到数据库上):一个简单的对策是将不存在的数据也缓存起来,value设为null。

  • 分布式缓存架构
    分布式缓存是指缓存部署在多个服务器组成的集群中,以集群方法提供缓存服务。其架构有两种方式:
    ①以JBoss Cache为代表的需要更新同步的分布式缓存:
    集群中的所有服务器中保存相同的缓存数据,当某台服务器有缓存数据更新的时候,会通知集群中的其他机器进行更新缓存会或清除缓存数据。通常,将应用程序和缓存部署在同一台服务器上(应用程序也是集群部署),应用程序可以从本地快速获取缓存数据。但由于数据同步的代价较大,这种方案更多见于企业应用中,很少在大型网站中使用。
    ②以Memcached为代表的不互相通信的分布式缓存:
    缓存与应用分离部署,应用程序通过一致性Hash等路由算法来确定缓存数据存放的缓存服务器,然后远程访问获取缓存数据。缓存服务器之间不需要通信,缓存集群的规模可以很容易地实现扩容,具有良好的可伸缩性。
    Memcached的特点:简单的通信协议;丰富的客户端支持;高性能的网络通信;高效的内存管理;互不通信的服务器集群架构;

3.2 使用消息队列实现异步操作

使用消息队列将调用异步化,可改善网站的扩展性,还可以改善网站系统的性能。
主要体现在使用消息队列进行削峰:通过异步处理,将短时间高并发产生的事务消息存储在消息队列中,从而削平高峰期的并发事务。但由于数据在后续的业务校验、写数据库等操作中有可能失败,因此在使用消息队列进行业务异步处理后,需要适当修改业务流程进行配合。

3.3 使用集群

使用负载均衡技术构建应用服务器集群,将并发访问请求发到多台服务器进行处理,避免单一应用服务器因负载压力过大而响应缓慢。

3.4 代码优化

  • 多线程
    ①一台应用服务器上启动多少线程合适?可供参考的估算公式:
    启动线程数=[任务执行时间/(任务执行时间-IO等待时间)]×CPU内核数
    ②线程安全问题的解决手段
    a.将对象设计为无状态对象(如Java中的Servlet就是无状态对象):无状态对象是指对象本身不存储状态信息对象无成员变量或者成员变量本身也是无状态对象。(我觉得还有一种就是有状态,但是状态只能是一种,永远不会改变)---不符合面向对象的思想;
    b.使用局部对象:在方法内部创建对象,这些对象会被进入该方法的每个线程创建,除非程序手动将对象传递给其他线程,否则不会出现对象被多线程并发访问的情形。
    c.并发访问资源时,使用锁。随着操作系统和编程语言的进步,出现各种轻量级锁,使得运行期线程获取锁和释放锁的代价变小,但由于锁导致线程同步顺序执行,可能会对系统性能产生严重影响。

  • 资源复用
    主要有两种方式:单例和对象池。
    单例:使用同一个对象。Spring默认构造的对象都是单例。
    对象池:比如线程池、连接池等可以理解为对象池,都由一个池来管理固定的几个对象(可能有最大、最小值),使用的时候从池里面拿出闲着的那个对象来用,用完还给池。

  • 数据结构
    灵活组合各种数据机构改善数据读写和计算特性。

  • 垃圾回收
    如果应用运行在JVM等就有垃圾回收功能的环境中,那么垃圾回收可能会对系统的性能产生巨大影响。理解垃圾回收机制有助于程序优化和参数调优,以及编写内存安全的代码。

3.5 存储性能优化
  • 固态硬盘 vs 机械硬盘
  • B+树 vs LSM树
  • RAID vs HDFS

你可能感兴趣的:(《大型网站技术架构》笔记:架构之高性能)