校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃

主頁 > 知識庫 > nginx作grpc的反向代理踩坑總結

nginx作grpc的反向代理踩坑總結

熱門標簽:威海人工外呼系統供應商 撫順移動400電話申請 貴陽教育行業電話外呼系統 藍點外呼系統 烏海智能電話機器人 寧夏房產智能外呼系統要多少錢 做外呼系統的公司違法嗎 400電話申請方案 在百度地圖標注車輛

背景

眾所周知,nginx是一款高性能的web服務器,常用于負載均衡和反向代理。所謂的反向代理是和正向代理相對應,正向代理即我們常規意義上理解的“代理”:例如正常情況下在國內是無法訪問google的,如果我們需要訪問,就需要通過一層代理去轉發。這個正向代理代理的是服務端(也就是google),而反向代理則相反,代理的是客戶端(也就是用戶),用戶的請求到達nginx后,nginx會代理用戶的請求向實際的后端服務發起請求,并將結果返回給用戶。

(圖片來自維基百科)

正向代理和反向代理實際上是站在用戶的角度來定義的,正向也就是代理用戶所要請求的服務,而反向則是代理用戶向服務發起請求。兩者一個很重要的區別:

正向代理服務方不感知請求方,反向代理請求方不感知服務方。
思考一下上面的例子,你通過代理訪問google時,google只能感知到請求來自代理服務器,而無法直接感知到你(當然通過cookie等手段也可以追蹤到);而通過nginx反向代理時,你是不感知請求具體被轉發到哪個后端服務器上的。

nginx最常被用于反向代理的場景就是我們所熟知的http協議,通過配置nginx.conf文件可以很簡單地定義一個反向代理規則:

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    server {
        listen       80;
        server_name  localhost;

        
        location / {
            proxy_pass http://domain;
        }
    }
}

nginx從1.13.10以后就支持gRPC協議的反向代理,配置類似:

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    server {
        listen       81 http2;
        server_name  localhost;

        
        location / {
            grpc_pass http://ip;
        }
    }
}

但是當需求場景更加復雜的時候,就發現nginx的gRPC模塊實際上有很多坑,實現的能力不如http完整,當套用http的解決方案時就會出現問題

場景

最開始我們的場景很簡單,通過gRPC協議實現一個簡單的C/S架構:

但這種單純的直連有些場景下是不可行的,例如client和server在兩個網絡環境下,彼此不相連通,那就無法通過簡單的gRPC連接訪問服務。一種解決辦法是通過中間的代理服務器轉發,用上面說的nginx反向代理gRPC方法:

nginx proxy部署在兩個環境都能訪問的集群上,這樣就實現了跨網絡環境的gRPC訪問。隨之而來的問題是如何配置這個路由規則?注意我們最開始的gRPC的目標節點都是清晰的,也就是server1和server2的ip地址,當中間加了一層nginx proxy后,client發起的gRPC請求的對象都是nginx proxy的ip地址。那client與nginx建立連接后,nginx如何知道需要將請求轉發給server1還是server2呢?(這里server1和server2不是簡單的同一個服務的冗備部署,可能需要根據請求的屬性決定由誰響應,例如用戶id等,因此不能使用負載均衡隨機挑選一個響應請求)

解決辦法

如果是http協議,那有很多實現方法:

通過路徑區分

請求將server的信息添加在path里,例如:/server1/service/method,然后nginx轉發請求的時候還原為原始的請求:

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    server {
        listen       80;
        server_name  localhost;

        location ~ ^/server1/ {
            proxy_pass http://domain1/;
        }
        
        location ~ ^/server2/ {
            proxy_pass http://domain2/;
        }
    }
}

注意http://domain/最后的斜杠,如果沒有這個斜杠請求的路徑會是/server1/service/method,而服務端只能響應/service/method的請求,這樣就會報404的錯誤。

通過請求參數區分

也可以將server1的信息放在請求參數里:

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    server {
        listen       80;
        server_name  localhost;

        location /service/method {
            if ($query_string ~ x_server=(.*)) {
                proxy_pass http://$1;
            }
        }
    }
}

但對于gRPC就沒這么簡單了,首先gRPC不支持URI的寫法,nginx轉發的請求會保留原來的path,無法在轉發的時候修改path,這意味著上述的第一種辦法不可行。其次gRPC是基于HTTP 2.0協議的,HTTP2沒有queryString這一概念,請求頭里有一項:path代表請求的路徑,例如/service/method,而這一路徑是不能攜帶請求參數的,也就是:path不能寫為/service/method?server=server1。這意味著上述的第二種方法也不可行。

注意到HTTP2中請求頭:path是指定請求的路徑的,那我們直接修改:path不就行了嗎:

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    server {
        listen       80 http2;
        server_name  localhost;

        location ~ ^/(.*)/service/.* {
            grpc_set_header :path /service/$2;
            grpc_pass http://$1;
        }
    }
}

