技术文章 > 服务端 > pomelo 用户指南 > server、connector 等组件与客户端通信 

与客户端通信


    在这部分,主要介绍 pomelo 是如何与客户端通信以及前端服务器是如何处理用户请求的。处理客户端的请求和响应是 pomelo 的核心之一,它涉及到了很多组件,包括 session 组件、server 组件、connection 组件、connector 组件、proxy 组件、remote 组件等。在本部分,我们仅仅介绍与前端服务器相关的组件,以及他们的作用,对于 rpc 以及后端服务器以来的 backendSession 以及 channel,这里不做深入介绍,将在其他部分进行介绍。
    对于前端服务器来说,session 组件是 sessionService 的包装组件,用来维护用户的 session 信息;connection 组件是 connectionService 的包装组件,是用来做连接统计的;connector 组件会开启监听接口,承受客户端的连接,这里对 connector 组件底层使用的具体的 connector 不做太多关注,只关心其抽象行为。
    对于 server 组件来说,会维护服务器的 Handler 和 HandlerFilter,当用户的请求到达前端服务器时,如果前端服务器定义了相应的 Handler,那么前端服务器会使用 filter-handler 链对其进行处理,然后将处理后的结果返回;如果对请求路由检查发现请求是发向到后端服务器的,那么前端服务器会根据用户配置的 router(也可能是默认的),计算出要发往的后端服务器 id,然后发起 rpc 调用,后端服务器在接收到 rpc 调用时,从其中取出请求路由以及请求参数,发起 filter-handler 链对请求进行处理,完成调用,并将响应发给前端服务器,前端服务器再将响应发送到客户端,整个处理流程如下如所示:


下面的类图粗略地展示了这些类之间的关系:


下面通过类时序图的方式,选取典型的用例行为,来介绍框架的控制流程:


初始化

客户端连接

当客户端连接到前端服务器时,会触发 connector 的监听事件,在事件的处理中,会通过 CoConnection 增加连接信息,用来做统计。会对连接返回的用来数据通信的 socket 绑定 message、close、error、disconnect 等事件,然后创建 session,session 由 CoSession 包装的 SessionService 维护。每一个 session 都会维护与其相关的 socket。此时,客户端已经完成了与服务器端的连接。

客户端请求

绑定/解绑用户

客户端断开

当客户端断开连接时,connector 监听的 socket 上会激发 disconnect 事件,在具体的事件处理中,会从 SessionService 中删除掉对应的 Session,释放掉 session 维护的连接,还会调用 ConnectionService 上 decreaseConnectionCount,维护统计信息。 上面选取了客户端与服务器交互的几个典型行为,说明了整个客户端请求中的控制流程。这里仅仅涉及到了前端服务器,对于后端服务器的具体处理,这里仅仅提到了会发起 rpc 调用,而没有具体地深入介绍。

Pomelo中的请求处理链


