日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

詳解Nginx如何代理UDP連接

瀏覽:29日期:2023-08-03 20:13:38
目錄UDP 連接實(shí)驗(yàn)基礎(chǔ)配置reuseportproxy_xxx directives動(dòng)態(tài)代理總結(jié)UDP 連接

眾所周知,UDP 并不像 TCP 那樣是基于連接的。但有些時(shí)候,我們需要往一個(gè)固定的地址發(fā)送多個(gè) UDP 來完成一個(gè) UDP 請求。為了保證服務(wù)端能夠知道這幾個(gè) UDP 包構(gòu)成同一個(gè)會(huì)話,我們需要在發(fā)送 UDP 包時(shí)綁定某個(gè)端口,這樣當(dāng)網(wǎng)絡(luò)棧通過五元組(協(xié)議、客戶端IP、客戶端端口、服務(wù)端IP、服務(wù)端端口)進(jìn)行區(qū)分時(shí),那幾個(gè) UDP 包能夠分到一起。通常我們會(huì)把這種現(xiàn)象稱之為 UDP 連接。

但這樣又有了一個(gè)新的問題。不同于 TCP 那樣有握手和揮手,UDP 連接僅僅意味著使用固定的客戶端端口。雖然作為服務(wù)端,由于事先就跟客戶端約定好了一套固定的協(xié)議,可以知道一個(gè) UDP 連接應(yīng)當(dāng)在何處終止。但如果中間使用了代理服務(wù)器,那么代理是如何區(qū)分某幾個(gè) UDP 包是屬于某個(gè) UDP 連接呢?畢竟沒有握手和揮手作為分隔符,一個(gè)中間人是不清楚某個(gè)會(huì)話應(yīng)當(dāng)在何處放下句號的。

通過下面的實(shí)驗(yàn),我們會(huì)看到 Nginx 是如何處理這個(gè)問題的。

實(shí)驗(yàn)

在接下來的幾個(gè)實(shí)驗(yàn)中,我都會(huì)用一個(gè)固定的客戶端。這個(gè)客戶端會(huì)向 Nginx 監(jiān)聽的地址建立 UDP “連接”,然后發(fā)送 100 個(gè) UDP 包。

// save it as main.go, and run it like `go run main.go`package mainimport ( 'fmt' 'net' 'os')func main() { conn, err := net.Dial('udp', '127.0.0.1:1994') if err != nil {fmt.Printf('Dial err %v', err)os.Exit(-1) } defer conn.Close() msg := 'H' for i := 0; i < 100; i++ {if _, err = conn.Write([]byte(msg)); err != nil { fmt.Printf('Write err %v', err) os.Exit(-1)} }}基礎(chǔ)配置

下面是實(shí)驗(yàn)中用到的 Nginx 基礎(chǔ)配置。后續(xù)實(shí)驗(yàn)都會(huì)在這個(gè)基礎(chǔ)上做些改動(dòng)。

這個(gè)配置中,Nginx 會(huì)有 4 個(gè) worker 進(jìn)程監(jiān)聽 1994 端口,并代理到 1995 端口上。錯(cuò)誤日志會(huì)發(fā)往標(biāo)準(zhǔn)錯(cuò)誤,而訪問日志會(huì)發(fā)往標(biāo)準(zhǔn)輸出。

worker_processes 4;daemon off;error_log /dev/stderr warn;events { worker_connections 10240;}stream { log_format basic '[$time_local] ' 'received: $bytes_received ' '$session_time'; server {listen 1994 udp;access_log /dev/stdout basic;preread_by_lua_block { ngx.log(ngx.ERR, ngx.worker.id(), ' ', ngx.var.remote_port)}proxy_pass 127.0.0.1:1995;proxy_timeout 10s; } server {listen 1995 udp;return 'data'; }}

輸出如下:

