Linux在进行系统调优的时候,首先要考虑整个操作系统的结构,然后针对各个部分进行优化,下面展示一个Linux系统的各个组成部分:

Linux系统调优1_优先级


有上图可以看出,我们可以调整的有应用程序,库文件,内核,驱动,还有硬件本身,所以接下来讲对这些进行详细的介绍,从而是系统的性能有所提高。


内核子系统中主要包括一下几个方面:


1.         network(网络)


2.         IO(输入输出子系统)


3.         process(进程)


4.         memory(内存)


5.         File System(文件系统)


一、    Linux的进程管理


1、进程的定义:进程是计算机资源分配单位,主要包括对系统资源的调度,如CPU时间,内存空间,是一个程序执行的一个副本。他们还包括一系列的资源,如文件的打开,释放信号,内核内的数据,进程状态,内存地址的映射,执行的多个线程,和数据段的全局变量。


2、进程状态:running(运行)、interruptible(可中断的睡眠态)、unitertible(非可中断的睡眠态)、stopped(停止状态)、zombie(僵死态)


Linux系统调优1_优先级_02


 


Task_Running:一个进程要么在CPU上执行,要么等待CPU的时间再执行;


Task_Interruptible:一个处于sleeping状态的进程,直到环境条件改变,重新挂起一个硬件中断,使用系统释放的资源,或者释放一个信号,这个信号可以唤醒这个进程到Task_Running状态,一般是一个IObound类型的;


Task_uninterruptible:这个和Task_Interruptible是一样的,但是CPU bound类型的。


Task_stopped:程序执行已经完成,这个进程在接受到SIGSTOP、SIGTSTP, SIGTTIN, or SIGTTOU signal这些信号的时候,这个进程进入这个状态;


Task_zombie:子进程执行完成,但是该子进程的父进程已近dead,无法回收这个子进程所占用的资源;


3、进程周期:一个子进程都是父进程的一个副本,所以除了PID和PPID不同,其他的都是相同的,而子进程在执行一个程序的时候,需要在单独在一个地址空间内进行,当执行完成之后,子进程锁占用的资源要有父进程进行回收,这就是一个进程的生命周期;


4、线程的概念:线程是比进程资源更小的资源调度单位,所以也叫轻量级的进程(LWP)


而线程的调度更加节省系统的资源,如果使用的是进程,即使是相同的进程也需要分配两份资源,而线程就不同了,它可以在同一个进程中实现资源的重复利用,这就是nginx的性能比使用apache性能要好的原因,因为nginx是基于线程的,而apache的prefork模式的是基于进程的,每一个进程连接都要分配4M的空间,而每一个线程确非配4k由此可以找出显著的差别了,关于进程和线程资源调分配对比,我给大家准备了一个图,可以简单的看出他们之间的区别:


Linux系统调优1_地址空间_03


5、进程的调度:进程调度就是按照一定的调度算法,来实现不同进程之间的切换,常见的调度算法有一下几种:


O(1)调度器<2.6之后>这种在调度的时候一秒一个,能实现公平的调度,公平分配时间,但是再有的时候会浪费时间,如edit和movie之间,edit就会浪费时间。


O(log n)


O(n)


O(n^2)


O(2^n)


为了解决O(1)的不足,又引用了deadline,deadline有三个队列,活动队列,死亡队列,deadline队列,为不同的进程做一个计数器,到时间就不管进程优先级的高低,而是“见死就救”。(deadline现在在磁盘上使用)现在进程调度使用的是CFS(完全公平调度算法)调度算法:不再为每一个进程分配一个时间片,而是按照进程来分配一个时间比例。


6、进程的种类:交互式进程、批处理进程、实时进程;


7、进程的优先级:


 静态优先级:1-99,100-139


 动态优先级:动态优先级调整的范围100-139,通过调整nice值进行调整,调整后表现为nice值。nice值范围在-20—19


 实时优先级:0-99(数字越大,优先级越高)


