分布式技术专题「系统服务优化系列」Web应用服务的性能指标优化开发指南(基础篇)

Posted 洛神灬殇

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分布式技术专题「系统服务优化系列」Web应用服务的性能指标优化开发指南(基础篇)相关的知识,希望对你有一定的参考价值。

前提概要

针对于Web应用系统是现在计算机领域里面最常见的信息载体了,整个服务并不是一个孤立的个体,一个较为简单的Web应用主要是由前端视图页面、后端系统支撑、应用服务器、负载代理服务器、数据库等等其他服务组件组成的,其中每一个部分都会影响系统的性能。对于一个攻守兼备的程序猿来讲,服务性能方面知识的了解也是非常有必要的,接下来就让我们开始学习和了解一下系统性能测试的方方面面。

常用的性能评价/测试指标

响应时间

提交请求和返回该请求的响应之间使用的时间,一般比较关注平均响应时间,也是最直观的看指标。

常用操作的响应时间列表

分析一下整体的运作流程和执行过程:

并发数

同一时刻,对服务器有实际交互的请求数。

网站在线用户数的关联:1000 个同时在线用户数,一般情况下经验之谈可以估计并发数在 5%到 15%之间,也就是同时并发数在 50~150 之间。

吞吐量

对单位时间内完成的工作量(请求)的量度。

系统吞吐量和系统并发数以及响应时间的关系

理解为高速公路的通行状况:

吞吐量是每天可以通过收费站的车辆数目(可以换算成收费站收取的高速费),并发数是高速公路上的正在行驶的车辆数目,响应时间是车速

  • 车辆很少时,车速很快。但是收到的高速费也相应较少
  • 随着高速公路上车辆数目的增多,车速略受影响,但是收到的高速费增加很快;
  • 随着车辆的继续增加,车速变得越来越慢,高速公路越来越堵,收费不增反降;
  • 如果车流量继续增加,超过某个极限后,任务偶然因素都会导致高速全部瘫痪,车走不
    动,当然后也收不着,而高速公路成了停车场(资源耗尽)

常用的性能优化手段

避免过早优化

不应该把大量的时间耗费在小的性能改进上,过早考虑优化是所有噩梦的根源。

  • (代码编写)我们应该编写清晰,直接,易读和易理解的代码,真正的优化应该留到以后,等到性能分析表明优化措施有巨大的收益时再进行。但是过早优化,不表示我们应该编写已经知道的对性能不好的的代码结构。

进行系统性能测试

所有的性能调优,都有应该建立在性能测试的基础上,直觉很重要,但是要用数据说话,
可以推测,但是要通过测试求证。寻找系统瓶颈,分而治之,逐步优化

  • 性能测试后,对整个请求经历的各个环节进行分析,排查出现性能瓶颈的地方,定位问题,分析影响性能的的主要因素是什么?内存、磁盘 IO、网络、CPU,还是代码问题?架构设计不足?或者确实是系统资源不足?

前端优化常用手段(浏览器/App)

减少请求数;

合并 CSS,Js,图片

使用客户端缓冲;

静态资源文件缓存在浏览器中,有关的属性 Cache-Control 和 Expires如果文件发生了变化,需要更新,则通过改变文件名来解决。

启用压缩

减少网络传输量,但会给浏览器和服务器带来性能的压力,需要权衡使用。

资源文件加载顺序

css 放在页面最上面,js 放在最下面

减少 Cookie 传输

cookie 包含在每次的请求和响应中,因此哪些数据写入 cookie 需要慎重考虑

CDN 加速

CDN,又称内容分发网络,本质仍然是一个缓存,而且是将数据缓存在用户最近的地方。
无法自行实现 CDN 的时候,可以考虑商用 CDN 服务。

反向代理缓存

将静态资源文件缓存在反向代理服务器上,一般是 nginx

WEB 组件分离

将 js,css 和图片文件放在不同的域名下。可以提高浏览器在下载 web 组件的并发数。因
为浏览器在下载同一个域名的的数据存在并发数限制。


应用服务性能优化

缓存

  • 网站性能优化第一定律:优先考虑使用缓存优化性能且缓存离用户越近越好

缓存的基本原理和本质

缓存是将数据存在访问速度较高的介质。可以减少数据访问的时间,同时避免重复计算。

合理使用缓冲的准则

  • 频繁修改的数据,尽量不要缓存,读写比 2:1 以上才有缓存的价值。
  • 缓存一定是热点数据。
  • 应用需要容忍一定时间的数据不一致。
  • 缓存可用性问题,一般通过热备或者集群来解决。
  • 缓存预热,新启动的缓存系统没有任何数据,可以考虑将一些热点数据提前加载到缓存系
  • 统。

解决缓存穿透:

  • 1、布隆过滤器
  • 2、把不存在的数据也缓存起来 ,比如有请求总是访问 key = 23 的数据,但是这个 key = 23 的数据在系统中不存在,可以考虑在缓存中构建一个( key=23,value = null)的数据。设置一个TTL时间较短,并且新增该key的时候删除该key的缓存。

分布式缓存与一致性哈希

以集群的方式提供缓存服务,有两种实现;

  • 1、需要更新同步的分布式缓存,所有的服务器保存相同的缓存数据,带来的问题就是,缓存的数据量受限制,其次,数据要在所有的机器上同步,代价很大。
  • 2、每台机器只缓存一部分数据,然后通过一定的算法选择缓存服务器。常见的余数 hash算法存在当有服务器上下线的时候,大量缓存数据重建的问题。所以提出了一致性哈希算法。

