swoole IO处理模型

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chosen0ne/article/details/53169693

公司的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进程?



展开阅读全文

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