8、进程调度策略:


 SCHED_FIFO:先进先出【1-99】,只能调度实时优先级进程;


 SCHED_RR:轮调 引入了时间片,是FIFO改进后的算法,只能调度实时优先级进程;


 SCHED_OTHER:调度传统的分时进程【100-139】;


 SCHED_BATCH:只用来调度nice=0或优先级为120的;


 使用#ps axo comm.,rtprio显示实时优先级;


 


实时进程定义启动使用的调度类别和指定优先级:


chrt  -f [1-99] /path/to/program arguments //添加到FIFO队列中去


chrt  -r [1-99] /path/to/program arguments //添加到RR队列中


nice&&renice调整优先级


查看系统的瓶颈是否是CPU


1.平均负载 yum install sysstat


 负载的三个平均值不能大于3


 w  


 uptime


 top


 sar -q 1 3 


 vmstat 1 5


2.CPU的利用率


 mpstat -p 60%在用户空间就是正常的


 sar -P ALL 1


 iostat -c 1 


 cat /proc/stat


9、cache 缓存:


缓存分为cache-hit和cache-miss


#yum install x86info


#x86info –c 查看cpu的缓存类型


#valgrind --tool=cachegrind ls 查看缓存命中情况


# dmesg | grep -i cache 查看缓存大小


10、多个CPU和多核CPU之间进行均衡


#watch -n .5 'ps axo comm,pid,psr | grep httpd ' 查看进程在哪个CPU上


taskset [opts]


#taskset -c -p CPULIST PID 把某一个进程绑定到一个特定的CPU上


#taskset -c -p 0 5533 把5533进程绑定到0号CPU上


这种能提高缓存命中率,但是对均衡有缺陷


11、调度域:就是将某些进程绑定在多个CPU组成的域中。调度域的作用就是把CPU组定义为调度域,一个CPU集合就是一个调度域,配置本地调度域:


#mkdir /cpusets


#vim /etc/fstab 添加一下内容


cpuset     /cpusets   cpuset     default    0 0


#cd /cpusets


#ls


Linux系统调优1_地址空间_04

#mkdir ro


#cd ro


#echo 0 > cpus 这样就建立了一个ro的调度域,同时绑定到第一个CPU上了;


12、进程的地址空间


一个进程在使用自己的内存空间进行工作的,所以这就导致了每一进程都有自己的地址空间,每一个进程都有自己的特点和数据大小,进程必须持有大量的数据尺寸,对于Linux内核来说,每个进程使用动态内存分配的是结构化的,具体如下图所示:


Linux系统调优1_子进程_05


所以进程可以分为代码段、数据段、BBS、堆、栈。


 


二、      内存管理


1、内存管理要想了解内存的调度机制,下面我就结合下图进行简单的阐述:


Linux系统调优1_优先级_06


我就从左向右一步一步的介绍用户发出个请求,通过调用库文件,有用户空间进入内核空间,在内核空间中把数据从磁盘中读入内存中进行操作,操作完成之后,在同步到磁盘中,而为了提高CPU的工作效率,使用MMU(memory manger unit,内存管理单元)来替代CPU来执行整个进程的调度,在这个过程中,首先要交换分区slab allocator目录找到对应的资源所在的位置,然后到对应的内存空间或磁盘空间中去寻找,当然为了避免内存回收的外碎片,引入了zoned buddy allocator,这个就是合理分配内存资源的,等到进程调度占用的空间使用完成之后,需要回收资源,这里就是用到了pdflush,就是讲内存中dirty pages的数据同步到磁盘上去。


PTE:page tables 页表项


PAE:物理地址扩展


TLB:transition lookaside buffers 转换后缓冲器


只用x86info –c 和 dmesg可以查看


2、内存空间结构:


下图是对32位的系统和64位的系统内存空间的一个对比


Linux系统调优1_缓存_07


由于硬件设备的限制,所以内核不能把所以的page视为相同的,所以出现了如上图的Zone,下面开始详细的介绍这些内容了:


1.在32位的系统上一个单独的进程最大的地址空间是4G(2^32),这4G被分为1G的内核空间和3G的用户空间;其中1G的内核空间是用来做页表的虚拟地址和物理地址进行映射关系的,另外3G是用户空间;


