可編程網(wǎng)關(guān) Pipy 第三彈:事件模型設(shè)計

keep-care

自從參加了 Flomesh 的 workshop媚朦,了解了可編程網(wǎng)關(guān) Pipy氧敢。對這個“小東西”充滿了好奇,前后寫了兩篇文章询张,看了部分源碼解開了其部分面紗孙乖。但始終未見其全貌,沒有觸及其核心設(shè)計瑞侮。

不是有句話的圆,“好奇害死貓”。其實應(yīng)該還有后半句半火,“滿足了就沒事”(見維基百科)越妈。

所有就有了今天的這一篇,對前兩篇感興趣的可以跳轉(zhuǎn)翻看钮糖。

言歸正傳梅掠。

事件模型

上篇寫了 Pipy 基于事件的信息流轉(zhuǎn)酌住,其實還未深入觸及其核心的事件模型。既然是事件模型阎抒,先看事件酪我。

src/event.hpp:41 中定義了 Pipy 的四種事件:

  • Data
  • MessageStart
  • MessageEnd
  • SessionEnd

翻看源碼可知(必須吐槽文檔太少)這幾種事件其實是有順序的:MessageStart -> Data -> MessageEnd -> SessionEnd

這種面向事件模型且叁,必然有生產(chǎn)者和消費者都哭。又是翻看源碼可知,生產(chǎn)者和消費者都是 pipy::Filter逞带。我們在上篇文章中講過:每個 Pipeline 都有一個過濾器鏈欺矫,類似單向鏈表的數(shù)據(jù)結(jié)構(gòu)

那是不是按照上面說的展氓,事件是從一個 Filter 流向下一個 Filter穆趴?也對,也不對遇汞。

矛盾未妹?

先看 Filter 如何向下傳遞事件,src/session.cpp:55 處空入,Filter 持有 output 變量络它,類似為 Event::Receiver(參數(shù)為 Eventstd::function 的別名,作為外行的筆者并不懂 c++执庐,但不妨礙了解程序設(shè)計)酪耕。通過 Receiver 調(diào)用下一個 Filter#process 方法。

這里的 Receiver 就可以理解為事件發(fā)送的窗口轨淌,而 #process(Context *ctx, Event *inp) 就是事件的接收窗口迂烁。

這就是前面為什么說 “事件是從一個 Filter 流向下一個 Filter” 是正確的。

為什么不對递鹉?首先盟步,一個 Filter 會產(chǎn)生多個事件,比如 decodeHttpRequest 可能會產(chǎn)生 MessageStart躏结、DataMessageEnd 事件却盘,并且每產(chǎn)生一個事件都會通過Receiver 向下傳遞,不會等 #process 流程結(jié)束才傳遞事件媳拴;再就是下一個 Filter 可能并不會對某個事件感興趣(下一個 Filter#process 方法不做任何處理就返回了)黄橘。

可能看下圖會更容易理解(圖中 no output 表明事件不會向下傳遞):

event-handling-flow

最簡單的示例

test/001-echo/pipy.js 提供了的示例:

pipy()

.listen(6080)
  .decodeHttpRequest()
  .encodeHttpResponse()

發(fā)起請求

$ 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屈溉。前面提到它會產(chǎn)生 3 個事件塞关,都是在 deframe 的過程中發(fā)出的。

decodeHttpRequest

Session 調(diào)用第一個 Filter 時子巾,傳入的事件類型是 event::Data帆赢。decodeHttpRequest 關(guān)注該事件小压,并按照 HTTP 協(xié)議開始解析。

在上圖可以看到解析的不同階段椰于,會發(fā)出不同的事件怠益。調(diào)用 Receiver 傳輸事件,調(diào)用 encodeHttpResponse#process() 方法瘾婿。

這里又會好奇蜻牢,假如上面的示例中去掉兩個過濾器中的任何一個,或者都去掉偏陪,能不能正常工作孩饼?

答案是都不能!響應(yīng)狀態(tài)碼都是 502 Bad Gateway(curl/httpie)竹挡。

分析

這里需要結(jié)合本文的第一張圖 event-handling-flow。

去掉兩個過濾器

假如兩個都去掉了立膛,HTTP Request 請求消息會被直接回傳給客戶端揪罕,協(xié)議錯誤。

去掉 decodeHttpRequest

前面提到 Session 傳給第一個 Filter 的事件是 event::Data宝泵。而 encodeHttpResponse 針對該事件只會將其保存到 buffer 中好啰。

然后整個鏈路在此結(jié)束,沒有回傳任何數(shù)據(jù)儿奶】蛲客戶端會等待響應(yīng),超時退出(curl)闯捎。

2021-06-27-08-43-40

去掉 encodeHttpResponse

先說結(jié)果椰弊,與前面一樣超時退出。

為什么會這樣瓤鼻,明明 decodeHttpRequest 產(chǎn)生了 3 個時間秉版,Session 里的 Receiver 也有收到,也確實寫回了請求 body 里的 {}茬祷。

encodeHttpResponse 過濾器有寫回響應(yīng)頭清焕,缺少了這些信息,響應(yīng)就不并不是合法的 HTTP 協(xié)議祭犯,只是普通的 TCP 協(xié)議秸妥。

總結(jié)

Pipy 基于事件模型的設(shè)計,提供了強大的靈活性沃粗。允許我們在“規(guī)則”中使用不同過濾器針對不同的事件粥惧,對請求和響應(yīng)的信息進行處理。

“規(guī)則” 就是業(yè)務(wù)邏輯的核心陪每,而 Pipy 就是這邏輯的執(zhí)行引擎影晓。

最后镰吵,“好奇心是成長的驅(qū)動力,永遠保持好奇心挂签“碳溃”

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市饵婆,隨后出現(xiàn)的幾起案子勺馆,更是在濱河造成了極大的恐慌,老刑警劉巖侨核,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件草穆,死亡現(xiàn)場離奇詭異,居然都是意外死亡搓译,警方通過查閱死者的電腦和手機悲柱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來些己,“玉大人豌鸡,你說我怎么就攤上這事《伪辏” “怎么了涯冠?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長逼庞。 經(jīng)常有香客問我蛇更,道長,這世上最難降的妖魔是什么赛糟? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任派任,我火速辦了婚禮,結(jié)果婚禮上璧南,老公的妹妹穿的比我還像新娘吨瞎。我一直安慰自己,他們只是感情好穆咐,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布颤诀。 她就那樣靜靜地躺著,像睡著了一般对湃。 火紅的嫁衣襯著肌膚如雪崖叫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天拍柒,我揣著相機與錄音心傀,去河邊找鬼。 笑死拆讯,一個胖子當著我的面吹牛脂男,可吹牛的內(nèi)容都是我干的养叛。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼宰翅,長吁一口氣:“原來是場噩夢啊……” “哼弃甥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起汁讼,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤淆攻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后嘿架,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瓶珊,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年耸彪,在試婚紗的時候發(fā)現(xiàn)自己被綠了伞芹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蝉娜,死狀恐怖丑瞧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蜀肘,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布稽屏,位于F島的核電站扮宠,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏狐榔。R本人自食惡果不足惜坛增,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望薄腻。 院中可真熱鬧收捣,春花似錦、人聲如沸庵楷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽尽纽。三九已至咐蚯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間弄贿,已是汗流浹背春锋。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留差凹,地道東北人期奔。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓侧馅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親呐萌。 傳聞我的和親對象是個殘疾皇子馁痴,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容