但是實際驗證表明這種方法也不可行,直接修改:path的請求頭會導致服務端報錯,一種可能的錯誤如下:

rpc error: code = Unavailable desc = Bad Gateway: HTTP status code 502; transport: received the unexpected content-type "text/html"

抓包后發現,grpc_set_header并沒有覆蓋:path的結果,而是新增了一項請求頭,相當于請求header里存在兩個:path,可能就是因為這個原因導致服務端報了502的錯誤。

山窮水盡之際想起gRPC的metadata功能,我們可以在client端將server的信息存儲在metadata中,然后在nginx路由時根據metadata中server的信息轉發給對應的后端服務,這樣就實現了我們的需求。對于go語言,設置metadata需要實現PerRPCCredentials接口,然后在發起連接的時候傳入這個實現類的實例:

type extraMetadata struct {
    Ip string
}

func (c extraMetadata) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
    return map[string]string{
        "x-ip": c.Ip,
    }, nil
}

func (c extraMetadata) RequireTransportSecurity() bool {
    return false
}

func main(){
    ...
    // nginxProxy是nginx proxy的ip或域名地址
    var nginxProxy string
    // serverIp是根據請求屬性計算好的后端服務的ip
    var serverIp string
    con, err := grpc.Dial(nginxProxy, grpc.WithInsecure(),
        grpc.WithPerRPCCredentials(extraMetadata{Ip: serverIp}))
}

然后在nginx配置里根據這個metadata轉發到對應的server:

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    server {
        listen       80 http2;
        server_name  localhost;

        location ~ ^/service/.* {
            grpc_pass grpc://$http_x_ip:8200;
        }
    }
}

注意這里使用了$http_x_ip這一語法引用了我們傳遞的x-ip這個metadata信息。這一方法驗證有效,client可以通過nginx proxy成功訪問到server的gRPC服務。

總結

nginx的gRPC模塊的文檔太少了,官方文檔只給出了幾個指令的用途,并沒有說明metadata這一方法,網上的文檔也鮮有涉及,導致花了兩三天的時間在排查。將整個過程總結在這里,希望能幫助到遇到同一問題的人。

到此這篇關于nginx作grpc的反向代理踩坑總結的文章就介紹到這了,更多相關nginx grpc反向代理內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

標簽:周口 銅川 松原 泰州 慶陽 蕪湖 那曲 朝陽