在1G的内核空间中,其中有16MB是用来做DMA(直接内存区域)的,这个区域包括pages;从16MB-896MB这期间的880MB是内核使用的,还有128MB是用来做映射的,从虚拟地址空间映射到物理地址空间上去;而上面的3G就是整整的地址空间了。而对于64位的操作系统的空间,有1G是用来做DMA的,区域的都是用来做实际的地址空间的,所以在服务器上,不带考虑的直接装64位的系统;


2. 通常出现缺页异常的原因:数据还在磁盘上、数据在交换分区上,如果数据持续从交换分区上进行数据调度的话,那么这就直接可以断定是内存瓶颈,内存不够用,剩下的就不解释了,你懂的,扩展内存,呵呵!


3.查看各个进程的资源使用情况的方法:


#cat /proc/PID/status 或cat /proc/PID/statm


Linux系统调优1_优先级_08


然后你就可以查看一下里面的内容了,系统每启动一个进程,都会占用一定的地址空间。


也可以使用图形化界面进行查看


#gnome-system-monitor


#pmap +PID 查看进程对应的库文件,也可以定位内存的瓶颈


 


#yum install glibc-utils


#memusage +COMMAND 查看单个进程占用的内存,同时以条形框的形式展示


#memusage –help可以获取该命令的更多的帮助信息


Linux系统调优1_地址空间_09


#ps axo minflt,majflt 看所有进程的缺页异常发生情况


Linux系统调优1_子进程_10


其中minflt表示的是磁盘的使用情况,而majflt表示交换分区使用的情况,根据这些信息可以判断,如果长期使用交换分区的话,那么就是内存瓶颈了。


4.内存的配额分为一下几种:


 (1)Process forks or execs child process


(2)New process requests memory


(3)New process uses memory


(4)Process frees memory


5.内存的类型:


SRAM:静态(static RAM)


DRAM:动态 (Dynamic RAM)


   SDRAM


   DDR


   RDRAM(服务器上使用,窄带,有奇偶校验的内存)


6、提高TLB的性能


TLB:(transition lookais buffer)转换后援缓冲器,就是存放虚拟地址到物理地址转换的表,也称为页表缓冲;


TLB存放的页面在32位系统上支持4k和4M两种,在其他系统上就更多了,如果想了解,可以借助帮助文档


#yum install kernel-doc


安装完成之后位于 /usr/share/doc/kernel-doc-2.6.18/Documentation中;


如果我们想让TLB的值大点,也就是做成Hugetlb Page(大页表)可以设置内核参数,这样可以提高TLB缓存的命中率,降低PTE的方位次数,来加速地址转换的速度;


调整TLB值的大小:


/etc/sysctl.conf


 vm.nr_hugepages=n


临时生效:


 #echo 4 > /proc/sys/vm/nr_hugepages


 #sysctl -w vm.nr_hugepages=n


永久有效:


 #vim /etc/sysctl.conf


 #sysctl -p 保存,生效


为了以后使用大页表,我们可以做一个大页表文件系统


#mkdir /hugepages


#mount -t hugetlbfs none /hugepages 在以后就如果使用到了,就可以直接使用了;


当然为了详细的观察进程详细的调度情况,也可以追踪系统调用


#strace -p PID 查看进程详细调度的进程


#strace ls 可以看到所发出指令的详细的系统调用


#strace ls -o /tmp/tmp.txt 保存在指定的文件中。


#strace -c -p PID 统计系统调用时间和所调用的次数,结合这些结果进行分析


7、内存使用应遵循的策略:


 a.减小内存小对象的消耗,使用的工具有slab cache


 b.降低那些比较慢的系统服务时间:


    i.文件系统的:buffer cache(slab cache)


    ii.DISK IO: page cache


    iii.Internetprocess:shared memory



    iv.network IO:buffer cache,arp cache,connection tracking (buffer是解决两端速率不匹配的,而cache是为了重复使用,提高缓存命中率的)


结合上面的理论,接下来就是做详细的内存内核参数的调整的过程了:


1、vm.min_free_kbytes 至少要在内存中保留多大的K字节的空间


 说明:当一个应用反复使用和释放大的内存,磁盘的带宽下,CPU使用低下,内存小,需要改变上面的参数,如果改小了,这样就会导致服务时间降低,其他应用程序无法有足够的内存,对zone_nomal照成很大的压力;默认是2890