在 pomelo 中,HandlerFilter 分为 beforeFilter 和 afterFilter,对于 beforeFilter 来说,其方法签名为:
before(msg, session, next);
其中 msg 是请求,session 表示当前请求的 session,在前端服务器的话是 FrontendSession,在后端服务器的话是 BackendSession,next 是用来组成请求链的,是用来指定下一步调用的。如果在具体的 filter 上没有错误的话,那么就直接调用 next(), 否则,则调用 next(err, resp),向后面传递具体的处理错误以及响应。在 filter 的具体实现中,在逻辑处理完后,必须调用 next,否则将打断整个处理链。如果有任意一个 beforeFilter 的 next 调用中传递了 err 的话,此处理链将会立即被中断,直接会转入错误处理。在 next 传递 err 的时候,可以携带一个 resp 参数,作为对客户端错误的响应,即 next(err, resp)。
Handler 的签名一般为:
(msg, session, next);
msg 是经过 beforeFilter 链处理过的 msg,session 是经过 beforeFilter 链处理后的 session,next 是下一步处理。如果需要给客户端响应的话,没有错误的话,使用 next(null, resp),否则可以使用 next(err, resp),向后面传递错误信息。这里,resp 是给客户端的响应,一般来说客户端的响应都是在 Handler 的具体逻辑中生成。在具体 Handler 的实现中,也必须调用 next。其 next 语义与前面的 beforeFilter 中的 next 语义一致。
对于 afterFilter 来说,其方法签名为:
after(err, msg, session, resp, next);
afterFilter 是做一些清理操作的,在执行 afterFilter 链的时候,具体的响应已经发送给了客户端,也就是说在 afterFilter 如果对 resp 做更改的话,将对客户端响应没有任何影响。同样,这里的 next 参数,也是指定了下一步的处理,其签名是 next(err),不过与上面 beforeFilter 和 Handler 不同的是,由于在 afterFilter 中常做的是一些清理操作,而且此时具体的响应 resp 已经发送到了客户端,所以 afterFilter 中,处理链对 err 将不再敏感,无论是否有 err,整个 afterFilter 链都会执行完毕。
ErrorHandler,是当在处理请求时产生异常时进行的处理,具体的签名为:
(err, msg, resp, session, cb);
在 beforeFilter 或者 Handler 中,如果处理产生错误,那么将会转向错误处理,ErrorHandler 就是用来进行错误处理的,具体的参数意义跟上面的一样,其中 resp 是由前面产生错误的 next(err, resp) 调用传递来的,cb 的签名为 cb(err, resp),cb 会将 resp 发送给客户端。因此在 ErrorHandler 里面,是需要调用 cb(err, resp), 否则,客户端将得不到服务器端的响应。在errorHandler 中可以根据传入的 resp 以及 err 信息,重新生成要发送给客户端的 resp。通过如下方式设置全局的ErrorHandler:
var errorHandler = require('<path');
app.set('errorHandler', errorHandler);
如果用户没有配置全局的 errorHandler 的话,默认的 errorHandler 会向客户端返回由 beforeFilters 或者 Handler 产生的 resp。整个请求处理链的大致流程如下:


Pomelo 内建 filter


Pomelo 内建了常见的一些 filter,用户可以通过如下的方式启用:
app.filter(pomelo.filters.());
下面介绍一下这几个 fitler:

serial

这个 filter 是用来对用户请求做串行化的,可以使得用户的请求只有在第一个请求被处理完后,才会处理第二个请求。serial 中使用了一个 taskManager,当用户请求到来时,在 beforeFilter 中,将用户的请求放到 taskManager 中,taskManager 中维护着一个 task 队列。在对应的 afterFilter 中,如果 taskManager 还有未处理的请求,将会处理其请求,即在一个请求的 afterFilter 里启动在 taskManager 中还没处理的下一个请求,这样就实现了请求的序列化。

timeout

这个 filter 是用来对服务端处理超时进行警告的,在 beforeFilter 中会启动一个定时器,在 afterFilter 中清除。如果在其定时器时间内,afterFilter 被调用,定时器将会被清除,因此不会出现超时警告。如果定时器超时时,afterFilter 还没有执行到,则会引发超时警告,并记录日志。默认的处理超时是 3 秒,可以在加载 timeout 的时候作为参数传入。

time

这个 filter 使用来记录服务器处理时间的,在 beforeFilter 中会记录一下当前的时间戳,在 afterFilter 中再次获取当前的时间戳,然后两个时间戳相减,得到整个处理时间,然后记录日志。

toobusy

这个 filter 中,一旦检测到 node.js 中事件循环的请求等待队列过长,超过一个阀值时,就会触发 toobusy。一旦触发了 toobusy,那么 toobusy 的 filter 中将终止此请求处理链,并在next调用中,传递错误参数。

总结


在本部分,介绍了前端服务器与客户端的通信的相关内容,讲述了相关的类关系,以及典型用例行为的控制流程。对于请求响应链中的 before filter,handler,after fitler,error handler 等做了较为详细的分析,最后简单分析了一下 pomelo 内建提供的一些 filter。


来源:摘自 https://github.com/NetEase/pomelo/wiki/%E4%B8%8E%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%80%9A%E4%BF%A1,本站 行痴 整理