自从加入了 Flomesh 的 workshop,理解了可编程网关 Pipy。对这个“小东西”充斥了好奇,前后写了两篇文章,看了局部源码解开了其局部面纱。但始终未见其全貌,没有涉及其外围设计。
不是有句话,“好奇害死猫”。其实应该还有后半句,“满足了就没事”(见维基百科)。
所有就有了明天的这一篇,对前两篇感兴趣的能够跳转翻看。
- 初探可编程网关 Pipy
- 可编程网关 Pipy 第二弹:编程实现 Metrics 及源码解读
言归正传。
事件模型
上篇写了 Pipy 基于事件的信息流转,其实还未深刻涉及其外围的事件模型。既然是事件模型,先看事件。
src/event.hpp:41
中定义了 Pipy 的四种事件:
Data
MessageStart
MessageEnd
SessionEnd
翻看源码可知(必须吐槽文档太少)这几种事件其实是有程序的:MessageStart
-> Data
-> MessageEnd
-> SessionEnd
。
这种面向事件模型,必然有生产者和消费者。又是翻看源码可知,生产者和消费者都是 pipy::Filter
。咱们在上篇文章中讲过:每个 Pipeline
都有一个过滤器链,相似 单向链表的数据结构。
那是不是依照下面说的,事件是从一个 Filter
流向下一个 Filter
?也对,也不对。
矛盾?
先看 Filter
如何向下传递事件,src/session.cpp:55
处,Filter
持有 output
变量,相似为 Event::Receiver
(参数为 Event
的 std::function
的别名,作为在行的笔者并不懂 c++,但不障碍理解程序设计)。通过 Receiver
调用下一个 Filter
的 #process
办法。
这里的 Receiver
就能够了解为事件发送的窗口,而 #process(Context *ctx, Event *inp)
就是事件的接管窗口。
这就是后面为什么说“事件是从一个 Filter
流向下一个 Filter
”是正确的。
为什么不对?首先,一个 Filter
会产生多个事件,比方 decodeHttpRequest
可能会产生 MessageStart
、Data
和 MessageEnd
事件,并且每产生一个事件都会通过Receiver
向下传递,不会等 #process
流程完结才传递事件;再就是下一个 Filter
可能并不会对某个事件感兴趣(下一个 Filter
的 #process
办法不做任何解决就返回了)。
可能看下图会更容易了解(图中 no output
表明事件不会向下传递):
最简略的示例
在 test/001-echo/pipy.js
提供了的示例:
pipy()
.listen(6080)
.decodeHttpRequest()
.encodeHttpResponse()
发动申请
$ curl -X POST localhost:6080 -d '{}'
{}
HTTP 音讯体
#request
POST / HTTP/1.1
Content-Type: application/javascript
User-Agent: PostmanRuntime/7.28.1
Accept: */*
Postman-Token: fc84b575-7fea-487b-a55d-f6085bc62cf7
Host: localhost:6080
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 2
{}
#response
HTTP/1.1 200 OK
postman-token: fc84b575-7fea-487b-a55d-f6085bc62cf7
accept-encoding: gzip, deflate, br
host: localhost:6080
accept: */*
user-agent: PostmanRuntime/7.28.1
content-type: application/javascript
Connection: keep-alive
Content-Length: 2
{}
这里咱们以过滤器 decodeHttpRequest
为例,官网的阐明是 Deframes an HTTP request message
。后面提到它会产生 3 个事件,都是在 deframe
的过程中收回的。
Session
调用第一个 Filter
时,传入的事件类型是 event::Data
。decodeHttpRequest
关注该事件,并依照 HTTP 协定开始解析。
在上图能够看到解析的不同阶段,会收回不同的事件。调用 Receiver
传输事件,调用 encodeHttpResponse
的 #process()
办法。
这里又会好奇,如果下面的示例中去掉两个过滤器中的任何一个,或者都去掉,能不能失常工作?
答案是都不能!响应状态码都是 502 Bad Gateway
(curl/httpie)。
剖析
这里须要联合本文的第一张图 event-handling-flow。
去掉两个过滤器
如果两个都去掉了,HTTP Request 申请音讯会被间接回传给客户端,协定谬误。
去掉 decodeHttpRequest
后面提到 Session
传给第一个 Filter
的事件是 event::Data
。而 encodeHttpResponse
针对该事件只会将其保留到 buffer 中。
而后整个链路在此完结,没有回传任何数据。客户端会期待响应,超时退出(curl)。
去掉 encodeHttpResponse
先说后果,与后面一样超时退出。
为什么会这样,明明 decodeHttpRequest
产生了 3 个工夫,Session
里的 Receiver
也有收到,也的确写回了申请 body 里的 {}
。
encodeHttpResponse
过滤器有写回响应头,短少了这些信息,响应就不并不是非法的 HTTP 协定,只是一般的 TCP 协定。
总结
Pipy 基于事件模型的设计,提供了弱小的灵活性。容许咱们在“规定”中应用不同过滤器针对不同的事件,对申请和响应的信息进行解决。
“规定”就是业务逻辑的外围,而 Pipy 就是这逻辑的 执行引擎。
最初,“好奇心是成长的驱动力,永远放弃好奇心。”
文章对立公布在公众号
云原生指北