2、vm.overcommit_memory 内存过度使用,这个参数有三个数值可以设置0,1,2


0|拒绝过度使用(默认)


 1|总是过度使用 (不建议)


 2|仅能使用所有的RAM和swap的一个百分比建议设置为30,50%已经是大的了<这个对启动2才有效>)尽可能根据committed_AS为参照来设置


3、vm.overcommit_ratio 过度使用的比,就是上面swap的比(建议设置为30%,50%已经是较大的了)默认:50


4、调整slab缓存小内存对象,缓存的是文件的innode(索引),每一种slab只能缓存一中小内存对象;


该文件在/proc/slabinfo文件中,我们可以看一下:


Linux系统调优1_子进程_11


这个问价中可以该的值有limit,batchcount,sharedfactor,其中limited=N*batchcount


如:


#echo “ext3_inode_cache 108 27 8” >/proc/slabinfo


#slabtop //查看当前slab分配的信息


同样可以使用vmstat –m 也可以查看当前slab分配信息


Linux系统调优1_子进程_12


5、调整ARP cache:


#cat /proc/net/arp


Linux系统调优1_数据_13


可以看出现在arp缓存


也可以使用一下命令进行查看

#arp –a


#ip neigh show


arp -d hostname 删除arp缓存


ip neighbor flush dev eth0 标记为失效,过一会就会清空


当让为了减少arp cache占用系统资源,可以设置其存储的条目


net.ipv4.neigh.default.gc_thresh1 定义缓存上线,当缓存大于多少的时候就做清理(默认128)


net.ipv4.neigh.default.gc_thresh2 软上线 512


net.ipv4.neigh.default.gc_thresh3 硬上线 1024


net.ipv4.neigh.default.gc_interval 缓存收集垃圾时间 默认30s


这些是对arp缓存大小的设置;


6、page cache :page缓存的是数据;


使用到的场所:直接读、读写、读写快设备、访问内存mapped files、访问swap mapped files


vm.lowmem_reserve_ratio 低地址空间中预留的空间的百分比,一般指的是zone_normal放置OOM(内存地址耗尽);


vm.vfs_cache_pressure 定义内核回收slab cache、pagecache、swapcache中的内存的倾向性,默认是100,如果小于100,倾向性变小,如果设置为0,就不会回收pagecache、swapcache中的内存(不建议),如果经常打开文件,要增大这个值,能快速回收内存,如果有足够大的内存,可以维持在100,一般不需要降低这个值;


vm.page_cluster 页簇:控制物理内存数据交换到交换分区的时候,一次交换的多少个页面数2^n 这个值默认是3,也就是8个页面,应用程序频繁使用交换分区的时候,可以调大点;


vm.zone_reclaim_mode 内存区域回收的模型,当一个区域的内存消耗完的时候,如何回收此区域的空间,其值有:1(打开回收机制)、2(将此内存的章页同步到磁盘在回收)、4(回收交换页面所占用的空间)


7、anonymous pages:匿名页面


匿名页面主要包括程序数据,arrarys,heap,allowcations等


Linux系统调优1_缓存_14


8、SysV IPC interprocess communication 进程间通信:


*1.semaphores 信号


调整:


kernel.sem


cat /proc/sys/kernel/sem


250 每个数组信号量


32000


32


128 可以所使用的数组


*2.Messageing queues 消息队列(rubbit MQ)通过交换信息


调整:


kernel.msgmnb


16384 一个单独的消息队列能容纳多少消息信号


kernel.msgmni


16 消息队列最大消息队列数


kernel.msgmax


8192 单个消息最大上线8k


*3.shared memory 共享内存


调整:


kernel.shmmni


4096 共享内存段的最大数目


kernel.shmall


2097152 一次共享页面的值


kernel.shmmax


shmall*4k 共享内存段的大小可以被创建


 


使用ipcs命令查看当前机器进程间通信的机制


ipcs -l显示进程间通信的限制


Linux系统调优1_子进程_15


如果文件的修改不是太多,可以把数据放在/dev/shm中,这个直接写入内存,但是一旦断电,数据就会丢失


 


9、内存详细使用情况的命令:


free -m 显示内存使用情况


page tables:cat /proc/vmstat 


system memory:cat /proc/meminfo (total physical memory,cache,active use,inactive) 使用vmstat -s


#yum install sysstat


sar -r 1 10 (每个一秒取一次,取十次)


 


10、页面分类:


1.free 


2.inactive clean 可以被直接回收使用


3.inactive dirty 页面中有数据没有同步到磁盘上去,只要同步到磁盘上去了,就能回收


4.active 正在被使用的页面


 


Bubby system:伙伴系统,是避免内存回收的外碎片的,保存内存空间是连续的一片空间


 


内核中的有个线程叫kswapd来回收空闲分区,把内存中使用较少的(非活动clean状态的)放到交换分区,腾出空间供其他的使用


 


使用vmstat -a |-s 显示页框使用状态


 


页面主要作用:page cache 和进程地址空间,所有回收page cache中的页面


 


11、如何回收dirty pages:


1.同步到磁盘上,靠的是pdflush的内核线程(每隔一段时间就会同步,可以多个同时运行的,可以定义pdflush的数目,如CPU,DISK多,可以在一个CPU上一个,提高并发能力)


2.放到交换分区


vm.nr_pdflush_threads 就是定义pdflush线程个数,建议一个磁盘一个pdflush线程


vm.dirty_background_ratio 当脏页总数占整个内存比例的时候,启动pdflush


vm.dirty_ratio 某一个单进程的脏页所占用的比例,然后启动pdflush进行刷写


vm.dirty_expir_centisecs 每隔一段时间进行一次刷写操作(默认30s,0表示禁用)


vm.dirty_writeback_centisecs 默认5s,定义一个数据修改超过这个时间就可以刷写了


 


12、如何回收干净页面:


sync


fsync


echo s > /proc/sysrq-trigger   手动同步到磁盘


echo x > /proc/sys/vm/drop_caches


x=


 1 free pagecache 


 2 free dentries and inodes


 3 buffer and cache


out-of-memory killer进程在内存占用满了,就开始杀死一些进程


/proc/PID/oom_score 进程的分数,分数越大,就会在内存oom的时候最先杀死


 


13、优化OOM策略:


echo n >/proc/PID/oom_adj


echo f > /proc/sysrq-trigger 手动杀死进程


vm.panic_on_oom=1 禁止oom-kill ,但是内存耗尽也会照成系统恐慌


 


14、探测内存泄漏:一个进程退出的时候,内存未释放


内存泄漏分为两种:


 1.虚拟(virtual)内存泄漏:只申请,但不使用


 2.real:内存释放失败


#sar -R 查看内存申请、释放情况,正数是申请的,负数是释放,其中frmpgz正好相反


#yum install valgrind


#valgrand --tool=memcheck ls 查看内存泄漏


**作为管理员要经常关注内存是否泄漏


 


15、swap 交换分区:


swap-out=page-out 就是把内存中的数据放到交换分区


swap-in :把内存中的数据放到交换分区;


 


那些pages要进行交换:


inactive pages


anonymous pages


 


16、提高swap的性能:


1.降低决策时间 :快速换入唤出小页面,匿名pages


2.降低访问次数:做swap集群,多个分区做相同的优先级


3.降低服务时间:尽可能使用分区,不实用文件;尽量把交换分区放到磁盘外道;把交换分区放到raid0上


vm.swappiness 定义多大倾向唤出交换分区的匿名页,里面是一个%比,达到了就使用交换内存,如果不想使用交换分区,可以把值设置小于100,默认是60


 


 


17、交换分区的大小:


批处理服务:> 4*RAM


数据库服务:<=1G


应用程序服务:>=0.5*RAM


 


vm.page_cluster=n (2^n个页面)


vm.swap_token_timeout 一旦发现交换分区频繁的不参与这个的时间


 


18、监控内存工具:


vmstat -n 显示内存和swap分区的数据


sar -r 显示内存和swap分区的数据


sar -R 显示内存的数据


sar -W 像是swqp数据


sar -B 显示页面的数据