Linux遭遇扩展性问题
使用真正大型机器的乐趣,一方面在于能够比别人更早在可扩展性方面发现新的惊奇,所以使用SGI高性能计算机的人常常比我们许多人享有更多的乐趣。他们最近的发现与内核线程的数量有关: 在4096路系统上,Linux内核线程的数量导致内核出现了令人关注的一些行为。
发现问题
首先他们发现:即使使用默认的配置,也启动不了内核。Linux系统在任何一个特定的时间,活动进程通常限制在32768个。运行过ps命令的人都会注意到: 内核线程在占用数量越来越多的内存插槽。单处理器桌面系统可能在运行其中的39个活动进程。实际上,如今一个典型的系统上有足够多的内核线程,以至这些线程会占满4096路机器上的全部空间,甚至更多。这个问题比较容易得到解决,只要提高处理器数量的限额。不过,这样一来情况变得比较有意思了。
对系统上的其他每个进程(包括内核线程)来说,init进程是最终的父进程。所以在大型系统上,init有许多子进程。这些子进程位于一个很大的链表(linked list)上。该链表由诸多函数来搜索,其中包括wait()的变种版本。如果正在搜索中的进程接近链表末端,那么这个搜索需要花费很长时间。一是因为大多数内核线程是长期线程,二是因为新进程被放在链表末端,所以某次搜索很可能确实会寻找末端的某个进程。
然后把某个模块装入内核。当新模块进行链接时,模块装入过程就会调用stop_machine_run(),该函数会为系统上的每个进程创建高优先级的内核线程。该线程就会获取分配给它的CPU,然后只是闲置在那里,直到被告知退出;尽管所有CPU以这种方式被搁置起来,但链接过程照常执行。即便在最好的时候(即线程数量不多的时候),调用stop_machine_run()这样的函数也是有点不合常理,更何况对一个拥有4096路处理器的系统而言,stop_machine_run()会创建4096个线程,每个线程都会进入到init的子链表的末端;每个线程等到需要清理时,都必须进行搜索。结果就是,系统在很长一段时间过后才会停机。
解决办法
有人可能认为,拥有这么大系统的人根本不应该装入模块,但可能会受到来自用户社区的反对。所以需要找到其他的解决方案。有关报告提供了一种简单的补丁,可以把现有的进程转移到子链表的始端。这种变化解决了眼前的问题,因为它可以通过搜索这些子进程就能找到它们,不必遍历不会去任何地方的所有长期进程。
Linus有几个变通办法。办法之一就是为僵尸进程(zombie process)建立不同的链表,从而完全不需要这种搜索。另一个办法就是停止让内核线程成为init进程的子进程,因为在任何情况下,它们与用户空间都没有多大关系。但一些开发人员认为,真正的解决方案也许在于开始减少内核线程的数量。
导致内核线程大量创建的最主要原因无疑是工作队列。默认情况下,工作队列会为系统上的每个CPU创建一个线程。有些情况能够得益于多个线程和CPU局部性(CPU locality),但毫无疑问也有许多情况下不需要所有这些线程。清除这些线程有助于解决部分扩展性问题; 另一个好处就是,这可以让ps列表显得整洁一些。
在许多情况下,工作队列可能根本没有必要。相反,内核子系统可能完全使用“一般的”keventd工作队列(作为events/n线程来运行)。使用keventd内核线程存在一些问题,包括无限制延迟以及可能性很小的死锁,不过在许多情况下,它的工作效果足够好。
在其他情况下,使用线程很有必要。涉及长时间延迟的任务是一个例子; 使用kevented运行延迟时间好几秒的函数被认为是不恰当的。需要复杂上下文的工作也会得益于其自己的线程。不过在许多情况下,这些线程在一些工作实际完成之前并不需要创建。大多数系统上迅速运行ps命令可以显示与错误处理、异步I/O、蓝牙及更多方面有关的线程。按照当前方式,这些线程在启动时(或者模块装入时)创建,其中许多线程在系统关闭之前可能根本不做任何实际工作。创建线程的成本很低,所以许多这些线程可以在需要时创建而成。
这方面恐怕需要进行一些真正的改进。需要的只是有人、有时间、有动力来做这项工作。与此同时,使用4096路处理器系统的人可能需要打上一两个补丁。
链接:进程与线程
可执行文件由指令和数据组成。进程就是在计算机上运行的可执行文件针对特定的输入数据的一个实例,同一个可执行程序文件如果操作不同的输入数据就是两个不同的进程。
线程是进程的一条执行路径,它包含独立的堆栈和CPU寄存器状态,每个线程共享其所附属的进程的所有的资源,包括打开的文件、页表(因此也就共享整个用户态地址空间)、信号标识及动态分配的内存等等。线程和进程的关系是:线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一物理内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。
Linux内核只提供了轻量进程的支持,限制了更高效的线程模型的实现,但Linux着重优化了进程的调度开销,一定程度上也弥补了这一缺陷。目前最流行的线程机制LinuxThreads所采用的就是线程-进程“一对一”模型,调度交给核心,而在用户级实现一个包括信号处理在内的线程管理机制。
在Linux的“一对一”模型中,用一个核心进程(轻量进程)对应一个线程,将线程调度等同于进程调度,交给核心完成,而其他诸如线程取消、线程间的同步等工作,都是在核外线程库中完成的。因此可以把进程看作一组线程,这组线程拥有相同的线程组号(TGID),这个TGID就是这组线程序所附属的进程的ID号,每个线程的ID号就是我们用ps命令所看到的LWP号。(ccw)
- 1局域网加速五个方法
- 2支招OA选型:简单三步完成筛选
- 3一招克死所有病毒
- 4OA:服务如何助客户提升管理能力
- 5自建维基网站
- 6物理隔离技术及产品的选购要点
- 7VoIP治疗通信病
- 8界面与程序分离 --- MIS开发新方法
- 9聚焦OA时代 安全、易用是关键
- 10移动OA 外出碎片时间也可创效益
- 11核心网网络测试技术
- 12“明星程序员”的DNA
- 13大协同时代的智慧管理
- 14智慧城市之共享式标准移动OA产品
- 15Sybase数据库安全性控制策略
- 16怎样清理故障磁盘上的残留数据
- 17如何挽救大型机技术危机
- 18网络管理员避免10种愚蠢行为
- 19霍邱县政务协同办公(OA)系统启用暨业务培训会召开
- 20七种IP拥塞控制算法需改进
- 21OA系统行业八强功力大比拼协同定江山
- 22怎样应对IDS八大高危事件
- 23实现JSP与MySQL的连接
- 24OA选型霾气重 抓住要害治“雾霾”
- 25OA办公系统选购法则:理性、务实,永远
- 26以信息化引领公安工作现代化
- 27文件备份故障五大原因分析
- 28企业CIO进行OA选型的注意事项
- 29路由器的五代家谱
- 30了解OA六大重点 掌握选型主动权