|
Linux下多进程设计模式
作者:lipi Email:[email protected]
在Linux环境下多进程的应用很多,其中最主要的就是网络/客户服务器。但是在电信、金融等数据量和稳定性要求都比较高的环境中,也会涉及到多进程的应用。
在这里,我们主要讨论的是在应付高数据量、稳定性的环境下多进程的设计模式。一般来说,在这种环境下,我们需要同时500个进程以上同时操作,这样就会对进程间的管理、进程对系统的消耗等作更多的考虑。
一般来说,我们有如下设计方法:
1、 传统的并发模式
这种模式应用最多的就是实时性的Socket服务器,针对每一个事务开启一个进程,
然后父进程返回等待的状态,而子进程则处理该事务,如果事务处理完毕,子进程退出。
这种设计方法比较简单,但是存在一些问题:
* 消耗系统资源。
如果面临每秒需要处理将近1000个事务、而且每次子进程的处理时间特别短(<0.5秒)的情况下,这种模式对系统资源的浪费是很大的,而且因为在每秒要开启500个进程,这样中间当系统负担过重时,进程的开启就会需要很大的时间,我测试过,中间最长的延迟时间是1.5秒,就是系统开启一个进程需要1.5秒的处理时间。
在以上情况下,系统将大部分的处理能力消耗在开启、销毁进程上,造成了极大的浪费。
* 进程状态难以了解。
如果在以上情况下某一个子进程发生了延迟或者其他异常,长期处在等待
的状态下,父进程根本无法对如此众多的子进程进行监控,所以就会对子进程无法控制。
* 进程数难以控制。
在每次开启子进程时,父进程可以判断是否达到了最大进程数,如果达到
了,则需要等待自进程的释放。这样固然可以控制最大的进程,但是不能根据
需要自主调节进程数。
所以,这种设计模式主要是在开启进程数比较少,至少开启进程的时间间隔不是特
别小的情况下使用,而且子继承在处理事务的时间如果长一点为好。
2、 进程池模式
多进程模型中, 其子进程处理客户请求, 父进程用于管理子进程. 当系统过载时父进程会再启动几个子进程, 当系统空闲时, 父进程会杀掉几个子进程. 子进程的数目在"MaxIdleProcs"和"MinIdleProcs"之间。
而子进程的状态主要储存在一片共享内存区中,因为不能让子进程在空闲时消耗系统资源,所以要让子进程在空闲时阻塞等待。方式有如下几种:
* accept阻塞
应用在Socket服务器上。
* select 阻塞
* 信号锁或者文件锁
将文件分成多个部分,每一部分对应一段子进程,主进程通过控制这个文件达到控制子进程的目的。
三种方法都要求进行阻塞, 区别在于阻塞与不同的地方. 前两种方法都会由所谓的巨群问题: 多个阻塞在同一个资源上的进程被同时唤醒引发再次竞争. 不过, 按Richard Steve的评测, 第一种方法最快, 第二种其次, 第三种最慢. 其实, 在linux上第三种方法也会有巨群问题。
巨群:唤醒所有的子进程。当然,只有最先被调度的子进程才会获得客户的连接,其他的子进程会再次进入睡眠状态。这种情况会导致系统性能的下降。解决这个问题的方法是给accept上锁,即保证accept操作的原子性。有些Linux或者Unix系统在内核已经解决了这一问题,就无须再给accept上锁了。
我们在这里不重点讨论Socket上的应用,在平时事务比较多的情况,例如短信息系统,大概500-1500条/秒的流量。而每条信息处理时间<0.5秒。
除了采用信号锁或者文件锁,我们还可以采用消息队列达到进程阻塞的目的。
图(一)见附件
以上这种方式较好了解决了事务处理量较大的环境下多进程的处理问题,当系统真正达到满负荷运转时,没有子进程处在休息状态,而且还可以对子进程的状态实时监控。
定时器的处理:
因为在多进程处理过程中会出现一些异常,例如查询数据库、通信等过程,所以要限制确定子进程的处理时间,不能让子进程长期处在等待状态。所以在以上的方式下,可以在共享内存里存贮进程的事务开始时间,然后监控进程可以定时查询共享内存,如果发现有子进程处理时间过长,则向该进程发送信号。然后子进程就会接收这个信号,并且在你sigsetlogjmp()的位置跳出,重新开始请求其它的事务。
综述:
以上这是我个人在工作当中接触到的一些典型的多进程处理模式,主要是在RedHat 7.3和Sybase12.5的环境下,因为我没有对多线程的处理方式作研究,所以如果采用POSIX线程的话会不会大幅度的提高系统处理能力,我不清楚。希望清楚的同行能给我些意见和知识。 |
|