分享到:

厦门快快网络科技有限公司高防服务器,高防服务器租用,高防服务器托管价格

联系资料

厦门快快网络科技有限公司
所在地区:
福建省 厦门市
公司主页:
暂无
电话号码:
0592*******
传真号码:
暂无
联 系 人:
林先生
移动电话:
1805*******
电子邮箱:
暂无

服务器性能优化的正确姿势

发布于 2017年08月19日

[摘要]在系统运维中除了要维持平台的稳定运行以外,还需对服务器的性能进行优化,让服务器发挥出良好的工作性能是稳定运行的基础。
什么是性能?

性能最通俗的衡量指标就是“时间”,CPU的使用率指的是CPU用于计算的时间占比,磁盘使用率指的是磁盘操作的时间占比,当CPU使用率100%时,意味着有部分请求来不及计算,响应时间增加或者超时;当磁盘使用率100%时,意味着有部分请求需要等待IO操作,响应时间也会增加或者超时。换言之,所有的操作都在理想的时间内,就不存在“性能优化“的问题。我们在分析性能的时候,总是会首先要找到是什么引起响应时间变慢了,对应单机性能的分析,一般我们会将目光锁定在CPU和IO上,因为对于应用程序一般分为CPU bound型和IO bound型,即计算密集型或者读写密集型;至于内存,其性能因素往往也会反映到CPU或者IO上,因为内存的设计初衷就是提高内核指令和应用程序的读写性能,当内存不足,系统可能进行大量的交换操作,这时候磁盘可能成为瓶颈;而缺页、内存分配、释放、复制、内存地址空间映射等等问题又可能引起CPU的瓶颈;更严重的情况是直接影响功能,这个就不仅仅是性能的问题了。

性能优化并不是一个孤立的课题,除了响应时间的考虑,我们往往还需要综合功能完整性、安全性等等方面的问题。

性能分析的基础

性能优化需要厚实的基础知识:

操作系统——操作系统管理着应用程序所需要的所有资源,例如CPU和IO,当任何一个组件出现问题,我们的分析也是基于操作系统的,例如文件系统类型,磁盘类型,磁盘raid类型都需要操作系统管理和支持。

系统编程技术——系统编程技术涉及到我们如何使用系统资源,例如对IO的操作我们可以使用buffering I/O,也可以使用Direct IO,可以采用同步的方式,也可以采用异步的方式,可以使用多进程,也可以使用多线程的方式。懂得不同编程技术的原理,有利于问题的分析。

应用程序——例如数据库组件的数据类型、引擎、索引、复制、配置参数、备份、高可用等等都可能是性能问题的元凶。

性能分析的方法论

问题分析方面,各类方法论如金字塔思维、5W2H、麦肯锡七步法等等。套用5W2H方法,可以提出性能分析的几个问题

What-现象的表现是什么样的

When-什么时候发生

Why-为什么会发生

Where-哪个地方发生的问题

How much-耗费了多少资源,问题解决后能减少多少资源耗用

How to do-怎么解决问题

但是这些只能给出方向,性能分析需要找到原因需要更具体的方法,怎么解决一个问题也需要更加具体的方式。

Brendan Gregg在《性能之巅:洞悉系统、企业与云计算》第二章中讲到大量的方法,比较突出的如Use方法、负载特征归纳、性能监控、静态性能调优、延时分析、工具法等等。其中工具法最具体,但是工具法也有自己的限制,如磁盘的饱和度,在磁盘使用率100%的时候,磁盘的负载可能还可以继续增加。在实际分析问题中,负载特征归纳更有指导意义,静态跟踪和动态跟踪让我们更容易更直观发现问题。



CPU

认识CPU

CPU本身的架构和内核调度器的架构这里不做详细讲述,具体可以参考操作系统类书籍。但是仍然需要清楚一些概念:

处理器

硬件线程
CPU内存缓存
时钟频率
每指令周期数CPI和每周期指令数IPC
CPU指令
使用率
用户时间/内核时间
调度器
运行队列
抢占
多进程
多线程
字长
针对应用程序,我们通常关注的是内核CPU调度器功能和性能



线程的状态分析主要是分析线程的时间用在什么地方,而线程状态的分类一般分为:

on-CPU:执行中,执行中的时间通常又分为用户态时间user和系统态时间sys

off-CPU:等待下一轮上CPU,或者等待I/O、锁、换页等等,其状态可以细分为可执行、匿名换页、睡眠、锁、空闲等状态

如果大量时间花在CPU上,对CPU的剖析能够迅速解释原因;如果系统时间大量处于off-cpu状态,定位问题就会费时很多。

分析方法与工具

在观察CPU性能的时候,按照负载特征归纳的方法,可以检查如下清单:

整个系统范围内的CPU负载如何,CPU使用率如何,单个CPU的使用率呢?
CPU负载的并发程度如何?是单线程吗?有多少线程?
哪个应用程序在使用CPU,使用了多少?
哪个内核线程在使用CPU,使用了多少?
中断的CPU用量有多少?
用户空间和内核空间使用CPU的调用路径是什么样的?
遇到了什么类型的停滞周期?
要回答上面的问题,使用系统性能分析工具最经济和直接,这里列举的工具足够回答上面的问题:

工具 描述
uptime 平均负载
vmstat 包括系统范围的CPU平均负载
top 监控每个进程/线程CPU用量
pidstat 每个进程/线程CPU用量分解
ps 进程状态
perf CPU剖析和跟踪,性能计数器分析
上述问题中,调用路径和停滞周期的分析可以使用perf工具,也可以使用DTrace等更灵活的工具。其中perf支持对各类内核时间的跟踪计数统计,可以使用perf list查看。例如停滞周期分析可能十分复杂,需要对CPU和调度器架构有较系统的认识和了解,停滞的周期可能发生在一级、二级或者三级缓存,如缓存未命中,也可能是内存IO和资源IO上的停滞周期,perf中有诸如L1-dcahce-loads,L1-icache-loads等事件的计数统计。

实际案例

火焰图帮助分析CPU的调用路径

我们在压测mysql在某机型上的非原地更新性能时,分析mysql服务器延时情况时,分析了CPU上主要的函数调用。使用perf top能够看到调用次数的排名,但是调用关系不能展示出来。火焰图很清晰地提供了调用关系的视图(如下两图中的比例不同是因为perf top加了-p参数,火焰图分析是针对整个系统)。



内存

认识内存

如前所述,内存是为提高效率而生,实际分析问题的时候,内存出现问题可能不只是影响性能,而是影响服务或者引起其他问题。同样对于内存有些概念需要清楚:

主存
虚拟内存
常驻内存
地址空间
OOM
页缓存
缺页
换页
交换空间
交换
用户分配器libc、glibc、libmalloc和mtmalloc
LINUX内核级SLUB分配器
分析方法与工具

Brendan在书中给出了一些问题,比如内存总线的平衡性,NUMA系统中,内存是否被分配到合适的节点中去等等,这些问题在实际分析问题的时候,并不能作为切入点,需要持续的分析。因此笔者简化为如下清单:

系统范围内的物理内存和虚拟内存使用率
换页、交换、oom的情况
内核和文件系统缓存的使用情况
进程的内存用于何处
进程为何分配内存
内核为何分配内存
哪些进程在持续地交换
进程或者内存是否存在内存泄漏?
内存的分析工具如下:

工具 描述
free 缓存容量统计信息
vmstat 虚拟内存统计信息
top 监视每个进程的内存使用情况
ps 进程状态
Dtrace 分配跟踪
除了DTrace,所有的工具只能回答信息统计,进程的内存使用情况等等,至于是否发生内存泄漏等,只能通过分配跟踪。但是DTrace需要对内核函数有很深入的了解,通过D语言编写脚本完成跟踪。Perf也有一些诸如cache-miss、page-faults的事件用于跟踪,但是并不直观。

实际案例

关于内存泄漏,从监控和顶层观察很难发现问题,一般都是从底层程序代码来分析,案例中使用各种观察工具和跟踪工具都不能很确定原因所在,只能通过分析代码来排查问题。最终发现是lua脚本语言分配内存速度快,包驱动的周期性服务的用法中,lua自动回收不能迅速释放内存,而是集中回收,如果频繁回收又可能带来CPU的压力。开发项目组最后采用的解决方式为分步回收,每次回收一部分内存,然后周期性全量回收。

IO

逻辑IO vs 物理IO

通常在讨论问题时,总是会分析IO的负载,IO的负载通常指的是磁盘IO,也就是物理IO,例如我们使用iostat获取的avgqu-sz、svctm和until等指标。因为我们的读写最终都是来自或者去往磁盘的,关注磁盘的IO情况非常正确。但是我们在进行读写操作的时候,面向的对象大多数时候并不会直接面向磁盘,而是面向文件系统的,除非使用raw io的方式。

如下图为通用的IO结构图,如果你想了解更详细,可以查看第二张图片。

我们知道LINUX通过文件系统将所有的硬件设备甚至网络都抽象为文件来管理,例如read()调用时,实际就是就是调用了vfs_read函数,文件系统会确认请求的数据是否在页缓存中,如果不在内存中,于是将请求发送到块设备;此时内核会先获取到数据在物理设备上的实际位置,然后将读请求发送给块设备的请求队列中,IO调度器会通过一定的调度算法,将请求发送给磁盘设备驱动层,执行真正的读操作。在这一过程中可能发生哪些情况呢?如果应用程序执行的是大量的顺序读会怎样?随机读又会怎样?如果是顺序读,正确的做法就是进行预读,让请求的数据落到内存中,提升读效率。所以在应用程序发起一次读,从文件系统到磁盘的过程中,存在读放大的问题。



在写操作时同样存在类似的情况,应用程序发起对文件系统的IO操作,物理IO与应用程序之间,有时候会显得无关、间接、放大或者缩小。

无关:

其他的应用程序:磁盘IO来自其他的应用程序,如监控,agent等
其他用户:如同虚拟机母机下的其他用户
其他内核任务:如重建raid,校验等
间接:

文件系统预读:增加额外的IO,但是可能预读的数据无用
文件系统缓冲:写缓存推迟或者合并回写磁盘,造成磁盘瞬时IO压力
放大:

文件系统元数据:增大额外的IO
文件系统记录尺寸:向上对齐等增加了IO大小
缩小:

文件系统缓存:直接读取缓存,而不需要操作磁盘
合并:一次性回写磁盘
文件系统抵消:同一地址更新多次,回写磁盘时只保留最后一次修改
压缩:减少数据量