一致性哈希:

    1. 首先求出服务器(节点)的哈希值,并将其配置到 0~2^32 的圆(continuum)上。
    1. 然后采用同样的方法求出存储数据的键的哈希值,并映射到相同的圆上。
    1. 然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过 2^32 仍然找不到服务器,就会保存到第一台服务器上。
  • 一致性哈希算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错
    性和可扩展性。
  • 一致性哈希算法在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜问题,此时
    必然造成大量数据集中到 Node A 上,而只有极少量会定位到 Node B 上。
  • 为了解决这种数据倾斜问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点

具体做法可以在服务器 ip或主机名的后面增加编号来实现。例如,可以为每台服务器计算三个虚拟节点,于是可以分别计算 “Node A#1”、“Node A#2”、“Node A#3”、“Node B#1”、“Node B#2”、“NodeB#3”的哈希值,于是形成六个虚拟节点:同时数据定位算法不变,只是多了一步虚拟节点到实际节点的映射,例如定位到“Node A#1”、“Node A#2”、“Node A#3”三个虚拟节点的
据均定位到 Node A 上。这样就解决了服务节点少时数据倾斜的问题。在实际应用中,通常将虚拟节点数设置为 32 甚至更大,因此即使很少的服务节点也能做到相对均匀的数据分布。

异步

同步和异步,阻塞和非阻塞

同步和异步关注的是结果消息的通信机制
  • 同步:同步的意思就是调用方需要主动等待结果的返回
  • 异步:异步的意思就是不需要主动等待结果的返回,而是通过其他手段比如,状态通知,回调函数等。

阻塞和非阻塞主要关注的是等待结果返回调用方的状态
  • 阻塞:是指结果返回之前,当前线程被挂起,不做任何事

  • 非阻塞:是指结果在返回之前,线程可以做一些其他事,不会被挂起

  • 1.同步阻塞:同步阻塞基本也是编程中最常见的模型,打个比方你去商店买衣服,你去了之后发现衣服卖完了,那你就在店里面一直等,期间不做任何事(包括看手机),等着商家进货,直到有货为止,这个效率很低。jdk 里的 BIO 就属于 同步阻塞

  • 2.同步非阻塞:同步非阻塞在编程中可以抽象为一个轮询模式,你去了商店之后,发现衣服卖完了,这个时候不需要傻傻的等着,你可以去其他地方比如奶茶店,买杯水,但是你还是需要时不时的去商店问老板新衣服到了吗。jdk 里的 NIO就属于同步非阻塞

  • 3.异步阻塞:异步阻塞这个编程里面用的较少,有点类似你写了个线程池,submit 然后马上future.get(),这样线程其实还是挂起的。有点像你去商店买衣服,这个时候发现衣服没有了,这个时候你就给老板留给电话,说衣服到了就给我打电话,然后你就守着这个电话,一直等着他响什么事也不做。这样感觉的确有点傻,所以这个模式用得比较少

  • 4.异步非阻塞:好比你去商店买衣服,衣服没了,你只需要给老板说这是我的电话,衣服到了就打。然后你就随心所欲的去玩,也不用操心衣服什么时候到,衣服一到,电话一响就可以去买衣服了。jdk 里的 AIO 就属于异步

常见异步的手段

Servlet 异步

servlet3中才有,支持的web容器在tomcat7和jetty8以后
多线程
消息队列
集群:可以很好的将用户的请求分配到多个机器处理,对总体性能有很大的提升程序

代码级别

选择合适的数据结构

选择ArrayList 和 LinkedList 对我们的程序性能影响很大,为什么?因为 ArrayList 内部是数组实现,存在着不停的扩容和数据复制。

选择更优的算法

举个例子,最大子列和问题:

给定一个整数序列,a0, a1, a2, …… , an(项可以为负数),求其中最大的子序列和。
例如(a[1],a[2],a[3],a[4],a[5],a[6])=(-2,11,-4,13,-5,-2)时,最大子段和为 20,子段为 a[2],a[3],a[4]


  • 最坏的算法:穷举法,所需要的的计算时间是 O(n^3).
  • 一般的算法:分治法的计算时间复杂度为 O(nlogn).
  • 最好的算法:最大子段和的动态规划算法,计算时间复杂度为 O(n)

n 越大,时间就相差越大,比如 10000 个元素,最坏的算法和最好的算法之间的差距绝非
多线程或者集群化能轻松解决的。

并发编程

  • 充分利用 CPU 多核
  • 实现线程安全的类,避免线程安全问题
  • 同步下减少锁的竞争:减少排他机制的阻塞,以及加锁释放锁的过程
  • 资源的复用:池化机制
  • 目的是减少开销很大的系统资源的创建和销毁,比如数据库连接,网络通信连接,线程资源等等。
  • 单例模式:减少内存开销以及重复分配内存的操作流程
  • 池化技术:享元模式,可以充分复用数据信息以及内存

以上是关于分布式技术专题「系统服务优化系列」Web应用服务的性能指标优化开发指南(基础篇)的主要内容,如果未能解决你的问题,请参考以下文章

#私藏项目实操分享#Alibaba中间件技术系列「Sentinel技术专题」分布式系统的流量防卫兵的基本介绍(入门源码介绍)

分布式技术专题「OSS中间件系列」Minio的文件服务的存储模型及整合Java客户端访问的实战指南

分布式技术专题「OSS中间件系列」Minio的文件服务的存储模型及整合Java客户端访问的实战指南

#私藏项目实操分享#分布式技术专题「OSS中间件系列」Minio的文件服务的存储模型及整合Java客户端访问的实战指南

分布式技术专题「架构实践于案例分析」盘点一下分布式模式下的服务治理和监控优化方案

分布式技术专题「OSS中间件系列」Minio的Server端服务的架构和实战搭建