# 1.2 瓶颈分析 不同网站有不同的属于该类型网站的特定性能瓶颈。比如资讯类网站大部分在进行读数据库,文件存储类网站大部分在进行文件I/O操作,而如果网站业务是计算密集型,性能瓶颈一般在CPU。 ## 1.2.1 Linux 下的性能监测 要找到网站的瓶颈就不得不学会对系统状况的检测和分析。我们这里介绍一些常见的Linux性能监测指令和工具。 ### **Top指令:** CPU/内存情况 ~~~ top # top指令可以显示总体CPU占用率、内存使用率和交换情况,以及所有进程对应的CPU、内存占用情况 ~~~ 终端下使用该指令示例结果: ![](https://box.kancloud.cn/54f63e126dd638fc9e4a54b8b67f30b4_1019x718.png) 上图对一些重要的参数进行了简单标识,笔者这里使用的是XShell对远程Linux服务器进行连接和管理。 可以看到,在 `top` 指令返回的结果中,CPU和内存的占用信息都十分详细: >[success] - 第一行中的Load Average则是Linux系统中任务调度队列里1分钟、5分钟与15分钟任务的负载(有关Linux系统任务调度相关内容可参阅高等教育出版社的《操作系统概念》); > - 第三行中用户模态和内核模态的分别占用率以及空闲CPU都反应了当前CPU的总体占用情况。**I/O等待占CPU时间**要注意,如果此项过高可能是I/O读写出现了故障或者瓶颈; > - 第四行是物理内存的使用情况,一般来说,内存根据实际需要配置,增添看当前是否够用,这方面没有什么技巧。 > - 第五行是交换内存的使用情况。关于交换内存,首先,交换内存是指在等待或者被挂起的进程被交换到辅存(SSD、机械硬盘)。这样,能把空闲的进程腾出来,把空间让给更加活跃的进程。因此,交换内存的性能是低于物理内存的。当交换内存占用过大时,一方面可能是空闲进程多,还有一方面要注意的可能就是物理内存不够用,大量进程都被交换到了这里。 > - 而下面的列表,则是各个进程的具体情况。比如,图中的php-fpm就反映了PHP的运行情况,同样还有mysqld可以反应MySQL数据库的运行情况 # ### **IOStat指令:** 磁盘情况 ~~~ iostat -d -k 2 # iostat主要用来显示磁盘IO情况,这里-d、-k、2是三个常加的参数: # -d 表示显示设备(磁盘)使用状态 # -k 某些使用block为单位的列强制使用Kilobytes为单位 # 2 表示数据显示每隔2秒刷新一次。可以使用Ctrl+C来终止输出 ~~~ 终端下使用该指令示例结果: ![](https://box.kancloud.cn/4a5bf58928ffdd08dfd9c61ea85bd5b0_924x707.png) 如上图,命令执行后每两秒钟会向终端输出一次当前的I/O状况。这些数据的具体含义是: >[success] - tps:该设备每秒的I/O请求次数,即频率; > - kB_read/s:每秒从设备读取的数据量; > - kB_wrtn/s:每秒向设备写入的数据量; > - kB_read:读取的总数据量; > - kB_wrtn:写入的总数量数据量; # #### 更高级的用法: ~~~ iostat -d -x -k 1 10 # 这里添加了几个参数 -x 与 1 后面的 10 # -x 表示显示和io相关的扩展数据 # 1 10 1 表示每1秒刷新一次,1 后跟 10 表示一共输出10次数据 ~~~ 命令执行后,返回数据的含义: >[success] - avgrq-sz:平均请求扇区的大小 > - avgqu-sz:是平均请求队列的长度。**毫无疑问,队列长度越短越好**。 > - await: 每一个IO请求的处理的平均时间(单位是微秒毫秒)。这里可以理解为IO的响应时间,一般地系统IO响应时间应该低于5ms,如果大于10ms就比较大了。这个时间包括了队列时间和服务时间,也就是说,一般情况下,await大于svctm,它们的差值越小,则说明队列时间越短,反之差值越大,队列时间越长,说明系统出了问题。 > - svctm:表示平均每次设备I/O操作的服务时间(以毫秒为单位)。如果svctm的值与await很接近,表示几乎没有I/O等待,磁盘性能很好,如果await的值远高于svctm的值,则表示I/O队列等待太长,系统上运行的应用程序将变慢。 > - %util: 在统计时间内所有处理IO时间,除以总共统计时间。例如,如果统计间隔1秒,该设备有0.8秒在处理IO,而0.2秒闲置,那么该设备的%util = 0.8/1 = 80%,所以该参数暗示了设备的繁忙程度。一般地,如果该参数是100%表示设备已经接近满负荷运行了(当然如果是多磁盘,即使%util是100%,因为磁盘的并发能力,所以磁盘使用未必就到了瓶颈)。 # ### **nload工具:** 带宽情况 nload是一款命令行下监控入站流量和出站流量的工具,它的使用就十分简单。Ubuntu和Fedora系统默认软件库包含该工具,而CentOS则需要从Epel软件库安装。 ### #### 安装nload CentOS或Fedora系统下: ~~~ yum install nload -y ~~~ Ubuntu或debian系统下: ~~~ sudo apt-get install nload ~~~ ### #### 使用nload 直接运行命令即可: ~~~ nload ~~~ 终端下使用该工具: ![](https://box.kancloud.cn/8b8e8a14ecbbb86f17e431acdbb40ea4_890x706.png) nload的数据会一直刷新,它的显示也比较简单、易于理解。如果Curr(当前速度)一直处于峰值就要考虑宽带大小是否够用。 ### **云服务器控制面板:** 监控插件 如果购买的是云服务器,那么大多数云服务器提供商都会在控制面板提供服务器监控的功能。这里以常见的阿里云为例: ![](https://box.kancloud.cn/6352bba468a0225ecf9880ade7a058a4_1164x970.png) 阿里云服务器提供的检测功能很多,常见的CPU使用率、网络带宽、磁盘读写等都有助于我们判断系统资源的使用情况。其他监控面板应该也大同小异。 ### **为Linux安装控制面板:** 摆脱终端 如果没有云服务器控制面板,市面上也有很多针对Linux服务器开发的控制面板软件。通过图形化的管理,资源的使用情况可能更加直观,操作也更加方便。这里我们以国产的[宝塔面板](http://www.bt.cn/)为例: #### 安装面板 Centos安装命令: ~~~ yum install -y wget && wget -O install.sh http://download.bt.cn/install/install.sh && sh install.sh ~~~ Ubuntu/Deepin安装命令: ~~~ wget -O install.sh http://download.bt.cn/install/install-ubuntu.sh && sudo bash install.sh ~~~ Debian安装命令: ~~~ wget -O install.sh http://download.bt.cn/install/install-ubuntu.sh && bash install.sh ~~~ Fedora安装命令: ~~~ wget -O install.sh http://download.bt.cn/install/install.sh && bash install.sh ~~~ #### 面板使用 在浏览器访问 http://<服务器IP>:8888/ 进入面板登录页面,输入安装结束时终端输出的用户名和密码,登录即可。 ![](https://box.kancloud.cn/be2541f736ea6f85aa00ad6b4bb85aa4_1118x930.png) # ## 1.2.2 不同的瓶颈 了解了如何去检测Linux系统的资源使用状况,我们就要根据获得的信息来判断网站的瓶颈所在。当CPU总是被PHP-FPM占用过高,如果PHP跑了太多计算逻辑,那么就要考虑针对计算密集型如何去解决瓶颈;当磁盘I/O读写率总是峰值,就要判断是数据库负载过重还是文件存储频繁,然后对症下药,等等... ... 下面我们就分类讲一讲各种瓶颈出现的情形: # ### **计算密集型** 出现计算密集的表现在CPU的持续高占用。但要和高并发导致的CPU占用区别开,要结合网站具体业务进行分析。比如网站在运行较为复杂的推荐系统,在对用户行为进行统计分析,那么可能在用户访问量不算峰值的情况下,仍有较高的CPU占用。 对于大多数网站,这种情况是少见的,因为一般PHP不会跑过于复杂或者计算量大的逻辑。这样说是因为PHP的运行机制比较特殊:用户每访问一次页面,页面对应脚本会被PHP解释器从新加载、分配空间、解释、然后释放资源。用户的访问结束,脚本的生命周期就结束了,而这通常只有不到1秒的时间,所以在这1秒的时间内做大量的计算显然是不合适的。 那强行给PHP脚本加上复杂的逻辑、大量的计算的结果可能就是,网页的返回变得极其的慢,用户会感觉到加载慢、切换卡。 解决计算密集问题的方式有两个方向: >[info] 1. PHP仍可以使用,但是不是以传统的方式。采用PHP-CLI(也就是命令行)的形式运行PHP脚本,并且使用Swoole、Workerman这样的异步网络Socket库构建Server。将计算的部分转移到这种方式上显得更合理。 > 2. 使用其他语言技术承担这部分计算。坦诚地说,PHP的确是要比其他有些语言要慢,Java、Node.Js在计算方面可能都比PHP有优势,即使在最新的成倍性能提升的PHP7看来也是如此(期待JIT对于PHP的提升)。那么把需要计算的业务部分剥离出来,交给Java或者C++等语言负责,这样最理想。比如机器学习方面的推荐系统、图像识别等,PHP更适合做为Python语言的前端*向用户呈现计算的结果。 这两个方向的学习会在第八章有介绍与尝试。 **注意**:这里的前端不是指狭义上的HTML/CSS/JS,而应理解为更靠近用户那一端的相对概念。 # ### **高并发型** 并发量导致负载过重是最常见的瓶颈原因,直白的说,就是同一时间用户访问量过大。并发量过高导致的负载不仅在于PHP脚本的运行上,还在于数据库上,大量用户请求了大量页面,PHP脚本需要从数据库同时读取过多的数据,这需要数据库进行大量的I/O操作。事实上,大多数网站出现的并发瓶颈都在于数据库,这种情况mysqld进程会占用极多的磁盘I/O读写带宽和明显的CPU。 # #### PHP脚本 最明显的表现则是**php-fpm占用CPU过多**,在1.2.1中介绍的`top`命令可以检测相关信息。过多的用户会导致php-fpm启动很多的进程,同时为用户请求服务,不可避免的会占用过多的CPU和内存。 >[info] - 解决这个问题的方式就是使用**Web集群**。Web集群中有很多的Web服务器运行同样的Web应用,对本书而言,就是运行着同样一套ThinkPHP5框架开发的代码。这些Web服务器可以很廉价,因为只要数量足够多,那么就能够将分到每个Web服务器上的访问量变得很少,这就是Web集群解决高并发的方式。**关于Web集群的架构、配置在第六章会有实际介绍**。 >[info] - 如果使用Web集群,则涉及到Session不能再像单个服务器上搭建PHP网站一样使用了。在分布系统中,用户每次访问可能被分流到Web集群中的任意一台服务器。如果Session不在这些服务器上共享,可能出现的情形则是:用户请求登录,被分流到了服务器A,在服务器A上完成了登录操作,服务器A保存了该用户的SessionA;用户再次发起访问个人详情页,但是这次被分流到了服务器B,服务器B上并不存在该用户的SessionA,没法识别该用户的登录状态。这样,用户的状态就在分流的过程中丢失了,这肯定是不允许发生的。我们得想办法使Session在Web集群中共享,常见的方法则是搭建Redis服务器,将Redis作为共享Session来使用。**Redis服务器的有关内容会在第七章介绍**。 # #### MySQL数据库 最明显的表现则是**mysqld占用CPU过多,磁盘I/O带宽占用严重**。本书就不从如何优化SQL语句和查询操作的方面来思考解决方案了,而着重用构建分布式系统的方法解决问题。 >[info] - 解决这个问题的方式就是使用**分布式数据库**。同样是将数据库查询的负载分到不同服务器,这样类似于Web集群样的思想。当然,分布式数据库也有独特的地方,那就是主从式和读写分离。还有一点不同于Web集群的则是,Web集群中的各个服务器运行的是同样的一套PHP代码,不需要互相通信,而分布式数据库中的每个数据库需要保持信息的高度一致,这就需要对分布式数据库中的数据库进行同步配置。**分布式数据库的有关内容会在第三章介绍**。 # ### **大量存储型** 这类型一般就是典型的提供文件存储服务的站点,当大量存储操作发生时,瓶颈所在是显而易见的。不管是从数据安全还是性能方面考虑,都应该建立单独的存储系统来独立负责存储相关的操作。 >[info] - 我们可以搭建NAS服务器来负责文件存储,但是当服务器配置、文件备份等都很繁杂时,本书选择拥抱云时代,我们推荐的是采用云服务商提供的**对象储存服务**。对象储存的入门价格比搭建一台NAS的服务器要便宜的多,收费也是按量计费。而且大多云服务商都提供了便捷的数据安全方面的服务和各种语言对应的SDK方便开发者接入。**对象储存的有关内容会在第三章介绍**。 # ### **静态资源型** 网站存在大量的html、css、js和图片等静态资源时,我们可以建立单独的静态资源服务器来分走这部分访问压力,也可以选用CDN进行静态资源的节点加速。**静态资源服务器的有关内容会在第三章介绍**。 # ### **其他方面** 带宽瓶颈:除了页面压缩,其他唯一能做的就是花钱让运营商对服务器的网络带宽升级了。。。真的没有别的办法了。 # ## 扩展阅读 1. [iostat指令详解](http://www.orczhou.com/index.php/2010/03/iostat-detail/) 2. [宝塔面板的安装](https://www.bt.cn/bbs/thread-1186-1-1.html)