对速度的不满在调优的场景里占大多数,速度的不满一般来说也是分两种:
一种是对一个“体型”较大的任务执行的时间过长不满;
一种是对一个“体型”较小的任务的响应速度过长不满。
这两种不满看上去都是一样的速度问题,但是思路不完全一样。一般来说,在做这类优化之前先要做一件事,就是判断一下究竟是资源不足,还是资源分配不合理。
常见的场景可能有以下这些:例如,一个进程在服务器上运行,但是速度确实比期望的慢,而CPU和磁盘的带宽却大量闲置,这种情况下很显然是资源配置不合理。
因为资源不是不够,而是由于线程调度,或者算法,或者其他一些原因没有被利用上。这种情况下估计你去申请购买新机器,如果老板花的确实是自己的钱的话十有八九是不会给你批的,相信我。
1、思路一:逻辑层面的优化
在服务器上跑的程序,尤其是Batch通常是彼此之间独立的。这种情况下,其实是可以考虑让它们同时来执行,充分利用CPU和内存的资源。但是也要注意,要确认这种变化给磁盘带来的IO增加不会让它成为系统的瓶颈。这就是进程级别的并发。
还有的时候一个进程可以分解为多个独立作业和一个合并操作,那么这种情况下通常可以尝试着多启动几个进程或者线程,让每个进程或者线程处理整个作业的一部分,最后结束的时候做一个作业结果的“合并”操作,提高并行化,提高资源利用率。
这种应用比较典型的就是Hadoop环境中的MapReduce程序,实际是在很多节点各启动若干个Map进程和Reduce进程,让它们在不同节点上操作,分摊IO和CPU的资源压力。在单台服务器上也有类似的操作,如一个MySQL服务器进程在接受一个SQL请求时,这个SQL不论请求多少个表,不论它有多少个不相干的子查询,不论写得有多“优美”,它都只能在一个CPU内核上一步一步地走下去。
所以,如果采用MySQL环境做关联分析,就只能把一个SQL中的两个独立子查询放到两个或者更多的线程(进程)里去做请求,再用一个监控线程(进程)观察结果,最后做连接查询。有必要的话可以使用Memory内存视图的Hash索引进行速度优化。
2、思路二:容器层面的优化
当一台或多台服务器上有很多进程,但是资源占用普遍比较低时,还可以考虑使用容器层面的优化。
可以使用KVM或者Docker这样的容器把服务器资源划分成多个虚拟的服务器资源。这种情况下,原本在多个服务器的少量负载经过迁移会合起来加载在一个服务器上,而节省出来的服务器资源可以用来做其他的服务,在硬件的成本上会有一大笔节省。
现在的阿里云、腾讯云、金山云、亚马逊云等云产品服务商就是大规模使用了虚拟化技术,从而使得运维成本大为降低。
虽然容器层面的优化对于直接减少程序运行的时间作用较为间接,但在庞大的系统内提高硬件整体的使用效率还是非常有好处的。
3、思路三:存储结构层面的优化
目前在服务器普遍配置了RAID10磁盘阵列以后,磁盘IO在硬件层面进一步并行化的余地越来越小了。那么还有没有其他的办法可以对IO层面进行优化呢?有的。
例如,为了缓存一些数据做迭代运算,磁盘发生非常频繁的读写,每次几个GB(量比较小,至少内存能够承载),但是一次处理可能要读写数百次,这样会大量占用磁盘IO。这种情况下,不妨尝试在内存中虚拟或者划分出一个独立的空间,以供做IO使用。这样把CPU和磁盘之间的IO转化成为CPU和内存之间的IO,这种效率的提升可能是数千倍的。
另外,磁盘在做IO的过程中,是不是扫描了一些本可以不扫描的磁盘块?解决这种问题有很多成熟的办法。
在数据仓库里使用列式存储,从本质来讲也是用这种方法来规避没必要扫描的数据块被扫描。表分区(Table Partitioning)、索引(Index),这两种技术同样是为了解决数据查找中没必要扫描的数据块被访问而带来的IO效率下降问题。
资源分配不合理的情况比较好解决,就是找出在系统里CPU、内存、磁盘、网络中,哪些资源被大量闲置,如果利用起来能否提高并行性,基本就是这样一种思路。
4、思路四:环节层面的优化
环节层面的优化是一个边缘化的问题,因为这个层面上的优化通常会涉及硬件资源以外的一些问题——换句话说,这一类问题在计算机的CPU、内存、磁盘、网络层面考虑可能还是不能解决的。
(1)虚拟机惹的祸
笔者几年前在某500强企业的IT解决方案中心做顾问的时候,曾经遇到过一个案例。
这个案例从技术层面来说就是一个ERP系统页面请求速度太慢的问题,大概需要2到3秒时间才能把一个页面的数据完全加载完毕。不管2到3秒这个速度是不是够快,是不是比平时访问电商网页或者在线论坛的速度快,对于一个对效率要求很苛刻的500强企业来说,这是一件不能容忍的事情。况且,页面所访问的服务器也是DELL提供的很新的技术方案,48个CPU内核,192GB内存。
服务器在公司内网,内网带宽又基本都是1Gbps的光纤到楼层,楼层内部又都是100Mbps的以太网。所以从这个层面上看这种页面的延迟没有道理,而其他项目组在配置基本相当的服务器环境和终端环境,打开页面时间都是1秒以内。
但是很快就发现了问题所在,这个ERP系统的页面是使用Silverlight制作的。Silverlight是微软出品的一种跨服务器跨平台的插件,主要目的是解决浏览器上的流媒体和交互丰富性的问题,基本可以认为是Adobe Flash的替代者。然而这种技术框架有一个天生的问题就是慢,因为它调用的是微软.NET虚拟机的资源,而虚拟机本身的运行机制就是一种多层间接调用的架构,指令不是直接下达到CPU上,而是经过虚拟机,由虚拟机调度线程再发送到CPU。在一次HTTP请求的过程中,有几百个指令会以这种方式传递给CPU,延迟是显而易见的。
最后为了赢得这1秒多的时间,不得不推翻了整个项目的架构部分,采用HTML4+CSS2的方式。立竿见影,延迟瞬间就压缩到1秒以内了。但是代价是牺牲了一些交互上的丰富性和美观性,那个时候HTML5和CSS3还不成熟,还不能作为成熟的技术方案,所以说现在用HTML5和CSS3的程序员们真是赶上好时候了。
(2)CDN是个好东西
除了刚刚这个例子以外,平时也能见到很多从环节层面进行优化的例子。最常见的就是CDN技术。
CDN技术是一种近几年非常火的技术,全称是Content Delivery Network,内容分发网络。CDN应该说是一套完整的网络加速解决方案,包括分布式存储、负载均衡、网络请求的重定向和内容管理等多个技术环节部分。对于用户在网页上请求图片加载慢,或者文件下载慢等非本地带宽过小带来的数据下载问题能有很好的改善作用。
例如,当一个网站使用了CDN技术对网页资源进行加速的策略开启后,这些资源就会通过CDN提供商的分发策略分发到很多的缓存服务器上去。当用户进行该网站的访问时,这些资源引用的地址会自动指向这个离得最“近”,访问最快的缓存服务器节点上去,这样就能使资源下载加速了。
互联网是一个非常复杂的东西,不仅是拓扑结构复杂,其中不同的交换设备有着不同的交换策略,是一个分布式的自协调的连通系统。不同运营商之间也会由于技术性的或者非技术性的问题引发跨网(跨运营商)的带宽变窄问题。为了解决这种问题,我们不仅仅会用到CDN技术,还需要使用一种叫BGP双线/多线机房的技术来进行网络加速。
BGP(Border Gateway Protocol,边界网关协议)是一种在TCP协议上运行的自治系统之间动态交换路由信息的路由协议。启用BGP技术的机房一般称作BGP机房,服务器租用商或提供商通过技术的手段,实现不同运营商能共同访问一个IP,并且不同运营商之间都能以最快的速度访问这个IP地址。把服务器放在BGP机房给用户带来的好处就是,在BGP机房基本可以不考虑不同的用户跨网访问服务器会因运营商网络不同而产生的“带宽歧视”问题。
5、资源不足
资源不足的情况通常比较麻烦,因为如果观察到服务器上的CPU、磁盘IO、网络IO都非常繁忙,要想办法先排除是业务逻辑上设计的疏漏导致的不合理或者意外的资源请求太多,还是“真的”资源不够。
如果是由于一些疏漏导致的资源请求过于集中,那么通过debug或者优化业务逻辑,还是能够获解的。但是如果不是这些问题,那就是资源确实比客观真实的需求少了。典型的例子就是,在保存日志的情况下,业务要求无损永久存档,但是即便在启用压缩且不留冗余的情况下,还是很快把磁盘填满,那就是典型的磁盘资源不足了。
总之,还是要先用一些办法确定资源分配究竟是不足还是不合理,再用“低成本”的资源换取“高成本”的资源。