一、前提
我们可以在文章的开始就列出一个列表,列出可能影响Linux *** 作系统性能的一些调优参数,但这样做其实并没有什么价值。因为性能调优是一个非常困难的任务,它要求对硬件、 *** 作系统、和应用都有着相当深入的了解。如果性能调优非常简单的话,那些我们要列出的调优参数早就写入硬件的微码或者 *** 作系统中了,我们就没有必要再继续读这篇文章了。正如下图所示,服务器的性能受到很多因素的影响。
当面对一个使用单独IDE硬盘的,有20000用户的数据库服务器时,即使我们使用数周时间去调整I/O子系统也是徒劳无功的,通常一个新的驱动或者应用程序的一个更新(如SQL优化)却可以使这个服务器的性能得到明显的提升。正如我们前面提到的,不要忘记系统的性能是受多方面因素影响的。理解 *** 作系统管理系统资源的方法将帮助我们在面对问题时更好的判断应该对哪个子系统进行调整。
二、Linux的CPU调度
任何计算机的基本功能都十分简单,那就是计算。为了实现计算的功能就必须有一个方法去管理计算资源、处理器和计算任务(也被叫做线程或者进程)。非常感谢Ingo Molnar,他为Linux内核带来了O(1)CPU调度器,区别于旧有的O(n)调度器,新的调度器是动态的,可以支持负载均衡,并以恒定的速度进行 *** 作。
新调度器的可扩展性非常好,无论进程数量或者处理器数量,并且调度器本身的系统开销更少。新调取器的算法使用两个优先级队列。
引用
・活动运行队列
・过期运行队列
调度器的一个重要目标是根据优先级权限有效地为进程分配CPU 时间片,当分配完成后它被列在CPU的运行队列中,除了 CPU 的运行队列之外,还有一个过期运行队列。当活动运行队列中的一个任务用光自己的时间片之后,它就被移动到过期运行队列中。在移动过程中,会对其时间片重新进行计算。如果活动运行队列中已经没有某个给定优先级的任务了,那么指向活动运行队列和过期运行队列的指针就会交换,这样就可以让过期优先级列表变成活动优先级的列表。通常交互式进程(相对与实时进程而言)都有一个较高的优先级,它占有更长的时间片,比低优先级的进程获得更多的计算时间,但通过调度器自身的调整并不会使低优先级的进程完全被饿死。新调度器的优势是显著的改变Linux内核的可扩展性,使新内核可以更好的处理一些有大量进程、大量处理器组成的企业级应用。新的O(1)调度器包含仔2.6内核中,但是也向下兼容2.4内核。
新调度器另外一个重要的优势是体现在对NUMA(non-uniform memory architecture)和SMP(symmetric multithreading processors)的支持上,例如INTEL@的超线程技术。
改进的NUMA支持保证了负载均衡不会发生在CECs或者NUMA节点之间,除非发生一个节点的超出负载限度。
三、Linux的内存架构
今天我们面对选择32位 *** 作系统还是64位 *** 作系统的情况。对企业级用户它们之间最大的区别是64位 *** 作系统可以支持大于4GB的内存寻址。从性能角度来讲,我们需要了解32位和64位 *** 作系统都是如何进行物理内存和虚拟内存的映射的。
在上面图示中我们可以看到64位和32位Linux内核在寻址上有着显著的不同。
在32位架构中,比如IA-32,Linux内核可以直接寻址的范围只有物理内存的第一个GB(如果去掉保留部分还剩下896MB),访问内存必须被映射到这小于1GB的所谓ZONE_NORMAL空间中,这个 *** 作是由应用程序完成的。但是分配在ZONE_HIGHMEM中的内存页将导致性能的降低。
在另一方面,64位架构比如x86-64(也称作EM64T或者AMD64)。ZONE_NORMAL空间将扩展到64GB或者128GB(实际上可以更多,但是这个数值受到 *** 作系统本身支持内存容量的限制)。正如我们看到的,使用64位 *** 作系统我们排除了因ZONE_HIGHMEM部分内存对性能的影响的情况。
实际中,在32位架构下,由于上面所描述的内存寻址问题,对于大内存,高负载应用,会导致死机或严重缓慢等问题。虽然使用hugemen核心可缓解,但采取x86_64架构是最佳的解决办法。
四、虚拟内存管理
因为 *** 作系统将内存都映射为虚拟内存,所以 *** 作系统的物理内存结构对用户和应用来说通常都是不可见的。如果想要理解Linux系统内存的调优,我们必须了解Linux的虚拟内存机制。应用程序并不分配物理内存,而是向Linux内核请求一部分映射为虚拟内存的内存空间。如下图所示虚拟内存并不一定是映射物理内存中的空间,如果应用程序有一个大容量的请求,也可能会被映射到在磁盘子系统中的swap空间中。
另外要提到的是,通常应用程序不直接将数据写到磁盘子系统中,而是写入缓存和缓冲区中。Bdflush守护进程将定时将缓存或者缓冲区中的数据写到硬盘上。
Linux内核处理数据写入磁盘子系统和管理磁盘缓存是紧密联系在一起的。相对于其他的 *** 作系统都是在内存中分配指定的一部分作为磁盘缓存,Linux处理内存更加有效,默认情况下虚拟内存管理器分配所有可用内存空间作为磁盘缓存,这就是为什么有时我们观察一个配置有数G内存的Linux系统可用内存只有20MB的原因。
同时Linux使用swap空间的机制也是相当高效率的,如上图所示虚拟内存空间是由物理内存和磁盘子系统中的swap空间共同组成的。如果虚拟内存管理器发现一个已经分配完成的内存分页已经长时间没有被调用,它将把这部分内存分页移到swap空间中。经常我们会发现一些守护进程,比如getty,会随系统启动但是却很少会被应用到。这时为了释放昂贵的主内存资源,系统会将这部分内存分页移动到swap空间中。上述就是Linux使用swap空间的机制,当swap分区使用超过50%时,并不意味着物理内存的使用已经达到瓶颈了,swap空间只是Linux内核更好的使用系统资源的一种方法。
简单理解:Swap usage只表示了Linux管理内存的有效性。对识别内存瓶颈来说,Swap In/Out才是一个比较又意义的依据,如果Swap In/Out的值长期保持在每秒200到300个页面通常就表示系统可能存在内存的瓶颈。下面的事例是好的状态:
引用
# vmstat
procs ———–memory————- —swap– —–io—- –system– —-cpu—-
r b swpd free buff cache si so bi bo in cs us sy id wa
1 0 5696 6904 28192 50496 0 0 88 117 61 29 11 8 80 1
五、模块化的I/O调度器
就象我们知道的Linux2.6内核为我们带来了很多新的特性,这其中就包括了新的I/O调度机制。旧的2.4内核使用一个单一的I/O调度器,2.6 内核为我们提供了四个可选择的I/O调度器。因为Linux系统应用在很广阔的范围里,不同的应用对I/O设备和负载的要求都不相同,例如一个笔记本电脑和一个10000用户的数据库服务器对I/O的要求肯定有着很大的区别。
引用
(1).Anticipatory
anticipatory I/O调度器创建假设一个块设备只有一个物理的查找磁头(例如一个单独的SATA硬盘),正如anticipatory调度器名字一样,anticipatory调度器使用“anticipatory”的算法写入硬盘一个比较大的数据流代替写入多个随机的小的数据流,这样有可能导致写 I/O *** 作的一些延时。这个调度器适用于通常的一些应用,比如大部分的个人电脑。
(2).Complete Fair Queuing (CFQ)
Complete Fair Queuing(CFQ)调度器是Red Flag DC Server 5使用的标准算法。CFQ调度器使用QoS策略为系统内的所有任务分配相同的带宽。CFQ调度器适用于有大量计算进程的多用户系统。它试图避免进程被饿死和实现了比较低的延迟。
(3).Deadline
deadline调度器是使用deadline算法的轮询的调度器,提供对I/O子系统接近实时的 *** 作,deadline调度器提供了很小的延迟和维持一个很好的磁盘吞吐量。如果使用deadline算法请确保进程资源分配不会出现问题。
(4).NOOP
NOOP调度器是一个简化的调度程序它只作最基本的合并与排序。与桌面系统的关系不是很大,主要用在一些特殊的软件与硬件环境下,这些软件与硬件一般都拥有自己的调度机制对内核支持的要求很小,这很适合一些嵌入式系统环境。作为桌面用户我们一般不会选择它。
六、网络子系统
新的网络中断缓和(NAPI)对网络子系统带来了改变,提高了大流量网络的性能。Linux内核在处理网络堆栈时,相比降低系统占用率和高吞吐量更关注可靠性和低延迟。所以在某些情况下,Linux建立一个防火墙或者文件、打印、数据库等企业级应用的性能可能会低于相同配置的Windows服务器。
在传统的处理网络封包的方式中,如下图蓝色箭头所描述的,一个以太网封包到达网卡接口后,如果MAC地址相符合会被送到网卡的缓冲区中。网卡然后将封包移到 *** 作系统内核的网络缓冲区中并且对CPU发出一个硬中断,CPU会处理这个封包到相应的网络堆栈中,可能是一个TCP端口或者Apache应用中。
这是一个处理网络封包的简单的流程,但从中我们可以看到这个处理方式的缺点。正如我们看到的,每次适合网络封包到达网络接口都将对CPU发出一个硬中断信号,中断CPU正在处理的其他任务,导致切换动作和对CPU缓存的 *** 作。你可能认为当只有少量的网络封包到达网卡的情况下这并不是个问题,但是千兆网络和现代的应用将带来每秒钟成千上万的网络数据,这就有可能对性能造成不良的影响。
正是因为这个情况,NAPI在处理网络通讯的时候引入了计数机制。对第一个封包,NAPI以传统的方式进行处理,但是对后面的封包,网卡引入了POLL 的轮询机制:如果一个封包在网卡DMA环的缓存中,就不再为这个封包申请新的中断,直到最后一个封包被处理或者缓冲区被耗尽。这样就有效的减少了因为过多的中断CPU对系统性能的影响。同时,NAPI通过创建可以被多处理器执行的软中断改善了系统的可扩展性。NAPI将为大量的企业级多处理器平台带来帮助,它要求一个启用NAPI的驱动程序。在今天很多驱动程序默认没有启用NAPI,这就为我们调优网络子系统的性能提供了更广阔的空间。
七、理解Linux调优参数
因为Linux是一个开源 *** 作系统,所以又大量可用的性能监测工具。对这些工具的选择取决于你的个人喜好和对数据细节的要求。所有的性能监测工具都是按照同样的规则来工作的,所以无论你使用哪种监测工具都需要理解这些参数。下面列出了一些重要的参数,有效的理解它们是很有用处的。
(1)处理器参数
引用
・CPU utilization
这是一个很简单的参数,它直观的描述了每个CPU的利用率。在xSeries架构中,如果CPU的利用率长时间的超过80%,就可能是出现了处理器的瓶颈。
・Runable processes
这个值描述了正在准备被执行的进程,在一个持续时间里这个值不应该超过物理CPU数量的10倍,否则CPU方面就可能存在瓶颈。
・Blocked
描述了那些因为等待I/O *** 作结束而不能被执行的进程,Blocked可能指出你正面临I/O瓶颈。
・User time
描述了处理用户进程的百分比,包括nice time。如果User time的值很高,说明系统性能用在处理实际的工作。
・System time
描述了CPU花费在处理内核 *** 作包括IRQ和软件中断上面的百分比。如果system time很高说明系统可能存在网络或者驱动堆栈方面的瓶颈。一个系统通常只花费很少的时间去处理内核的 *** 作。
・Idle time
描述了CPU空闲的百分比。
・Nice time
描述了CPU花费在处理re-nicing进程的百分比。
・Context switch
系统中线程之间进行交换的数量。
・Waiting
CPU花费在等待I/O *** 作上的总时间,与blocked相似,一个系统不应该花费太多的时间在等待I/O *** 作上,否则你应该进一步检测I/O子系统是否存在瓶颈。
・Interrupts
Interrupts 值包括硬Interrupts和软Interrupts,硬Interrupts会对系统性能带来更多的不利影响。高的Interrupts值指出系统可能存在一个软件的瓶颈,可能是内核或者驱动程序。注意Interrupts值中包括CPU时钟导致的中断(现代的xServer系统每秒1000个 Interrupts值)。
(2)内存参数
引用
・Free memory
相比其他 *** 作系统,Linux空闲内存的值不应该做为一个性能参考的重要指标,因为就像我们之前提到过的,Linux内核会分配大量没有被使用的内存作为文件系统的缓存,所以这个值通常都比较小。
・Swap usage
这 个值描述了已经被使用的swap空间。Swap usage只表示了Linux管理内存的有效性。对识别内存瓶颈来说,Swap In/Out才是一个比较又意义的依据,如果Swap In/Out的值长期保持在每秒200到300个页面通常就表示系统可能存在内存的瓶颈。
・Buffer and cache
这个值描述了为文件系统和块设备分配的缓存。在Red Flag DC Server 5版本中,你可以通过修改/proc/sys/vm中的page_cache_tuning来调整空闲内存中作为缓存的数量。
・Slabs
描述了内核使用的内存空间,注意内核的页面是不能被交换到磁盘上的。
・Active versus inactive memory
提供了关于系统内存的active内存信息,Inactive内存是被kswapd守护进程交换到磁盘上的空间。
(3)网络参数
引用
・Packets received and sent
这个参数表示了一个指定网卡接收和发送的数据包的数量。
・Bytes received and sent
这个参数表示了一个指定网卡接收和发送的数据包的字节数。
・Collisions per second
这个值提供了发生在指定网卡上的网络冲突的数量。持续的出现这个值代表在网络架构上出现了瓶颈,而不是在服务器端出现的问题。在正常配置的网络中冲突是非常少见的,除非用户的网络环境都是由hub组成。
・Packets dropped
这个值表示了被内核丢掉的数据包数量,可能是因为防火墙或者是网络缓存的缺乏。
・Overruns
Overruns表达了超出网络接口缓存的次数,这个参数应该和packets dropped值联系到一起来判断是否存在在网络缓存或者网络队列过长方面的瓶颈。
・Errors 这个值记录了标志为失败的帧的数量。这个可能由错误的网络配置或者部分网线损坏导致,在铜口千兆以太网环境中部分网线的损害是影响性能的一个重要因素。
(4)块设备参数
引用
・Iowait
CPU等待I/O *** 作所花费的时间。这个值持续很高通常可能是I/O瓶颈所导致的。
・Average queue length
I/O请求的数量,通常一个磁盘队列值为2到3为最佳情况,更高的值说明系统可能存在I/O瓶颈。
・Average wait
响应一个I/O *** 作的平均时间。Average wait包括实际I/O *** 作的时间和在I/O队列里等待的时间。
・Transfers per second
描述每秒执行多少次I/O *** 作(包括读和写)。Transfers per second的值与kBytes per second结合起来可以帮助你估计系统的平均传输块大小,这个传输块大小通常和磁盘子系统的条带化大小相符合可以获得最好的性能。
・Blocks read/write per second
这个值表达了每秒读写的blocks数量,在2.6内核中blocks是1024bytes,在早些的内核版本中blocks可以是不同的大小,从512bytes到4kb。
・Kilobytes per second read/write
按照kb为单位表示读写块设备的实际数据的数量。
除了保证程序的正确性以外,在项目开发中往往还关心性能和稳定性。我们往往要对内核、应用程序或整个系统进行性能优化。在性能优化中常用的手段如下:
使用top、vmstat、iostat、sysctl等常用工具
top命令用于显示处理器的活动状况。在缺省情况下,显示占用CPU最多的任务,并且每隔5s做一次刷新vmstat命令用于报告关于内核线程、虚拟内存、磁盘、陷阱和CPU活动的统计信息iostat命令用于分析各个磁盘的传输闲忙状况netstat是用来检测网络信息的工具sar用于收集、报告或者保存系统活动信息,其中,sar用于显示数据,sar1和sar2用于收集和保存数据
sysctl是一个可用于改变正在运行中的Linux系统的接口。用sysctl 可以读取几白个以上的系统变量,如用sysctl—a可读取所有变量。
sysctl的实现原理是:所有的内核参数在/proc/sys中形成一个树状结构,sysctl系统调用的内核函数是sys_sysctl,匹配项目后,最后的读写在do_sysctl_strategy中完成。
2.使用高级分析手段,如OProfile、gprof
OProfile可以帮助用户识别诸如模块的占用时间、循环的展开、高速缓存的使用率低、低效的类型转换和冗余 *** 作、错误预测转移等问题。它收集有关处理器事件的信息,其中包括TLB的故障、停机、存储器访问以及缓存命中和未命中的指令的攫取数量。OProfile支持两种采样方式:基于事件的采样(Event Based)和基于时间的采样(Time Based)。基于事件的采样是OProfile只记录特定事件(比如L2缓存未命中)的发生次数,当达到用户设定的定值时Oprofile就记录一下(采一个样)。这种方式需要CPU内部有性能计数器(Performace Counter))。基于时间的采样是OProfile借助OS时钟中断的机制,在每个时钟中断,OProfile都会记录一次(采一次样)。引入它的目的在于,提供对没有性能计数器的CPU的支持,其精度相对于基于事件的采样要低,因为要借助OS时钟中断的支持,对于禁用中断的代码,OProfile不能对其进行分析。
内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。计算机中所有程序的运行都是在内存中进行的,因此内存的性能对计算机的影响非常大。内存作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。只要计算机在运行中,CPU就会把需要运算的数据调到内存中进行运算,当运算完成后CPU再将结果传送出来,内存的运行也决定了计算机的稳定运行。对于整个 *** 作系统来说,内存可能是最麻烦的的设备。而其性能的好坏直接影响着整个 *** 作系统。
我们知道CPU是不能与硬盘打交道的,只有数据被载入到内存中才可以被CPU调用。cpu在访问内存的时候需要先像内存监控程序请求,由监控程序控制和分配内存的读写请求,这个监控程序叫做MMU(内存管理单元)。下面以32位系统来说明内存的访问过程:
32位的系统上每一个进程在访问内存的时候,每一个进程都当做自己有4个G的内存空间可用,这叫虚拟内存(地址),虚拟内存转化成物理内存是通过MMU来完成的。为了能够从线性地址转换成物理地址,需要page table(页表)的内存空间,page table要载入到MMU上。为了完成线性地址到物理地址的映射,如果按照1个字节1个字节映射的话,需要一张非常大的表,这种转换关系会非常的复杂。因此把内存空间又划分成了另外一种存储单元格式,通常为4K。在不同的硬件平台上,它们的大小一般是不一样的,像x86 32位的有4k的页而64位的有4k页,2M页,4M页,8M页等等,默认都是4k的。每一个进程一般而言都有自己的页路径和页表映射机制,不管那一个页表都是由内核加载的。每一个进程只能看到自己的线性地址空间,想要增加新的内存的时候,只能在自己的线性地址空间中申请,并且申请后一定是通过 *** 作系统的内核映射到物理地址空间中去找那么一段空间,并且告诉线性地址空间准备好了,可以访问,并且在page table中增加一条映射关系,于是就可以访问物理内存了,这种叫做内存分配。但是新的申请一定是通过 *** 作的内核到物理内存中去找那么一段空间,并且告诉线性地址空间好了,可以建设映射关系,最终page table建立映射关系。
这反映了上述描述过程的大体情况。可以看到每一个用户程序都会有自己的页表,并且映射到对应的主存储器上去。
根据上述文字和图表的描述可以发现2个问题:
1.每个进程如果需要访问内存的时候都需要去查找page table的话,势必会造成服务器的性能底下
2.如果主存储器的内存满了以后,应用程序还需要调用内存的时候怎么办
对于第一个问题,我们就需要借助TLB(Translation Lookaside Buffer)翻译后备缓冲器。TLB是一个内存管理单元,它可以用于改进虚拟地址到物理地址转换速度的缓存。这样每次在查找page table的时候就可以先去TLB中查找相应的页表数据,如果有就直接返回,没有再去查找page table,并把查找到的结果缓存中TLB中。TLB虽然解决了缓存的功能,但是在那么page table中查找映射关系仍然很慢,所以又有了page table的分级目录。page table可以分为1级目录,2级目录和偏移量
但是一个进程在运行的时候要频繁的打开文件,关闭文件。这就意味着要频繁的申请内存和释放内存。有些能够在内存中缓存数据的那些进程,他们对内存的分配和回收更多,那么每一次分配都会在页表中建立一个对应项。所以,就算内存的速度很快,大量频繁的同一时间分配和释放内存,依然会降低服务器的整体性能。当然内存空间不够用的时候,我们称为oom(out of memory,内存耗尽)。当内存耗尽的时候,,整个 *** 作系统挂了。这种情况下我们可以考虑交换分区,交换分区毕竟是由硬盘虚拟出来的内存,所以其性能与真正的内存相比,差了很多,所以要尽力避免使用交换分区。有物理内存空间的时候尽量保证全部使用物理内存。cpu无论如何是不能给交换内存打交道的,它也只能给物理内存打交道,能寻址的空间也只能是物理内存。所以当真正物理内存空间不够用的时候,会通过LRU算法把其中最近最少使用的内存放到交换内存中去,这样物理内存中的那段空间就可以供新的程序使用了。但是这样会引发另外的一个问题,即原来的进程通过page table寻找的时候,那一段空间的数据已经不属于它了。所以此刻cpu发送通知或者异常告诉这个程序,这个地址空间已不属于它,这个时候可能会出现2种情况:
1.物理内存有可用的空间可用:这个时候cpu会根据以前的转换策略会把交换分区中的那段内存重新送到物理内存中去,但是转换过来的空间地址不一定会是以前的那一段空间地址,因为以前的那一段空间地址可能已经被别人使用了。
2.物理内存没有可用的空间可用:这个时候依然会使用LRU算发把当前物理地址空间上最近最少使用的空间地址转换到交换内存中去,并把当前进程需要的这断在交换空间中的内存送到物理内存空间中去,并且重新建立映射关系。
上述通知或者异常出现的情况,通常叫做缺页异常。缺页异常也分为大异常和小异常两种。大异常就是访问的数据内存中没有,不的不去硬盘上加载,无论是从交换内存中还是直接从磁盘的某个文件系统上,反正需要从硬盘上去加载,这种异常加载需要很长时间。小异常就是进程之间通过共享内存,第二个进程访问的时候,查看本地的内存映射表没有,但是其它进程已经拥有了这个内存页,所以可以直接映射,这种异常加载需要的时间一般很短。
在 *** 作系统开机的时候,每一个io设备都会像cpu申请一些列的随机端口,这种端口叫做io端口。在IBM PC体系结构中,I/O地址空间一共提供了65,536个8位的I/O端口。正是这些io端口的存在,cpu可以与io设备进行读写交互的过程。在执行读写 *** 作时,CPU使用地址总线选择所请求的I/O端口,使用数据总线在CPU寄存器和端口之间传送数据。I/O端口还可以被映射到物理地址空间:因此,处理器和I/O设备之间的通信就可以直接使用对内存进行 *** 作的汇编语言指令(例如,mov、and、or等等)。现代的硬件设备更倾向于映射I/O,因为这样处理的速度较快,并可以和DMA结合起来使用。这样io在和内存传数据的时候就不需要通过cpu,cpu把总线的控制权交给DMA,每次io传数据的时候就调用DMA一次,就把cpu给解放了出来。当数据传输完了以后,DMA通知给cpu中断一次。DMA在运行的时候对整个总线有控制权限,当cpu发现有其它进程需要使用总线的时候,二者就会产生争用。这个时候,在总线控制权的使用上,CPU和DMA具有相等的权限。只要CPU委托给了DMA,就不能随意的收回这个委托,就要等待DMA的用完。
如果没有其它进程可以运行,或者其它进程运行的时间非常短,这个时候CPU发现我们的IO仍然没有完成,那就意味着,CPU只能等待IO了。CPU在时间分配里面有个iowait的值,就是CPU在等待IO花费的时间。有些是在同步调用过程中,CPU必须要等待IO的完成否者CPU可以释放IO的传输在背后自动完成,CPU自己去处理其它的事情。等硬盘数据传输完成以后,硬盘只需要像CPU发起一个通知即可。CPU外围有一种设备,这个设备叫做可编程中断控制器。每一个硬件设备为了给CPU通信,在刚开机的时候,在BIOS实现检测的时候,这个设备就要到可编程中断控制器上去注册一个所谓的中断号。那么这个号码就归这个硬件使用了。当前主机上可能有多个硬件,每一个硬件都有自己的号码,CPU在收到中断号以后,就能够通过中断相量表查找到那个硬件设备进行中断。并且就由对应的IO端口过来处理了。
CPU正在运行其它进程,当一个中断请求发过来的时候,CPU会立即终止当前正在处理的进程,而去处理中断。当前CPU挂起当前正在处理的进程,转而去执行中断的过程,也叫做中断切换。只不过,这种切换在量级别上比进程切换要低一些,而且任何中断的优先级通常比任何进程也要高,因为我们指的是硬件中断。中断还分为上半部和下半部,一般而言,上半部就是CPU在处理的时候,把它接进来,放到内存中,如果这个事情不是特别紧急(CPU或者内核会自己判断),因此在这种情况下,CPU回到现场继续执行刚才挂起的进程,当这个进程处理完了,再回过头来执行中断的下半部分。
在32位系统中,我们的内存(线性地址)地址空间中,一般而言,低地址空间有一个G是给内核使用的,上面3个G是给进程使用的。但是应该明白,其实在内核内存当中,再往下,不是直接这样划分的。32位系统和64位系统可能不一样(物理地址),在32位系统中,最低端有那么10多M的空间是给DMA使用的。DNA的总线宽度是很小的,可能只有几位,所以寻址能力很有限,访问的内存空间也就很有限。如果DMA需要复制数据,而且自己能够寻址物理内存,还可以把数据直接壮哉进内存中去,那么就必须保证DMA能够寻址那段内存才行。寻址的前提就是把最低地址断M,DA的寻址范围内的那一段给了DMA。所以站在这个角度来说,我们的内存管理是分区域的。
在32位系统上,16M的内存空间给了ZONE_DMA(DMA使用的物理地址空间)从16M到896M给了ZONE_NORMAL(正常物理地址空间),对于Linux *** 作系统来说,是内核可以直接访问的地址空间从896M到1G这断空间叫做"Reserved"(预留的物理地址空间)从1G到4G的这段物理地址空间中,我们的内核是不能直接访问的,要想访问必须把其中的一段内容映射到Reserved来,在Reserved中保留出那一段内存的地址编码,我们内核才能上去访问,所以内核不直接访问大于1G的物理地址空间。所以在32位系统上,它访问内存当中的数据,中间是需要一个额外步骤的。
在64位系统上,ZONE_DAM给了低端的1G地址空间,这个时候DMA的寻址能力被大大加强了ZONE_DAM32可以使用4G的空间而大于1G以上给划分了ZONE_NORMAL,这段空间都可以被内核直接访问。所以在64位上,内核访问大于1G的内存地址,就不需要额外的步骤了,效率和性能上也大大增加,这也就是为什么要使用64位系统的原因。
在现在的PC架构上,AMD,INTER都支持一种机制,叫做PEA(物理地址扩展)。所谓PAE。指的是在32位系统的地址总线上,又扩展了4位,使得32位系统上的地址空间可以达到64G。当然在32为系统上,不管你的物理内存有多大,单个进程所使用的空间是无法扩展的。因为在32位的系统上,线性地址空间只有4个G,而单个进程能够识别的访问也只有3个G。
linux的虚拟内存子系统包含了以下几个功能模块:
slab allocator,zoned buddy allocator,MMU,kswapd,bdflush
slab allocator叫做slab分配器
buddy allocator又叫做buddy system,叫做伙伴系统,也是一种内存分配器
buddy system是工作在MMU之上的,而slab allocator又是工作在buddy system之上的。
设置为小于等于1G,在数据库服务器应该劲量避免使用交换内存
3.在应用服务器上,可以设置为RAM*0.5,当然这个是理论值
如果不的不使用交换内存,应该把交换内存放到最靠外的磁道分区上,因为最外边的磁盘的访问速度最快。所以如果有多块硬盘,可以把每块硬盘的最外层的磁道拿一小部分出来作为交换分区。交换分区可以定义优先级,因此把这些硬盘的交换内存的优先级设置为一样,可以实现负载均衡的效果。定义交换分区优先级的方法为编辑/etc/fstab:
/dev/sda1 swap swap pri=5 0 0
/dev/sdb1 swap swap pri=5 0 0
/dev/sdc1 swap swap pri=5 0 0
/dev/sdd1 swap swap pri=5 0 0
四.内存耗尽时候的相关调优参数
当Linux内存耗尽的时候,它会杀死那些占用内存最多的进程,以下三种情况会杀死进程:
1.所有的进程都是活动进程,这个时候想交换出去都没有空闲的进程
2.没有可用的page页在ZONE_NORMAL中
3.有其它新进程启动,申请内存空间的时候,要找一个空闲内存给做映射,但是这个时候找不到了
一旦内存耗尽的时候, *** 作系统就会启用oom-kill机制。
在/proc/PID/目录下有一个文件叫做oom_score,就是用来指定oom的评分的,就是坏蛋指数。
如果要手动启用oom-kill机制的话,只需要执行echo f>/proc/sysrq-trigger即可,它会自动杀掉我们指定的坏蛋指数评分最高的那个进程
可以通过echo n >/proc/PID/oom_adj来调整一个进程的坏蛋评分指数。最终的评分指数就是2的oom_adj的值的N次方。假如我们的一个进程的oom_adj的值是5,那么它的坏蛋评分指数就是2的5次方。
如果想禁止oom-kill功能的使用可以使用vm.panic_on_oom=1即可。
五.与容量有关的内存调优参数:
overcommit_memory,可用参数有3个,规定是否能够过量使用内存:
0:默认设置,内核执行启发式的过量使用处理
1:内核执行无内存的过量使用处理。使用这个值会增大内存超载的可能性
2:内存的使用量等于swap的大小+RAM*overcommit_ratio的值。如果希望减小内存的过度使用,这个值是最安全的
overcommit_ratio:将overcommit_memory指定为2时候,提供的物理RAM比例,默认为50
六.与通信相关的调优参数
常见在同一个主机中进行进程间通信的方式:
1.通过消息message2.通过signal信号量进行通信3.通过共享内存进行通信,跨主机常见的通信方式是rpc
以消息的方式实现进程通信的调优方案:
msgmax:以字节为单位规定消息队列中任意消息的最大允许大小。这个值一定不能超过该队列的大小(msgmnb),默认值为65536
msgmnb:以字节为单位规定单一消息队列的最大值(最大长度)。默认为65536字节
msgmni:规定消息队列识别符的最大数量(及队列的最大数量)。64位架构机器的默认值为198532位架构机器的默认值为1736
以共享内存方式实现进程通信的调优方案:
shmall:以字节为单位规定一次在该系统中可以使用的共享内存总量(单次申请的上限)
shmmax:以字节为单位规定每一个共享内存片段的最大大小
shmmni:规定系统范围内最大共享内存片段。在64和32位的系统上默认值都是4096
七.与容量相关的文件系统可调优参数:
file-max:列出内核分配的文件句柄的最大值
dirty_ratio:规定百分比值,当脏数据达到系统内存总数的这个百分比值后开始执行pdflush,默认为20
dirty_background_ratio:规定百分比值,当某一个进程自己所占用的脏页比例达到系统内存总数的这个百分比值后开始在后台执行pdflush,默认为10
dirty_expire_centisecs:pdlush每隔百分之一秒的时间开启起来刷新脏页,默认值为3000,所以每隔30秒起来开始刷新脏页
dirty_writeback_centisecs:每隔百分之一秒开始刷新单个脏页。默认值为500,所以一个脏页的存在时间达到了5秒,就开始刷新脏
八.linux内存常用的观察指标命令:
Memory activity
vmstat [interval] [count]
sar -r [interval] [count]
Rate of change in memory
sar -R [interval] [count]
frmpg/s:每秒释放或者分配的内存页,如果为正数,则为释放的内存页如果为负数,则为分配的内存页
bufpg/s:每秒buffer中获得或者释放的内存页。如果为正数则为获得的内存页,为负数。则为释放的内存页
campg/s:每秒cache中获得或者释放的内存页。如果为正数则为获得的内存页,为负数。则为释放的内存页
Swap activity
sar -W [interval] [count]
ALL IO
sar -B [interval] [count]
pgpgin/s:每秒从磁盘写入到内核的块数量
pgpgout/s:每秒从内核写入到磁盘的块数量
fault/s:每秒钟出现的缺页异常的个数
majflt/s:每秒钟出现的大页异常的个数
pgfree/s:每秒回收回来的页面个数
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)