Linux进程管理:
进程是可以运行在处理器CPU上的一个可执行的实例。进程完成工作需要所有linux内核需要的资源。
所有的在linux操作系统上运行的内存都是由task_struct 体系来管理的,也被称为进程描述符。一个进程描述符包括进程运行所需的所有信息,比如:进程号,进程的属性,还有构成进程的所有资源。如果你知道进程的体系,你就可以明白进程执行和结果的关键点。
进程的生命周期:
每一个进程都有它自己的生命周期比如创建,执行,终止和删除。只要系统正在运行,这些阶段会被重复几百万次。因此,进程的生命周期对于进程的执行情况很重要。
当一个进程创建一个新进程的时候,父进程发出一个fork()的系统新号。一个fork()信号发出之后,它为新的进程赋予了一个进程描述符和进程号。它复制了父进程的进程号给子进程。
同时父进程的全部地址空间没有被复制,父进程和子进程共享一个地址空间。
Exec()系统新号给子进程的地址空间一个新的程序。因为,父子进程共享一个地址空间,写一个新的程序数据造成页错误。因此,内核给子进程分配一个新的物理页。
被延迟的操作叫做复制写,子进程通常执行它自己的程序而不是执行父进程的。这个操作节省了不必要的开支,因为复制整个内存地址非常缓慢需要占用很多CPU时间。
当程序执行完之后,子进程会伴随着一个exit()的系统信号结束。Exit()系统新号释放大部分的进程数据结构通知父进程发送一个结束的信号。此时,这个子进程被称为僵尸进程。
直到父进程接收到wait()系统信号,知道子进程结束之后,子进程才彻底被移除。它会删除子进程的数据结构并释放进程描述符。
Linux线程管理
线程是在处理器上执行的单元。它和进程里的其他线程并列的在一个CPU中运行。它们共享内存,地址空间,打开的文件等资源。它们可以进入相同的应用数据。一个线程又被称为轻量级进程。因为他们共享资源,每个线程不能同时改变它们的共享资源。贯彻共有抵制,锁,序列是用户应用的责任。
从表现的角度来讲,线程创造没有进程创造昂贵,因为线程不需要在创建的时候复制资源。换一步说,线程和进程在规划运算的时候有相同的特点。内核用相似的态度来处理他们。
现在的linux执行中,支持UNIX操作系统接口标准。
Linux进程优先级和亲和力的等级
进程优先级是个决定进程在CPU中运行顺序的值,被动态的和静态的优先级决定。更高优先级的进程有更大的机会在处理器上运行。
内核根据需要动态调整动态的优先级基于进程的动作和特点。用户的进程通过进程的亲和力等级来改变进程的静态优先级。更高静态优先级的进程会有更长的CPU时间片。
Linux支持亲和力等级从19到-20 缺省值是0,切换到root用户可以把程序的亲和力值编程负值(负值的亲和力更高)。
Linux上下文切换
进程执行过程中,正在运行的进程信息储存在CPU的寄存器和缓存中。这些在加载到寄存器里的正在运行的CPU信息叫做上下文。为了在进程中切换,正在运行的进程上下文被存储,下一个要运行的进程的上下文被恢复到寄存器中。这个切换的进程叫做上下文切换。每次上下文切换时,处理器需要冲刷掉寄存器和缓存中的内容来给下一个进程腾出空间。有太多的上下文切换会造成性能的影响。
中断处理
中断处理是最高优先级的任务之一。中断经常是由IO的设备比如网卡,键盘,硬盘,等等设备引起的。中断处理器通知内核一个事件比如硬盘插入,ethernet frame 到达。它高速内核中断进程的执行,以迅速执行中断处理,因为有一些设备需要迅速响应。这对于系统稳定性是至关重要的。当一个终端的信号到达内核,内核必须要切换一个正在执行的进程到一个新的来处理中断。这就意味着中断会造成上下文切换,因此大量的中断可能造成性能退化。
在linux的运行中,有两种中断。需要对设备快速响应造成的中断比如说硬盘IO中断,网卡中断,鼠标键盘中断,叫做硬中断。可以延迟的进程比如(TCP/IP操作,SCSI协议操作等)用于软中断之中。你可以在/proc/interrupts中查看硬中断的信息。
在多处理器的环境中,每一个CPU都能处理中断。把中断绑定到一颗单核的CPU上可以提高系统性能。
进程状态:
每个进程都有自己的状态来表名正在发生的状态。随着进程的执行,进程状态在改变。一些可能的状态如下:
正在运行:task_running
在这个状态中,进程正在CPU中执行或者在等待队列中。
已经终止:task_stopped
进程被一些特定的信号暂停,比如说sigint,sigtop,这个进程正在等待被一些像 sigcont信号恢复。
可以中断的进程:task_interruptible
这个状态中,进程被暂停,在等待一个特定满足的条件。如果一个task_interruptible状态的进程接收到停止的信号,状态就会被改变,执行就会中断。经典的例子是:等待键盘输入的进程。
不能被中断的进程
类似于可以中断的进程,当一个进程处于不可中断的状态,发送信号也不能改变进程状态。经典的例子是等待磁盘IO操作的进程。
僵尸进程
一个进程接收到exit()系统信号停止,他的父进程应该知道终结。在僵尸进程中,进程正在等待父进程接受信号释放所有的数据结构。
僵尸进程
当一个进程已经终止之后,接收到一个信号将结束,它通常需要时间来完成所有的工作,在进程结束之前,这个简短的时间中,此进程就叫做僵尸。
进程已经完成所有关闭的任务之后,它报告给父进程它要死亡。有时候,有的僵尸不能自杀,这种情况,进程就出在僵尸进程中。
用kill命令杀不掉僵尸,因为系统认为它已经死了。如果你不能杀掉这个僵尸,你就把僵尸进程的父进程杀掉,僵尸也就死了。如果父进程是Init,你只能重启了。
1.1.8进程内存段
一个进程使用自己占用的内存区域来工作。工作内容随情况和进程使用情况不同。进程有不同的工作负载特性和不同的数据尺寸要求。进程必须可以处理不同数据大小。为了满足这个条件。Linux内核使用动态内存分配机制给每一个进程。进程内存分配将诶够如下图。
进程内存区包括以下段:
代码段:可执行代码存储的位置。
数据段:数据:静态变量等初始化数据存储的位置。
BSS:零初始化数据存放的地方。这些数据初始化为0.
堆:根据需求由malloc()分配的动态内存,它随着更高的地址增长。
栈段:本地变量,函数参数还有函数传递的值存放的地方。它随地址变低增长。
可以使用Pmap命令查看进程内存分配情况。
1.1.8linux CPU调度器
所有的计算机的基本目的都是计算。为了计算的目的,必须要处理计算资源和计算的任务比如线程或者进程。感谢Ingo Molnar,linux用0(1)算法来描述CPU调度器模板。算法指的是一个静态的算法,意思是选择进程放到CPU中执行是恒定的,不管进程的数量。
新的调度器缩放完好,不管进程数或者处理器数量,它占用较小的系统开支。这个算法使用两个进程优先级数据:
1.活跃的2.过期的
调度器会分配给进程一个时间片,基于他们的优先级和优先拦截率,他们被放在一列进程活跃数组中。当他们的时间片过期,就会被分配新的时间片,被放到一个过期的数组中。所遇活跃数组中的进程的时间片都过期之后,这两个数组就会切换,重启算法。为了交互的进程,越高优先级的进程会有更长时间片,比低优先级的进程获得更多运算时间。但是高优先级的进程不会饿死低优先级的进程。这种算法的优势在于提高linux负载的可伸缩性,linux企业版经常需要运行大量的进程或者线程。
有上千个,但是内存的地址是有限的。因此,内核为了更有效率的使用内存。我们描述linux内存结构,地址实际,还有linux如何更有效率地使用内存空间。
1.2.1物理内存和虚拟内存
今天我们面对32位和64为的系统。企业级的客户最重要的区别在于虚拟内存大于4G。从性能的角度来看,linux内核如何映射物理内存到虚拟内存32位和64位上很有趣。
Linux内核分配内存在32位和64位上分配内存有很大的不同。我们在这里只是强调一下一些细节,详细不在本文描述。
32位体系,linux内核只能在1G物理内存分配地址。超过ZONE_NORMAL的内存被映射到小于1G中。映射对于应用来说是完全透明了,但是在ZONE_HIGHMEM有轻微的性能延迟。
64位的体系结构,ZONE_NORMAL扩展到64G或者128G。你能看到,从ZONE_HIGHMEM到ZONE_NORMAL的映射内存也的开支在64位上可以完全消除。
虚拟内存布局
32位系统,单个进程使用的最大内存是4G,32位虚拟地址分配有个限制。标准的启动中欧冠,虚拟内存分配一个3G的使用空间和1G的内核空间。4G的内存布局实现有很大不同。
64位,没有限制存在。每个进程都能从巨大的内存空间中获益。
1.2.2虚拟内存管理器
系统的物理内存体系经常被隐藏在应用中因为系统会把任何内存映射到虚拟内存中。如果我们想知道调优的方法,必须要明白虚拟内存的分配机制。应用并不分配物理内存,而是在内核中请求一个特定大小的内存映射。虚拟内存并不必须被映射到物理内存中。如果你的应用分配大量的内存,一些可能被映射到磁盘子系统中的交换分区中了。
应用并不对磁盘子系统直接写入,而是写到cache或者buffers中。Pdflush内核线程冲刷cache/buffers的数据到硬盘中,如果有时间或者内存中文件大小超过了buffercache。
Linux内核管理硬盘cache的方式接近于linux内核处理吸入到物理硬盘子系统。Linux处理内存资源更为有效率。虚拟内存管理的默认管理器分配所有的可用内存空间作为硬盘缓存。因此linux生产系统的只有20M内存空闲很长长。
同事,linux处理交换空间很有效率。交换分区被使用并没有瓶颈,而是表名linux的效率。
页面分配
一个页是物理内存或虚拟内存中的一组连续的线性地址、;linux内核管理内存通过页单元。一页通常4K大小。当一个进程请求特定大小的页,如果有库存,内核会马上分配,否则会从其他的进程或者页缓存中取出来。内核知道多少内存页可用和它们的地址。
伙伴系统
Linux内核用一个叫伙伴系统的机制来管理空闲页。Buddy system维护可用页并分配页给页需求。她会保持内存区域连续化。如果小页面被分散分配,可能导致内存碎片,分配大的连续区域就很难了。可能会导致内存使用不科学性能倒退。
页面回收再利用
如果进程需要映射特定的内存页,页面不够用,linux内核会释放特定的页(已经用完,但是还是标记为active的页面)来获得新的页面,分配给新的进程。这叫做页面回收机制,kswapd内核线程和try_to_free_page内核线程负责页回收。
Kswapd通常处于睡眠可中断状态,可用内存页导到临界值,buddy system会把kswapd叫醒。她会基于最近使用的原则找出可替换的页。最近使用的页会被释放。活跃和不活跃的名单用于维护候选页面,kswapd扫描部分活跃名单,检查页面使用情况。可以用vmstat �Ca检查活跃和不活跃的内存数目。
Kswapd还遵循另一个原则。页面使用为了两个原因:页面缓存和进程地址空间。页面缓存是映射到硬盘上文件的页面。属于进程地址空间的页面(匿名的内存,因为不被映射到任何文件中)用于堆和栈。Kswapd回收内存时,她会优先收缩页面缓存而不是释放进程占用的页面。
Page out::把一部分页面放入交换分区
Swap out:把全部的内存地址放入交换分区。
页缓存被回收,进程地址被回收的很大一部分会根据使用场景来,会影响性能。你可以控制这个行为,/proc/sys/vm/swapiness
交换分区
页回收发生,候选页面在不活跃清单中,属于内存地址空间会被 page out 。拥有 swap 本身不是问题。对于别的系统来说, swap 只是个物理内存分配完了的保证。 Linux 使用更为有效率。虚拟内存同时生成物理内存和磁盘子系统或者交换分区。如果虚拟内存管理器发现一个内存页分配出去但是一段时间没有使用,就会把它挪到swap分区中去。Linux有很多系统的daemon并没有使用,linux会把它挪到swap分区中去。
linux文件系统
linux可以支持几乎所有的文件系统。
1.3.1虚拟文件系统
虚拟文件系统是个抽象的接口层,存在于用户进程和不同的linux文件系统实现之间。
VFS提供了普通的目标比如i-node file ,页缓存等。感谢VFS,用户进程可以不管什么文件系统,直接操作VFS
1.4 I/0子系统体系
向硬盘写数据的基本的操作如下。架设,文件数据在硬盘的扇区,而且已经在页缓存中了。
1.硬盘通过write()系统信号向一个文件写写数据。
2.内核升级page cache映射到文件
3.内核的pdflush线程解决冲刷page cache到硬盘中。
4.文件系统层把每一个块缓冲区放到 bio结构中去,提交一个写的请求到块设备层
5.数据块设备层从上层得到请求,开始一个I/0 电梯操作把请求放到I/0请求队列中
6.设备驱动程序比如SCSI,或者其他设备驱动会接管写的操作。
7.硬盘设备硬件会执行硬件操作比如磁盘磁头寻道,旋转,数据数据迁移到磁盘的扇区。
IO 子系统体系
1.4.2缓存 cache
过去20年中,处理器性能提升超过了其他的部件比如处理器缓存,内存硬盘等。到达内存和硬盘的慢速度限制了整个系统的性能,所有系统优化不会被处理器速度所限制。缓存机制解决了这个问题,经常在更快的内存中缓存出使用的数据来。它降低了到更慢内存的时间。现在的计算机系统使用这项技术在几乎所有的IO元件上,比如硬盘有硬盘缓存,磁盘缓存控制,文件系统缓存,缓存控制了所有的应用。
内存等级:
CPU寄存器和硬盘的速度差别很大,CPU会花很长时间等待数据从缓慢的磁盘硬件传输,因此这降低了CPU的效率。内存等级减少了这个缺陷利用设置L1缓存,L2缓存,内存和在CPU和磁盘的其他的缓存。越靠近CPU的内存有更快的速度和更小的空间。
这项技术也利用了访问局部性的准则。高速缓存命中率越高,数据传输的速度就越快。
Linux在页缓存,文件目标缓存(i-node缓存,目录进入缓存)中也使用了这些准则,提前读取缓冲区。
冲刷脏缓冲区
进程从硬盘读取数据时,数据被复制到内存。进程和其他的进程都可以从内存的缓存中检索到同样的数据。一个进程试图改编数据,进程会先改变内存中的数据。同事,内存中的数据和硬盘中的数据不匹配,内存中的数据此时被称为一个脏数据。脏数据需要尽快和硬盘的数据同步,否则一旦断电,内存中的数据会丢失。
把脏数据同步的进程叫flush。Linux内核2.6,内核线程pdflush负责把数据重刷到硬盘中。冲刷基于一个准则,内存中的脏数据大小超过特定大小时(bdflush)。这个特定大小成为buflush可以在/proc/sys/vm/dirty_background_ratio文件中编辑。
块设备层
块设备层处理和块设备操作相关的所有活动。块设备层最关键的结构是bio结构。Bio结构是文件系统层和块设备层之间的接口。
写的操作执行时,文件系统层写到页缓存中去(页缓存由块缓冲区构成)。把连续的块组合起来构成了一个bio结构,然后把bio发送到块设备层。
块设备层处理bio请求,把这些请求放到一个I/0请求队列中去。这些连接的操作叫做I/0电梯。Linux2.6内核中,四种I/0电梯算法可用。
块设备大小
块设备大小是能读写到驱动里的最小的数据单位,对服务器的系能有直接影响。如果你的系统处理很多小文件,一个小的块设备大小就会很有效率。如果你的服务器负责处理大文件,一个大的块设备会提升性能。正在运行的文件系统不能改变块设备大小。只有重新格式化才能改变当前的块设备大小。
I/0电梯
Linux内核2.6提供四种调度方法。Linux可以用作很广范围的任务,包括IO设备,和工作量的特点都改变很快。为了适应这些,四种I/0调度可用。
1预期分页
假定一个块设备只有一个物理寻求头,预期分页算法就被创造出来了。
1.5网络子系统
网络子系统是另一个性能方面的重要的子系统。网络操作和除了linux的很多设备交互,比如交换机路由器,网关,PC客户端等。尽管这些设备不再linux的控制之中。他们对于性能有很高的影响。和搞网络的人要搞好关系。
1.5.1网络实现
TCP/IP协议是一个和OSI层一样的分层结构。Linux内核网络实现调用了一个相似的方法。
网络应用程序接口
网络子系统在新的网络接口中经历了很多改变。网络栈的标准实现在linux上更注重于稳定性和少延迟,而不是性能优化。
传统的处理网络数据包的方法,网卡最终把数据包放到系统内核的网络缓冲区中,给CPU发送一个硬中断的信息。
这只是一个进程处理网络包的简介的说明,但是它说明了每一个步骤的缺陷。每一次一个以太数据帧到达网卡的时候,都会产生一个硬中断。CPU每次处理硬中断,都会先把正在运行的进程停掉,处理这个中断,这样会造成一个上下文切换,还有处理器缓存的冲刷。网络流量高的时候,会有每秒几千个数据包,会造成大量的中断和上下文切换。
因此,网络接口用来计算进程网络流量的开销。第一个数据包,接口按照传统凡是工作。第一个数据包之后,接口进入一个轮询的模式。只要在直接内存访问缓存中有数据包,就不会产生新的中断,可以很有效的减少上下文切换。如果ring buffer里空置了,网卡就会进入中断模式。网卡接口还可以根据多处理器提高多处理器扩展性通过软中断。NAPI对于很多企业级的多核系统有很高的提升。他需要NAPI的驱动。这对于调优至关重要。
网络过滤器
Linux内核有强大的防火墙的功能。是由网络过滤器内核提供的。你可以使用iptables单元来操作和添加网络过滤器。
通常来说,网络过滤器有两个功能
1.数据包过滤,如果一个数据包复合某个规则,网络过滤器会接受或者拒绝这个数据包。
2.地址翻译:如果一个数据包复合某个规则,网络过滤器会把数据包转换来达到地址转换的要求。
符合的过滤规则是通过以下的特征:
1.网络接口
2.Ip地址,Ip地址范围,子网
3.协议
4.因特网信报控制协议类型
1.端口
2.TCP标记
3.状态
1.5.2 TCP/IP
TCP/IP是默认的网络协议,linux也支持这些标准。
连接创建:
在数据传输之前,连接都会被建立在客户端和服务端之间。这个连接建立的进程叫做TCP/IP三次握手。
1.客户端发送SYN数据包(一个数据包有SYN标记)给服务器来请求连接
2.服务器接收到这个包,返回一个syn+ack的包
3.客户端发送一个ack的包给服务器来完成连接的建立
一旦连接建立起来,应用数据可以通过连接传输,全部数据传输完之后,连接终止进程启动。
1.客户端发送一个FIN包给服务端开启连接终止进程
2.服务端接收到FIN包,然后发送FIN包给客户端,如果没有数据发送。
3.客户端发送ACK包给服务器来完成连接的终止。
可以使用netstat命令查看TCP/IP会话连接。
流量控制:
TCP/IP实现有一个机制可以保证有效地数据传输,甚至网络拥挤阻塞。
TCP/IP传输窗口
传输准则窗口是在linux系统中实现TCP/IP的一个重要的方面。基本上,TCP传输窗口是一个主机所能接受和发送的最大量数据。这个窗口大小是从接收方提供给发送方,出葬在TCP头文件中。使用传输窗口,主机可以更有效地发送数据,因为发送方不需要为每一个数据包发送等待告知。它使得网络更充分利用。延迟的认证也能提高效率。TCP窗口开始很小,缓慢的增长从每一个连接中。
高速网络可以使用windows scaling的技术来提高最大传输窗口大小。我们可以在131的TCP调优中查看此项。
转发
在连接建立和结束和数据传输的过程中,因为很多不容的原因比如网络接口错误,路由速度缓慢,网络阻塞和多重网络实现,很多超时和数据转发会发生。TCP/IP使用数据包队列和多次发送数据包来解决这个问题。
可以在内核中改变这些设置参数,你可能想要增加TCP SYN的连接的尝试次数,如果丢包率很高的话。你可以改变一些超时的阀值通过/proc/sys/net文件。
1.5.3卸载
如果你的系统上的网络适配器支持硬件卸载,内核可以卸载部分适配器的人物,可以减少CPU使用率。
1.校验卸载
IP/TCP/UDP校验是用来确保数据包被正确的传输。通过比对协议头文件的校验领域和数据包数据的计算值。
2.TCP分割校验
数据超过能支持的最大值的时候,数据会被分割成最大值大小的数据包,适配器代表内核来主力。
1.5.4结合模块
Linux内核提供网络接口聚合器能力通过使用一个结合的驱动。这是个独立的结合驱动。这种驱动支持802.3连接聚合器喝一些负载均衡和错误容忍机制。可以创造一个更高的可用性和性能。
1.6了解linux性能指标
在我们查看不同调优参数和性能度量之前,可以先讨论一些不同的可用的指标和他们实际代表的意义。因为这是一个源代码系统,很多性能测试工具都可用。你可以根据性能指标和数据量大小来决定选取的工具。大量的工具其实检测得失同样的指标,因此我们只需要关注最重要的指标
1.6.1CPU指标
1.CPU使用率
这是最直观的指标,展示了每个处理器的负载。80%以上就由瓶颈了。
2用户时间
描述的是CPU使用率花在用户进程的时间,包括NICE的时间。很高的话,说明系统在进行工作。
3.系统时间
展示内核操作包括IRQ和软irq时间。高可用系统时间可以说明网络和驱动栈有瓶颈。系统内核时间应该越少越好。
4.等待
5.CPU所有在等待I/O操作的时间,就像是组侧的值,系统不能花费很长时间来等待IO操作,否则你应该调查一下对应的IO子系统。
6.空闲时间
展示了CPU空闲等待进程的时间。
7.NICE时间
展示了花在改变运行级别和进程优先级的re-nicing的进程的时间。
8平均负载
平均负载不是一个iebaifenbi,而是一个以下的平均值:
在等待队列中的进程
等待不可中断任务完成的进程。
这就是TASK_RUNNING 和TASK_UNINTERRUPTIBLE的进程平均值。如果请求CPU时间的进程阻塞了,平均负载就会提升。另一方面如果每个进程都能被立即处理,负载就会降低。
8.就绪的进程
展示了准备好被执行的进程,这个值不能超过10倍的CPU核数,不然CPU就会有瓶颈
9.blocked
进程在等待IO操作完成不能被执行,被阻塞的进程可以找到I/O瓶颈。
10.上下文切换
发生在系统中的线程切换。大量的上下文切换可以造成大量的中断。上下文切换不友好因为CPU缓存会重刷掉每一个。但是有的上下文切换是必要的。
11中断
中断之包括软和硬中断。硬中断对系统有更不利的影响。中断值太高暗示软件瓶颈。无论在内核还是驱动。中断值包括CPU时钟引起的中断。
1.6.2内存指标
空闲内存
Linux内核会把几乎所有的空闲内存非配作为文件系统缓存,所有去掉缓冲区和缓存得到的才是真正有效的空闲内存
SWAP 使用率
每秒200、300页交换可能有内存瓶颈
缓冲区和缓存
缓存会分配作为文件系统和块儿设备缓存
Slabs
展示了内核使用内存绿。内核页不能交换到磁盘中。
活跃的内存和不活跃的内存
不活跃的内存是被kswapd服务交换到硬盘中的候选人。
1.6.3网络接口指标
1.发送和接受的包
展示了一个网络接口发送和收到的数据包数。
2.接受和发送的字节数
特定的网络接口的发送和接受的字节数。
1.每秒碰撞
提供了网络接口和其他接口的碰撞率。稳定的碰撞值通常意味网络的瓶颈,而不是服务器的瓶颈。
5丢包率
内核丢包计数,或者因为防火墙和网络缓冲区太小。
6越线
越线代表网络缓冲区使用完的次数,这个应该和丢包率一块研究来确定网络缓冲区或者队列长度瓶颈。
7错误
被标记为错误的帧数。经常是因为网络电缆破碎和网络不匹配造成。对铜基网络有很大影响。
块设备指标
1.IOWAIT
CPU等待IO操作的时间。很高的值说明IO瓶颈
2.平均等待队列
2-3的硬盘队列是正常的,更高就有可能有IO瓶颈
3.平均等待
IO等待被解决的平均时间。包括IO操作和等待的时间。
4每秒传输
展示了每秒有多少操作运行包括读写。以KB为单位的每秒读写可以用来确认系统的平均传输大小。数据传输的平均大小需要和你的硬盘子系统的
5.每秒块设备读写
这个参数展示了读写速度在1024bytes的块设备上。
6千字节每秒读写
读写到千字节的块设备中代表从块设备读写传输的实际数据。