Skip to content

请求和响应切分原理

Mingliang Tan edited this page Feb 15, 2019 · 1 revision

分为以下几个问题

  • 录制的原理
  • 如何知道一个socket fd的性质
  • 怎么样切分inbound request/response(PHP自身处理的HTTP请求)
  • 怎么样切分outbound request/response(对外发起的redis/mysql/http/thrift等外部依赖的请求)

录制的原理

因为录制是在 syscall 层面直接录制的 7 层网络协议的包体。也就是把 send/recv 的函数参数里传递的 byte 数组给拷贝了一份。所以避免了 tcpdump 抓包需要进行 tcp 流重建的问题。

对于系统中所有的 socket 的 send 和 recv 我们都会拦截。但是不同的 socket 代表了不同的方向。所以需要解答第二个问题

如何知道一个socket的性质

socket 如果是 accept 进来的,那么它代表了 inbound 方向。recv 是 inbound request,send 是 inbound response。如果 socket 不是 accept 进来的,则代表了 outbound 方向。recv 是 outbound response,send 是 outbound request(注意 request response 正常是相反的)。

因为需要知道这点区分,所以我们不仅仅需要拦截 send recv 还需要拦截 accept。而且更复杂的问题是 accept 和 send recv 未必发生在同一个线程。对于从别的线程里创建的 socket fd,需要能够被发现。解决方法是维护了一个全局的 socket fd 的 map。如果一个线程发现了一个新的 fd,首先去这个全局 map 里找找看。

Inbound Request 切分的原理

参见:https://zhuanlan.zhihu.com/p/25720275

简单来说是两点

先利用线程内是串行执行的特性,把并发的流变成了串行的流。 在一个线程内,利用 request/response 的时序就可以把请求和响应切分开来。无需进行7层协议的解析。总是 请求 - 响应 - 再请求 这样的一个节奏。 所以实现就是当 recv 的时候,发现已经 send 了,则结束上一个 session,开始下一个session。这样即便是在 fastcgi_finish_request 之后发生的 call outbound 也可以被录制到 session 里

Outbound Request 切分的原理

同上