server多线程并发模型和多进程并发模型的选择

做unix上server程序实现时:到底是该选择多线程并发模型还是多线程并发模型呢?

想到这个问题是源于阅读scgi,nginx,memched的源码~如下:


scgi的实现是用的多进程,主进程负责监听socket连接请求,然后分发给各个子进程来处理。
nginx的实现是用的多进程,创建好子进程之后,各个子进程直接自己来监听socket连接请求并处理。
memched的实现则是用的多线程,主线程负责监听请求,然后分发给各个子线程来处理。

那这样的话:本质上是两个可选条件的组合
1.多线程 还是 多进程?
2.是master统一监听请求并分发给worker处理 还是 各个worker自己监听请求并处理?

其中第2点的区别产生源于:
是 先创建socket 再fork子进程 还是 先fork子进程再创建socket?
前者因为先创建的socket,所以fork出来的子进程自然也继承了这个东西,所以可以直接用它来监听请求。 后者则不行···

================================================
先说第2点的区别吧:
我觉得如果说:让各个worker自己来监听请求的话:因为其监听的都是同一个socket,所以会产生竞争!到底谁先accept? 所以在实现上也搞个accept锁,让各个进程来争夺这个。否则来一个请求,所有子进程都呗warkup的话···惊群现象发生了·······

那master来统一监听并分发呢?嗯,master得知道各个worker是否就绪可用··怎么知道?好吧··各种IPC进程间通信····貌似也要有不小的开销···

======================================================

那和2点都该怎样来抉择 或者说 都有什么优缺点 适用用什么场景呢?


问题一. 选择多线程 还是 多进程

我理解这个问题,其实本质上就一句话:多进程之间各自有用自己的内存空间,而同一个进程内的多线程之间共享内存空间。

首先:server程序的本质是:client来获取和修改数据. 那么:不管是nginx还是memcached都是为了解决这个问题而存在的。

对于memcached而言(单进程多线程):这个进程启动后,用户写入这个cache的所有内容都是写在这个进程的堆空间中。 也就是说:所有的数据都是集中存在于唯一一个进程空间中,这样各个线程完全可以共享这些数据,可以全部的去查询和修改; 而如果我们换用多进程来实现的话,那用户传入cache的数据都存在哪?传过来后是一个进程来处理的,那处理结果必然存在这个进程自己的内存空间中,这样别的进程想读取的话怎么办?IPC?消耗多大! 正是因为多进程各自的内存空间是独立的,导致传入的数据也是相互独立的,而不是存放在一起的!这样想跨进程查询的话就得IPC,而且及其频繁,而且还不知道是该查哪个子进程的空间!所以这种方式明摆着不合适,那如果我们是各个子进程获取到用户传入的数据之后:不是保存在自己的进程中,而是还要写入到一个多进程共享的内存中,这样好使得数据变为全局来避免IPC呢?这种实现的话就相当于:我们将每个进程传入的数据都写入到进程共享内存中!而各个进程只要操作这个共享内存就可以了。这个实现当然可以,没什么问题,但是显然没有直接单进程多线程来的easy,这样将所有数据直接放在进程空间中,而非共享内存中!操作起来也速度,简单!


所以从上边的角度来将:之所以选择多线程是基于全局数据的考虑,各个处理请求的进程/线程 都要全局的读取,而不是各自空间内读取!!

那因为多个处理进程/线程是同时读写同一份大数据,必然牵扯到同步的问题,避免同时写之类的操作。所以还加一些锁。


而mysql的实现呢?也是用的多线程,按照上边的原因也很容易解释的通。各个请求到来之后:需要各个处理worker来操作全局数据,所以要求这些workers都能访问同一片数据。所以多线程是中很合适的方式,大家都处于同一个进程的内存空间中! 当然:也牵扯读写锁的问题来同步等~~


=============================================================================================================

那nginx呢?为什么用的都是多进程??

其实这里一句话就可以解释:其只是读取server脚本,不会更改。

请求到达nginx后,其如果不用cgi协议的话,就是直接启动多个进程来调用后端server脚本并运行之。 所以:nginx只负责读取server脚本,比如一个Php脚本.

其是一个读取,不牵扯写入/更新··


那什么感觉nginx也会写入数据呢?其实这里写入数据是写入到数据库中,php/python脚本仅仅是加在中间的一个处理层·,这一层仅仅是个媒介!!!没有具体的数据写入

所以一个写请求到达nginx之后:其要做的工作就是先读php脚本,而后php脚本再调用mysql来写全局数据库!那这样的话:nginx仅仅是读脚本,不牵扯任何写!!Php脚本仅仅是nginx的一个媒介而已~~借助php来操作数据! 所以真正的读写数据都是在后端的Mysql数据库这里,在这里就使用多线程来操作全局数据(memcache的全局数据存在内存,而Mysql的全局数据存在硬盘而已)~~而nginx仅仅是读取php脚本,而且各个php脚本都是相互独立的,所以读取时不需要同步之类的,所以这里用多线程和多进程都可以做到!!那为毛用多进程呢?因为:多进程的话各个进程之间相互独立,一个crash不会影响其他进程;而多线程:任何一个子线程crash了,其他子线程就全部死掉了!这意味着:使用多线程的话:各个用户的请求处理是相互影响的,一个挂了,其他人的请求也跟着悲剧;而多进程就不会相互影响! 所以更适合使用多进程!


亦即:我觉得nginx使用多进程和多线程在其他方面没什么区别,最大考虑的因素是相互影响的问题:为了使各个请求处理不相互影响,从而最终选择多进程!!


===================================================================================================================

总结一下:我认为牵扯到全局数据写入/更新的操作,就用多线程;否则就多进程提高健壮性吧。


=====================================================


那下边两种方式的比较呢?

①master负责监听分发请求,各个worker从master那接收请求并处理 

②workers直接自己监听请求并处理


下一篇文章分析吧。

展开阅读全文

没有更多推荐了,返回首页