2023/01/27 18:00:59 [error] 6996#6996: *2 stream [lua] preread_by_lua(nginx.conf:48):2: 1 51933 while prereading client data, udp client: 127.0.0.1, server: 0.0.0.0:19942023/01/27 18:00:59 [error] 6995#6995: *4 stream [lua] preread_by_lua(nginx.conf:48):2: 0 51933 while prereading client data, udp client: 127.0.0.1, server: 0.0.0.0:19942023/01/27 18:00:59 [error] 6997#6997: *1 stream [lua] preread_by_lua(nginx.conf:48):2: 2 51933 while prereading client data, udp client: 127.0.0.1, server: 0.0.0.0:19942023/01/27 18:00:59 [error] 6998#6998: *3 stream [lua] preread_by_lua(nginx.conf:48):2: 3 51933 while prereading client data, udp client: 127.0.0.1, server: 0.0.0.0:1994[27/Jan/2023:18:01:09 +0800] received: 28 10.010[27/Jan/2023:18:01:09 +0800] received: 27 10.010[27/Jan/2023:18:01:09 +0800] received: 23 10.010[27/Jan/2023:18:01:09 +0800] received: 22 10.010

可以看出,全部 100 個(gè) UDP 包分散到了每個(gè) worker 進(jìn)程上。看來 Nginx 并沒有把來自同一個(gè)地址的 100 個(gè)包當(dāng)作同一個(gè)會(huì)話,畢竟每個(gè)進(jìn)程都會(huì)讀取 UDP 數(shù)據(jù)。

reuseport

要想讓 Nginx 代理 UDP 連接,需要在 listen 時(shí)指定 reuseport:

... server {listen 1994 udp reuseport;access_log /dev/stdout basic;

現(xiàn)在全部 UDP 包都會(huì)落在同一個(gè)進(jìn)程上,并被算作同一個(gè)會(huì)話:

2023/01/27 18:02:39 [error] 7191#7191: *1 stream [lua] preread_by_lua(nginx.conf:48):2: 3 55453 while prereading client data, udp client: 127.0.0.1, server: 0.0.0.0:1994[27/Jan/2023:18:02:49 +0800] received: 100 10.010

多個(gè)進(jìn)程在監(jiān)聽同一個(gè)地址時(shí),如果設(shè)置了 reuseport 時(shí),Linux 會(huì)根據(jù)五元組的 hash 來決定發(fā)往哪個(gè)進(jìn)程。這樣一來,同一個(gè) UDP 連接里面的所有包就會(huì)落到一個(gè)進(jìn)程上。

順便一提,如果在 1995 端口的 server 上打印接受到的 UDP 連接的客戶端地址(即 Nginx 跟上游通信的地址),我們會(huì)發(fā)現(xiàn)同一個(gè)會(huì)話的地址是一樣的。也即是 Nginx 在代理到上游時(shí),默認(rèn)就會(huì)使用 UDP 連接來傳遞整個(gè)會(huì)話。

proxy_xxx directives

相信讀者也已經(jīng)注意到,在錯(cuò)誤日志中記錄的 UDP 訪問開始時(shí)間,和在訪問日志中記錄的結(jié)束時(shí)間,正好差了 10 秒。該時(shí)間段對應(yīng)了配置里的 proxy_timeout 10s;。由于 UDP 連接中沒有揮手的說法,Nginx 默認(rèn)根據(jù)每個(gè)會(huì)話的超時(shí)時(shí)間來決定會(huì)話何時(shí)終止。默認(rèn)情況下,一個(gè)會(huì)話的持續(xù)時(shí)間是 10 分鐘,只是由于我缺乏耐心,所以特定配成了 10 秒。

除了超時(shí)時(shí)間,Nginx 還會(huì)依靠什么條件決定會(huì)話的終止呢?請往下看:

...proxy_timeout 10s;proxy_responses 1;

在新增了 proxy_responses 1 后,輸出變成了這樣:

2023/01/27 18:07:35 [error] 7552#7552: *1 stream [lua] preread_by_lua(nginx.conf:48):2: 2 36308 while prereading client data, udp client: 127.0.0.1, server: 0.0.0.0:1994[27/Jan/2023:18:07:35 +0800] received: 62 0.0032023/01/27 18:07:35 [error] 7552#7552: *65 stream [lua] preread_by_lua(nginx.conf:48):2: 2 36308 while prereading client data, udp client: 127.0.0.1, server: 0.0.0.0:1994[27/Jan/2023:18:07:35 +0800] received: 9 0.0002023/01/27 18:07:35 [error] 7552#7552: *76 stream [lua] preread_by_lua(nginx.conf:48):2: 2 36308 while prereading client data, udp client: 127.0.0.1, server: 0.0.0.0:1994[27/Jan/2023:18:07:35 +0800] received: 7 0.0002023/01/27 18:07:35 [error] 7552#7552: *85 stream [lua] preread_by_lua(nginx.conf:48):2: 2 36308 while prereading client data, udp client: 127.0.0.1, server: 0.0.0.0:1994[27/Jan/2023:18:07:35 +0800] received: 3 0.0002023/01/27 18:07:35 [error] 7552#7552: *90 stream [lua] preread_by_lua(nginx.conf:48):2: 2 36308 while prereading client data, udp client: 127.0.0.1, server: 0.0.0.0:1994[27/Jan/2023:18:07:35 +0800] received: 19 0.000

我們看到 Nginx 不再被動(dòng)等待時(shí)間超時(shí),而是在收到上游發(fā)來的包之后就終止了會(huì)話。proxy_timeout 和 proxy_responses 兩者間是“或”的關(guān)系。

和 proxy_responses 相對的有一個(gè) proxy_requests:

...proxy_timeout 10s;proxy_responses 1;proxy_requests 50;

在配置了 proxy_requests 50 后,我們會(huì)看到每個(gè)請求的大小都穩(wěn)定在 50 個(gè) UDP 包:

2023/01/27 18:08:55 [error] 7730#7730: *1 stream [lua] preread_by_lua(nginx.conf:48):2: 0 49881 while prereading client data, udp client: 127.0.0.1, server: 0.0.0.0:19942023/01/27 18:08:55 [error] 7730#7730: *11 stream [lua] preread_by_lua(nginx.conf:48):2: 0 49881 while prereading client data, udp client: 127.0.0.1, server: 0.0.0.0:1994[27/Jan/2023:18:08:55 +0800] received: 50 0.002[27/Jan/2023:18:08:55 +0800] received: 50 0.001

注意讓會(huì)話終止所需的上游響應(yīng)的 UDP 數(shù)是 proxy_requests * proxy_responses。在上面的例子中,如果我們把 proxy_responses 改成 2,那么要過 10 秒才會(huì)終止會(huì)話。因?yàn)檫@么做之后,對應(yīng)每 50 個(gè) UDP 包的請求,需要響應(yīng) 100 個(gè) UDP 包才會(huì)終止會(huì)話,而每個(gè)請求的 UDP 包只會(huì)得到一個(gè) UDP 作為響應(yīng),所以只能等超時(shí)了。

動(dòng)態(tài)代理

在大多數(shù)時(shí)候,UDP 請求的包數(shù)不是固定的,我們可能要根據(jù)開頭的某個(gè)長度字段來確定會(huì)話的包數(shù),抑或通過某個(gè)包的包頭是否有 eof 標(biāo)記來判斷什么時(shí)候終結(jié)當(dāng)前會(huì)話。目前 Nginx 的幾個(gè) proxy_* 指令都只支持固定值,不支持借助變量動(dòng)態(tài)設(shè)置。

proxy_requests 和 proxy_responses 實(shí)際上只是設(shè)置了 UDP session 上的對應(yīng)計(jì)數(shù)器。所以理論上我們可以修改 Nginx,暴露出 API 來動(dòng)態(tài)調(diào)整當(dāng)前 UDP session 的計(jì)數(shù)器的值,實(shí)現(xiàn)按上下文決定 UDP 請求邊界的功能。那是否存在不修改 Nginx 的解決方案呢?

換個(gè)思路,我們能不能通過 Lua 把客戶端數(shù)據(jù)都讀出來,然后在 Lua 層面上由 cosocket 發(fā)送給上游?通過 Lua 實(shí)現(xiàn)上游代理這個(gè)思路確實(shí)挺富有想象力,可惜它目前是行不通的。

使用如下代碼代替前面的 preread_by_lua_block:

content_by_lua_block { local sock = ngx.req.socket() while true dolocal data, err = sock:receive()if not data then if err and err ~= 'no more data' thenngx.log(ngx.ERR, err) end returnendngx.log(ngx.WARN, 'message received: ', data) end}proxy_timeout 10s;proxy_responses 1;proxy_requests 50;

我們會(huì)看到這樣的輸出:2023/01/27 18:17:56 [warn] 8645#8645: *1 stream [lua] content_by_lua(nginx.conf:59):12: message received: H, udp client: 127.0.0.1, server: 0.0.0.0:1994[27/Jan/2023:18:17:56 +0800] received: 1 0.000...

由于在 UDP 下面, ngx.req.socket:receive 目前只支持讀取第一個(gè)包,所以即使我們設(shè)置了 while true 循環(huán),也得不到全部的客戶端請求。另外由于 content_by_lua 會(huì)覆蓋掉 proxy_* 指令,所以 Nginx 并沒有走代理邏輯,而是認(rèn)為當(dāng)前請求只有一個(gè)包。把 content_by_lua 改成 preread_by_lua 后,雖然 proxy_* 指令這下子生效了,但因?yàn)槟貌坏饺靠蛻舳苏埱螅廊粺o法完成 Lua 層面上的代理。

總結(jié)

假如 Nginx 代理的是 DNS 這種只有一個(gè)包的基于 UDP 的協(xié)議,那么使用 listen udp 就夠了。但如果需要代理包含多個(gè)包的基于 UDP 的協(xié)議,那么還需要加上 reuseport。另外,Nginx 目前還不支持動(dòng)態(tài)設(shè)置每個(gè) UDP 會(huì)話的大小,所以沒辦法準(zhǔn)確區(qū)分不同的 UDP 會(huì)話。Nginx 代理 UDP 協(xié)議時(shí)能用到的功能,更多集中于像限流這種不需要關(guān)注單個(gè) UDP 會(huì)話的。

以上就是詳解Nginx如何代理UDP連接的詳細(xì)內(nèi)容,更多關(guān)于Nginx代理UDP連接的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Nginx
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
久久爱www成人| 久久精品国产一区二区| 久久不卡日韩美女| 日本亚洲不卡| 国产麻豆一区二区三区精品视频| 亚洲在线一区| 国产suv精品一区二区四区视频 | 欧美日韩国产传媒| 欧美高清一区| 日韩电影免费在线观看| 日韩电影二区| 国产精品外国| 三级欧美在线一区| 国产精品一区二区三区av麻| 免费在线观看一区| 国产精品亚洲综合色区韩国| 99久久www免费| 午夜亚洲福利| 久久麻豆精品| 国产乱码精品| 中文字幕在线免费观看视频| 99久久婷婷| 亚洲深夜av| 国产欧美日韩在线一区二区 | 国产一区91| 欧美日韩一区二区三区不卡视频| 高清不卡亚洲| 欧美日韩 国产精品| 欧美日韩一二| 日韩福利视频网| 国产成人久久精品一区二区三区| 99久久夜色精品国产亚洲1000部| 亚州av日韩av| 国产精品一区亚洲| 久久久精品午夜少妇| 国产精品资源| 国内激情久久| 欧美丰满日韩| 亚洲欧美激情诱惑| 鲁鲁在线中文| 你懂的国产精品| 999国产精品视频| 国产精品主播| 伊人www22综合色| 99视频精品全国免费| 久久国产三级精品| 婷婷国产精品| 日本久久一区| 麻豆精品91| 伊人久久亚洲热| 99视频精品视频高清免费| 精品中国亚洲| 国产亚洲一区| 亚洲日产av中文字幕| 99亚洲精品| 成人午夜精品| 欧美片第1页| 色综合五月天| 国产精品三级| 日本在线观看不卡视频| 亚洲网址在线观看| 精品日产乱码久久久久久仙踪林| 日韩av三区| 四虎在线精品| 人人精品久久| 欧美午夜网站| 国产精品qvod| 欧美韩日一区| 好吊日精品视频| 激情综合自拍| 日韩美女国产精品| 国产伦一区二区三区| 视频一区二区三区中文字幕| 亚洲2区在线| 中文字幕日本一区| 国产欧美日韩视频在线 | 亚洲自啪免费| 国产精品7m凸凹视频分类| 岛国精品一区| 亚洲91久久| 91久久在线| 国产精品mv在线观看| 日本欧美国产| 成人片免费看| 黄色亚洲在线| 日韩中文一区二区| 久久精品xxxxx| 四虎8848精品成人免费网站| 久久美女精品| 日韩午夜精品| 日韩精品一区二区三区免费视频| 麻豆一区二区三| 性欧美videohd高精| 99在线精品免费视频九九视| 亚洲综合激情在线| 欧美亚洲tv| 91亚洲人成网污www| 好吊日精品视频| 久久久精品国产**网站| 丝瓜av网站精品一区二区 | 午夜精品一区二区三区国产| 国产乱子精品一区二区在线观看| 四虎8848精品成人免费网站| 日韩动漫一区| 成人精品久久| 亚洲1区在线| 91精品国产91久久久久久黑人| 日韩不卡在线观看日韩不卡视频 | 婷婷综合成人| 欧美男人天堂| 国产人成精品一区二区三| 激情六月综合| 精品久久精品| 99国产精品久久久久久久| 国产精品一区二区三区av麻| 免费高潮视频95在线观看网站| 国产精品亚洲人成在99www| 国产精品色网| 欧美精品二区| 国产情侣一区在线| 亚洲无线一线二线三线区别av| 国产免费播放一区二区| 日韩一区欧美二区| 久久精品成人| 日韩成人亚洲| 国产精品视频3p| 青草av.久久免费一区| 黄色不卡一区| 欧美精品二区| 欧美精品导航| 蜜桃精品视频| 精品国产一区二区三区2021| 最新亚洲国产| 国产精品毛片| 蜜桃伊人久久| 久久最新视频| 久久精品二区亚洲w码| 国产人成精品一区二区三| 亚洲黄色免费av| 欧美精品九九| 免费在线成人| 亚洲天堂日韩在线| 97精品一区二区| 色综合视频一区二区三区日韩 | 久久国内精品视频| 亚洲精品福利| 精品国产亚洲日本| 首页亚洲欧美制服丝腿| 色爱综合网欧美| 日韩欧美激情| 精品一区欧美| 日本强好片久久久久久aaa| 国产美女高潮在线| 欧美日韩亚洲一区二区三区在线| 久久三级福利| 国产精品成人自拍| 99re国产精品| 黄色网一区二区| 亚洲精品免费观看| 中国字幕a在线看韩国电影| 少妇精品久久久一区二区| 精品免费视频| 卡一精品卡二卡三网站乱码| 三级在线观看一区二区| 国产99久久久国产精品成人免费| 久久亚洲道色| 国产一区不卡| 日韩欧美一区二区三区在线观看 | 亚洲一区二区动漫| 中文在线а√天堂| 欧美日韩18| 日韩精品乱码av一区二区| 亚洲成人日韩| 视频小说一区二区| 日本麻豆一区二区三区视频| 久久九九电影| 超碰在线99| 精品三级在线| 精品视频在线观看网站| 国产亚洲人成a在线v网站| 蜜臀久久久久久久| 一区免费在线| 日韩视频二区| 麻豆91精品| 亚洲精品高潮| 18国产精品| 国产精品啊v在线| 91九色综合| 日韩成人一级| 综合亚洲色图| 婷婷精品在线观看| 国产欧美在线观看免费| 国产精品久久久久久久久免费高清 | 国产日韩视频在线| 久久国产日韩欧美精品| 日本欧美久久久久免费播放网| 亚洲一二三区视频| 热久久久久久| 国产在视频一区二区三区吞精| 日韩久久精品|