巨人網絡通訊聲明:本文標題《nginx作grpc的反向代理踩坑總結》,本文關鍵詞  nginx,作,grpc,的,反向,代理,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《nginx作grpc的反向代理踩坑總結》相關的同類信息!
  • 本頁收集關于nginx作grpc的反向代理踩坑總結的相關信息資訊供網民參考!
  • 推薦文章
    校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃
    国产麻豆成人精品| 水野朝阳av一区二区三区| 欧美一级精品大片| 一区二区在线观看免费| 亚洲成人免费视| 欧美三级在线视频| 亚洲男同1069视频| 94-欧美-setu| 午夜私人影院久久久久| 色婷婷国产精品| 亚洲精品视频在线| 色国产综合视频| 天天免费综合色| 日韩欧美一卡二卡| 国产91在线观看丝袜| 一区二区高清免费观看影视大全| 欧美日韩精品二区第二页| 日本强好片久久久久久aaa| 欧美人妇做爰xxxⅹ性高电影| 国产精品视频观看| 一本久久精品一区二区| 蜜臀av一级做a爰片久久| 国产精品久久福利| 色视频一区二区| 国产精品一级二级三级| 亚洲欧美韩国综合色| 欧美日韩视频在线第一区 | 91丨porny丨中文| 自拍偷拍国产精品| 精品国产乱子伦一区| 97精品久久久久中文字幕| 午夜精品一区二区三区三上悠亚| 一区在线播放视频| 久久综合一区二区| 久久久久免费观看| 欧美电影免费观看高清完整版在线 | 成人污视频在线观看| 日韩高清不卡在线| 亚洲一区二区欧美激情| 久久久久久麻豆| 久久日一线二线三线suv| 91久久精品午夜一区二区| av亚洲精华国产精华精华| 色综合天天综合在线视频| 豆国产96在线|亚洲| 成人白浆超碰人人人人| 久久se这里有精品| 国产在线不卡一区| 国产在线不卡一卡二卡三卡四卡| 久久99久久久久久久久久久| 成人h动漫精品| 欧美视频一区二区三区四区 | 亚洲在线一区二区三区| 一区二区三区免费看视频| 亚洲综合图片区| 紧缚捆绑精品一区二区| 不卡影院免费观看| 在线观看成人免费视频| 欧美一级免费大片| 亚洲精品久久7777| 国产一区二区三区久久悠悠色av| 成人黄色免费短视频| jiyouzz国产精品久久| 7777精品伊人久久久大香线蕉完整版 | 国产精品国产自产拍高清av | 日韩电影在线观看一区| 一个色综合av| 国产精一区二区三区| 久久亚洲精品小早川怜子| 亚洲电影一级黄| 欧美在线观看你懂的| 国产日产欧美一区二区三区| 婷婷丁香激情综合| 91成人国产精品| 久久久久久亚洲综合影院红桃| 国产乱码精品1区2区3区| 精品粉嫩aⅴ一区二区三区四区| 视频一区国产视频| av中文一区二区三区| 中文字幕在线不卡国产视频| 99久久久精品| 亚洲第一成年网| 在线成人免费观看| 一区二区免费视频| 欧美日韩国产另类一区| 久久精品国产一区二区| 欧美大片免费久久精品三p| 久88久久88久久久| 一区二区三区美女| 精品欧美久久久| 91福利区一区二区三区| 一区二区欧美国产| 久久久久久夜精品精品免费| 国产原创一区二区| 亚洲欧洲日韩综合一区二区| 欧美在线不卡视频| 免费久久精品视频| 亚洲国产欧美另类丝袜| 欧美一级欧美三级| 91久久奴性调教| 国产精品456露脸| 午夜精品爽啪视频| 综合电影一区二区三区 | 欧美一区二区三区日韩| 久久国产精品99精品国产| 午夜精彩视频在线观看不卡| 中文字幕中文乱码欧美一区二区| 欧美女孩性生活视频| 91美女片黄在线观看| 国产一区二区三区久久久| 午夜激情一区二区三区| 亚洲尤物在线视频观看| 亚洲激情五月婷婷| 亚洲成人黄色小说| 国产精品久久久久四虎| 久久精品男人的天堂| 精品电影一区二区三区| 精品99999| 国产精品伦一区| 国产丝袜美腿一区二区三区| 亚洲精品在线一区二区| 国产日韩av一区| 17c精品麻豆一区二区免费| 专区另类欧美日韩| 无吗不卡中文字幕| 国产sm精品调教视频网站| 色久优优欧美色久优优| 制服.丝袜.亚洲.另类.中文| 久久亚洲欧美国产精品乐播| 中文字幕一区二区三区在线不卡 | 免费看日韩精品| 精品制服美女久久| jiyouzz国产精品久久| 精品免费一区二区三区| 一区二区激情小说| 岛国精品在线观看| 91精品国产色综合久久不卡电影| 精品久久一区二区三区| 日韩影视精彩在线| 欧美亚洲综合色| 国产三级一区二区三区| 日韩电影在线一区| 欧美在线观看视频在线| 久久精品在线免费观看| 日本中文在线一区| 欧美年轻男男videosbes| 国产精品护士白丝一区av| 国产精品911| 欧美mv日韩mv国产网站app| 婷婷六月综合亚洲| 欧美日韩精品一区视频| 欧美精品一区二区三区很污很色的| 亚洲一区二区四区蜜桃| 在线免费不卡视频| 舔着乳尖日韩一区| 日韩精品在线看片z| 免费观看在线色综合| 久久亚洲一区二区三区四区| 激情亚洲综合在线| 日韩美女一区二区三区| 国产传媒一区在线| 欧美国产综合一区二区| 成人性色生活片免费看爆迷你毛片| 久久久久久9999| 高清不卡一二三区| 一区二区三区四区av| 欧美丰满少妇xxxxx高潮对白| 久久国产生活片100| 国产精品久久久久影院色老大| 日本二三区不卡| 国产一区二区在线影院| 亚洲乱码国产乱码精品精可以看 | 午夜免费欧美电影| 久久麻豆一区二区| 欧美日韩在线播| 色哟哟亚洲精品| 成人av动漫在线| 日韩在线一区二区| 亚洲线精品一区二区三区八戒| 欧美成人a∨高清免费观看| 国产69精品一区二区亚洲孕妇| 婷婷国产在线综合| 中文字幕中文字幕一区| 精品国产亚洲一区二区三区在线观看| 日韩成人一级大片| 亚洲美女视频一区| 在线看一区二区| 一本到三区不卡视频| 91麻豆免费看| 欧美综合色免费| 欧美绝品在线观看成人午夜影视| 一本大道久久精品懂色aⅴ| 成人激情黄色小说| 91视频91自| 91免费国产在线| 91麻豆精品久久久久蜜臀| 99re6这里只有精品视频在线观看 99re8在线精品视频免费播放 | 成人午夜伦理影院| 国内一区二区在线| 国产麻豆精品视频|