上述命令會用提供的腳本啟動 Pipy 服務器。敏銳的用戶可能已經(jīng)注意到,我們通過環(huán)境變量PIPY_CONFIG_FILE提供了一個遠程 Pipy 腳本的鏈接,而不是一個本地文件,Pipy 足夠智能,可以處理這種情況。
下面是tutorial/01-hello/hello.js文件的內(nèi)容,供參考:
pipy()
.listen(8080)
.serveHTTP(
new Message('Hi, there!\n')
)
在這個腳本中,我們定義了一個端口管道,它監(jiān)聽 8080 端口,并為從監(jiān)聽端口收到的每個 HTTP 請求返回“Hi, there!”。
既然我們已經(jīng)通過上面的docker run命令暴露了本地 8080 端口,那么我們可以在同一端口上進行測試了:
$ curl http://localhost:8080
執(zhí)行上述命令,控制臺中應該顯示“Hi, there!”。
如果是出于學習、開發(fā)或調(diào)試的目的,建議在本地安裝 Pipy(從源代碼構(gòu)建 Pipy 或針對你的操作系統(tǒng)下載一個預構(gòu)建版本),因為它提供了 Web 管理控制臺以及相關(guān)的文檔和教程。
安裝到本地后,運行pipy,不需要任何參數(shù),就可以在6060端口啟動管理控制臺,但如果要監(jiān)聽不同的端口,可以通過--admin-port=參數(shù)配置。
監(jiān)聽 6060 端口的 Pipy 管理控制臺
要從源代碼構(gòu)建 Pipy 或針對你的操作系統(tǒng)安裝預編譯的二進制文件,請參考PipyGitHub 庫的 README.md 文件。
通過 CLI 運行
要啟動 Pipy 代理,可以用一個 PipyJS 腳本文件運行 Pipy。例如,如果需要一個簡單的回顯服務器,針對每個傳入的請求都用所接收到的消息體進行響應,那么就用腳本tutorial/01-hello/hello.js:
$ pipy tutorial/01-hel lo/hello.js
另外,在開發(fā)和調(diào)試時,可以啟動帶有內(nèi)置 Web UI 的 Pipy:
$ pipy tutorial/01-hello/hello.js --admin-port=6060
顯示命令行選項
$ pipy --help
列出內(nèi)置過濾器及其參數(shù)
$ pipy --list-filters
$ pipy --help-filters
前文從概念和技術(shù)上對 Pipy 做了一個簡短的介紹,這些內(nèi)容也是我們實現(xiàn)一個支持緩存和負載均衡的網(wǎng)絡代理所需要了解的,這一點我們在下一節(jié)會看到。
編寫一個網(wǎng)絡代理
假設(shè)我們正在運行不同服務的單獨實例,我們想要添加一個代理,根據(jù)請求的 URL 路徑將流量轉(zhuǎn)發(fā)到相關(guān)服務。這樣做的好處是,我們只需要提供一個 URL,并在后端擴展我們的服務,而用戶不需要分別記住不同服務的 URL。在正常情況下,服務會在不同的節(jié)點上運行,每個服務可以有多個實例在運行。假設(shè)在這個例子中,我們正在運行下面的服務,我們希望根據(jù) URI 將流量分配給它們。
服務 | URI | 主機:端口 |
service-hi | /hi/* | "127.0.0.1:8080", "127.0.0.1:8082" |
service-echo | /echo | "127.0.0.1:8081" |
service-tell-ip | /ip/* | "127.0.0.1:8082" |
Pipy 的腳本是用 JavaScript 編寫的,你可以用任何文本編輯器來編輯它們。另外,如果你在本地安裝了 Pipy,就可以使用 Pipy 提供的 Web 端管理 UI,它提供了語法高亮、自動完成、提示等特性,你甚至可以運行腳本,所有這些都在同一個控制臺上。
好了,讓我們啟動一個 Pipy 實例,不需要任何參數(shù),這樣,Pipy 管理控制臺將在 6060 端口啟動。現(xiàn)在,打開你喜歡的 Web 瀏覽器,導航到 http://localhost:6060,就會看到 Pipy 內(nèi)置的 Web 端管理 UI(如圖 1)。
創(chuàng)建一個 Pipy 程序
將代碼和配置分開是一種很好的設(shè)計實踐。Pipy 通過插件(你可以把它想成是 JavaScript 模塊)來支持這種模塊化設(shè)計。也就是說,我們將把配置數(shù)據(jù)存儲在 config 文件夾下,把編碼邏輯存儲在 plugins 文件夾下不同的文件中。主代理服務器腳本將存儲在根目錄下,主代理腳本(proxy.js)將包含并組合這些單獨的模塊所定義的功能。 一旦我們完成了下述步驟,最終的文件夾結(jié)構(gòu)將是下面這個樣子:
├── config
│ ├── balancer.JSON
│ ├── proxy.json
│ └── Router.json
├── plugins
│ ├── balancer.js
│ ├── default.js
│ └── router.js
└── proxy.js
讓我們開始吧:
- 點擊新建代碼庫,在對話框中輸入/proxy(或任何你想使用的名稱)作為代碼庫名稱,然后點擊創(chuàng)建。你將進入到新創(chuàng)建的代碼庫的代碼編輯器。
- 點擊上面的“+”按鈕,添加一個新文件。輸入/config/proxy.json(這是配置文件,我們將用來配置代理)作為文件名,然后點擊創(chuàng)建。
- 現(xiàn)在,你會看到,左側(cè)窗格的config文件夾下多了一個proxy.json文件。點擊該文件把它打開,并添加如下所示的配置信息,務必點擊頂部面板上的磁盤圖標來保存文件:
{
"listen": 8000,
"plugins": [
"plugins/router.js",
"plugins/balancer.js",
"plugins/default.js"
]
}
- 重復步驟 2 和 3,創(chuàng)建另一個文件/config/router.json,它將存儲路由信息,配置數(shù)據(jù)如下:
{
"routes": {
"/hi/*": "service-hi",
"/echo": "service-echo",
"/ip/*": "service-tell-ip"
}
}
- 重復步驟 2 和 3,創(chuàng)建另一個文件/config/balancer.json,它將存儲服務到目標的映射信息,內(nèi)容如下:
{
"services": {
"service-hi" : ["127.0.0.1:8080", "127.0.0.1:8082"],
"service-echo" : ["127.0.0.1:8081"],
"service-tell-ip" : ["127.0.0.1:8082"]
}
}
- 現(xiàn)在,我們編寫第一個 Pipy 腳本,當我們收到一個沒有配置任何目標(端點/url)的請求時,它將被用作默認的后備選項。重復上述步驟,創(chuàng)建文件/plugins/default.js。使用 default 作為文件名只是一個習慣做法,并不是 Pipy 的要求,你可以選擇任何你喜歡的名字。該腳本將包含如下代碼,返回 HTTP 狀態(tài)代碼 404,信息為 No handler found:
pipy()
.pipeline('request')
.replaceMessage(
new Message({ status: 404 }, 'No handler found')
)
- 創(chuàng)建/plugins/router.js文件,存儲路由邏輯:
(config =>
pipy({
_router: new algo.URLRouter(config.routes),
})
.export('router', {
__serviceID: '',
})
.pipeline('request')
.handleMessageStart(
msg => (
__serviceID = _router.find(
msg.head.headers.host,
msg.head.path,
)
)
)
)(JSON.decode(pipy.load('config/router.json')))
- 創(chuàng)建/plugins/balancer.js文件,存儲了我們的負載均衡邏輯。順便說明一下,Pipy 提供了多種負載均衡算法,但簡單起見,我們這里將使用 Round Robin 算法。
(config =>
pipy({
_services: (
Object.fromEntries(
Object.entries(config.services).map(
([k, v]) => [
k, new algo.RoundRobinLoadBalancer(v)
]
)
)
),
_balancer: null,
_balancerCache: null,
_target: '',
})
.import({
__turnDown: 'proxy',
__serviceID: 'router',
})
.pipeline('session')
.handleStreamStart(
() => (
_balancerCache = new algo.Cache(
// k is a balancer, v is a target
(k ) => k.select(),
(k,v) => k.deselect(v),
)
)
)
.handleStreamEnd(
() => (
_balancerCache.clear()
)
)
.pipeline('request')
.handleMessageStart(
() => (
_balancer = _services[__serviceID],
_balancer && (_target = _balancerCache.get(_balancer)),
_target && (__turnDown = true)
)
)
.link(
'forward', () => Boolean(_target),
''
)
.pipeline('forward')
.muxHTTP(
'connection',
() => _target
)
.pipeline('connection')
.connect(
() => _target
)
)(JSON.decode(pipy.load('config/balancer.json')))
- 現(xiàn)在,我們來編寫入口點或代理服務器腳本,它會使用上述插件。創(chuàng)建一個新的代碼庫(步驟 1),這個過程會創(chuàng)建一個默認的main.js文件作為入口點。我們可以用它作為我們的主入口點,或者如果你希望換個名字,可以隨時刪除main.js,然后用你選的名字新建一個文件。讓我們刪除它并新建一個名為/proxy.js的文件。務必點下頂部的旗標,將其設(shè)置為主入口點,這可以確保在你點擊運行按鈕(右側(cè)的箭頭圖標)時開始執(zhí)行腳本:
(config =>
pipy()
.export('proxy', {
__turnDown: false,
})
.listen(config.listen)
.use(config.plugins, 'session')
.demuxHTTP('request')
.pipeline('request')
.use(
config.plugins,
'request',
'response',
() => __turnDown
)
)(JSON.decode(pipy.load('config/proxy.json')))
如果你已經(jīng)按照上面的步驟進行了操作,就可以看到類似于以下截圖的東西:
現(xiàn)在,我們點擊播放圖標按鈕(右起第四個)來運行我們的腳本。如果腳本沒有任何錯誤,我們將看到 Pipy 運行我們的代理腳本,輸出類似下面這樣:
這表明我們的代理服務器正在監(jiān)聽 8000 端口(這是在/config/proxy.json中配置的)。我們用 curl 來運行一個測試:
$ curl -i http://localhost:8000
HTTP/1.1 404 Not Found
content-length: 10
connection: keep-alive
No handler found
這沒問題,因為我們沒有為 root 配置任何目標。讓我們試下配置過的路由,如/hi:
$ curl -i http://localhost:8000/hi
HTTP/1.1 502 Connection Refused
content-length: 0
connection: keep-alive
我們看到了 502 Connection Refused 這個消息,因為我們沒有在配置的目標端口上運行服務。
你可以更新/config/balancer.json,加入你已經(jīng)運行的服務的主機、端口等細節(jié),以匹配你的實際情況,或者我們在 Pipy 中編寫一個腳本,監(jiān)聽我們配置的端口,并返回簡單的消息。
將以下代碼片段保存到你本地計算機上的一個文件中,命名為mock-proxy.js,并記住文件的存儲位置。
pipy()
.listen(8080)
.serveHTTP(
new Message('Hi, there!\n')
)
.listen(8081)
.serveHTTP(
msg => new Message(msg.body)
)
.listen(8082)
.serveHTTP(
msg => new Message(
`You are requesting ${msg.head.path} from ${__inbound.remoteAddress}\n`
)
)
打開一個新的終端窗口,通過 Pipy 運行這個腳本(其中/path/to是存儲該腳本文件的位置):
$ pipy /path/to/mock-proxy.js
2022-01-11 18:56:31 [INF] [config]
2022-01-11 18:56:31 [INF] [config] Module /mock-proxy.js
2022-01-11 18:56:31 [INF] [config] ================
2022-01-11 18:56:31 [INF] [config]
2022-01-11 18:56:31 [INF] [config] [Listen on :::8080]
2022-01-11 18:56:31 [INF] [config] ----->|
2022-01-11 18:56:31 [INF] [config] |
2022-01-11 18:56:31 [INF] [config] serveHTTP
2022-01-11 18:56:31 [INF] [config] |
2022-01-11 18:56:31 [INF] [config] <-----|
2022-01-11 18:56:31 [INF] [config]
2022-01-11 18:56:31 [INF] [config] [Listen on :::8081]
2022-01-11 18:56:31 [INF] [config] ----->|
2022-01-11 18:56:31 [INF] [config] |
2022-01-11 18:56:31 [INF] [config] serveHTTP
2022-01-11 18:56:31 [INF] [config] |
2022-01-11 18:56:31 [INF] [config] <-----|
2022-01-11 18:56:31 [INF] [config]
2022-01-11 18:56:31 [INF] [config] [Listen on :::8082]
2022-01-11 18:56:31 [INF] [config] ----->|
2022-01-11 18:56:31 [INF] [config] |
2022-01-11 18:56:31 [INF] [config] serveHTTP
2022-01-11 18:56:31 [INF] [config] |
2022-01-11 18:56:31 [INF] [config] <-----|
2022-01-11 18:56:31 [INF] [config]
2022-01-11 18:56:31 [INF] [listener] Listening on port 8080 at ::
2022-01-11 18:56:31 [INF] [listener] Listening on port 8081 at ::
2022-01-11 18:56:31 [INF] [listener] Listening on port 8082 at ::
現(xiàn)在,我們已經(jīng)模擬了監(jiān)聽 8080、8081 和 8082 端口的服務。讓我們在代理服務器上再做一次測試,你會看到,模擬服務返回了正確的響應。
小結(jié)
我們使用了 Pipy 的許多特性,包括變量聲明、導入/導出變量、插件、管道、子管道、過濾器鏈、handleMessageStart、handleStreamStart和link等 Pipy 過濾器,以及JSON、algo.URLRouter、algo.RoundRobinLoadBalancer和algo.Cache等 Pipy 類。徹底解釋所有這些概念超出了本文的范圍,如果你希望了解更多信息,請閱讀 Pipy 的文檔。你可以通過 Pipy 的 Web 端管理 UI 查看這些文檔,并按照入門教程一步步操作。
結(jié)語
來自Flomesh的 Pipy 是一個開源、高性能、輕量級的網(wǎng)絡流量處理器,適用于多種場景,包括邊緣路由器、負載平衡 &代理(正向/反向)、API 網(wǎng)關(guān)、靜態(tài) HTTP 服務器、服務網(wǎng)格挎斗等。Pipy 仍在積極開發(fā)之中,并由全職的提交者和貢獻者維護,雖然仍是早期版本,但已有多個商業(yè)客戶完成了測試并投入生產(chǎn)應用。它的創(chuàng)建者和維護者Flomesh.cn提供的商用解決方案就是以 Pipy 為核心。
這篇文章對 Pipy 做了一個非常簡要的介紹和概述。GitHub 上提供了入門教程和文檔,你也可以通過 Pipy 管理控制臺的 Web UI 查看。社區(qū)非常歡迎大家為 Pipy 的發(fā)展做貢獻,也歡迎大家在自己特定的場景下進行試用,或者提供反饋和意見。
作者簡介:
Ali Naqvi 是一位擁有超過 20 年 IT 行業(yè)經(jīng)驗的專業(yè)人士。他非常熱衷于開發(fā)以及為開源軟件做貢獻。他主要關(guān)注開發(fā)、軟件架構(gòu)、DevOps 等領(lǐng)域。他經(jīng)常發(fā)表演講,是當?shù)厣鐓^(qū)/分會的活躍成員,致力于傳播 OSS、DevOps 和 Agile 理念和知識。
原文鏈接:
How to Create a Network Proxy Using Stream Processor Pipy
好了,這篇文章的內(nèi)容發(fā)貨聯(lián)盟就和大家分享到這里,如果大家網(wǎng)絡推廣引流創(chuàng)業(yè)感興趣,可以添加微信:80709525 備注:發(fā)貨聯(lián)盟引流學習; 我拉你進直播課程學習群,每周135晚上都是有實戰(zhàn)干貨的推廣引流技術(shù)課程免費分享!