您的位置:首页 > 其它

swoole IO处理模型

2016-11-15 12:41 141 查看
公司的php服务框架是通过swool实现的,发现线上存在丢请求的情况。为了排查这个问题,顺便看了一下swoole的源码,了解了其IO、进程模型。本篇文章主要介绍选用swoole官方推荐的多进程、多线程模型时IO处理模型。
swoole的进程模型有一些复杂,包括:master进程、manager进程和worker进程,这里只介绍IO处理相关,所以暂时丢下manager进程(主要用于配置重载)。下面是整体结构图:


首先介绍各个元素:
- master进程:IO相关处理,又由一下两类线程组成:
- Accept Thread(swoole中叫做MainReactor):用于接受客户端的连接。一个swoole实例只能有一个Accept Thread。
- IO Thread(swoole中叫做ReactorThread):用于接收客户端的请求,并向客户端发送响应。一个swoole实例,可以有多个IO Thread。
- worker进程:用于处理具体的业务逻辑,会回调php中注册的回调方法。一个swoole实例可以多个worker进程。
上述模块中,Accept Thread、IO Thread和worker进程中,没有实例都有一个事件循环,用于处理IO事件。
接下来,以客户端与服务器建立连接、请求响应的过程,介绍其中会涉及到的各种细节。
1. connect
初始化时,会将监听socket添加到Accept Thread的事件循环中,监听客户端的连接事件。当有客户端连接到来时,会处理该事件,accept到对应的socket。
2. connection dispatch
swoole中会有多个IO Thread,每个客户端连接会由其中一个IO Thread处理IO事件。所以在accept到新的连接时,需要将该连接分发到一个IO Thread。具体的分发策略是:对应socket的fd % IO Thread的数目 得到的值便是要分发到的IO Thread的下标。分发之后,会将该连接加入到这个IO Thread的事件循环中,之后所有IO事件都由这个IO Thread处理。同一个IO Thread会同时负责处理多个连接。3. send data
当客户端发送请求后,对应的IO Thread会被唤醒,并回调read事件的处理函数,接收客户端的请求。IO Thread会将发送的数据封装成task,然后分发给worker进程。
4. dispatch task
task中主要包括:
- 客户端发送的数据
- 对应的连接的fd
- 负责处理IO事件的IO Thread的id
task分发,swoole支持集中方式:
- Round-Robbin
- 基于fd取模
- 基于IP取模
- 等等
master进程与worker进程的通信是基于socketpair,双方会将对应的socket添加到各自的事件循环中,所以可以接收对方发送的数据。
5. process request
worker接收到task后,会进行解包,回调php中注册的回调函数。这里有一点需要注意,swoole层不会缓存不完整的请求,所以在实现php回调函数时,需要自己缓存,否则会有请求丢失的风险。
6. send response
worker将请求处理完后,会将php回调函数返回的结果回传给对应的IO Thread,这里基于的是task中的fd和IO Thread的id。
7. respond
IO Thread接收到worker的响应后,会直接将响应内容发送给对应的客户端。

swoole为了充分利用多核,所以采用了多进程+多线程,进程模型略微复杂,与其他框架对比:
- nginx:nginx采用的是多进程。由于nginx作为web server,本身主要是CPU bound的,正常情况下,只会有少量IO,所有不需要更多的进程或线程。
- redis:redis采用的是单线程,不能使用多核,需要人工开启多个进程以利用多核。由于redis的大部分操作都是存内存,快速操作,为了简单,作者采用了单线程模型。
swoole中进行具体业务逻辑处理是在worker进程中,在IO Thread和worker进程间需要跨进程传输请求和响应,存在较严重的复制。这里,不清楚一点:为了利用多核,为什么不用线程替换woker进程?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: