Linux在进行系统调优的时候,首先要考虑整个操作系统的结构,然后针对各个部分进行优化,下面展示一个Linux系统的各个组成部分:
有上图可以看出,我们可以调整的有应用程序,库文件,内核,驱动,还有硬件本身,所以接下来讲对这些进行详细的介绍,从而是系统的性能有所提高。
内核子系统中主要包括一下几个方面:
1. network(网络)
2. IO(输入输出子系统)
3. process(进程)
4. memory(内存)
5. File System(文件系统)
一、 Linux的进程管理
1、进程的定义:进程是计算机资源分配单位,主要包括对系统资源的调度,如CPU时间,内存空间,是一个程序执行的一个副本。他们还包括一系列的资源,如文件的打开,释放信号,内核内的数据,进程状态,内存地址的映射,执行的多个线程,和数据段的全局变量。
2、进程状态:running(运行)、interruptible(可中断的睡眠态)、unitertible(非可中断的睡眠态)、stopped(停止状态)、zombie(僵死态)
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由此可以找出显著的差别了,关于进程和线程资源调分配对比,我给大家准备了一个图,可以简单的看出他们之间的区别:
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
#mkdir ro
#cd ro
#echo 0 > cpus 这样就建立了一个ro的调度域,同时绑定到第一个CPU上了;
12、进程的地址空间
一个进程在使用自己的内存空间进行工作的,所以这就导致了每一进程都有自己的地址空间,每一个进程都有自己的特点和数据大小,进程必须持有大量的数据尺寸,对于Linux内核来说,每个进程使用动态内存分配的是结构化的,具体如下图所示:
所以进程可以分为代码段、数据段、BBS、堆、栈。
二、 内存管理
1、内存管理要想了解内存的调度机制,下面我就结合下图进行简单的阐述:
我就从左向右一步一步的介绍用户发出个请求,通过调用库文件,有用户空间进入内核空间,在内核空间中把数据从磁盘中读入内存中进行操作,操作完成之后,在同步到磁盘中,而为了提高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位的系统内存空间的一个对比
由于硬件设备的限制,所以内核不能把所以的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
然后你就可以查看一下里面的内容了,系统每启动一个进程,都会占用一定的地址空间。
也可以使用图形化界面进行查看
#gnome-system-monitor
#pmap +PID 查看进程对应的库文件,也可以定位内存的瓶颈
#yum install glibc-utils
#memusage +COMMAND 查看单个进程占用的内存,同时以条形框的形式展示
#memusage –help可以获取该命令的更多的帮助信息
#ps axo minflt,majflt 看所有进程的缺页异常发生情况
其中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文件中,我们可以看一下:
这个问价中可以该的值有limit,batchcount,sharedfactor,其中limited=N*batchcount
如:
#echo “ext3_inode_cache 108 27 8” >/proc/slabinfo
#slabtop //查看当前slab分配的信息
同样可以使用vmstat –m 也可以查看当前slab分配信息
5、调整ARP cache:
#cat /proc/net/arp
可以看出现在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等
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显示进程间通信的限制
如果文件的修改不是太多,可以把数据放在/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 显示页面的数据