OpenResty 反向代理的用法與技巧

jopen 8年前發布 | 14K 次閱讀 OpenResty Web服務器

OpenResty中使用反向代理

導語:

Nginx 最開始是作為反向代理被熟知的,基于它的 OpenResty 的自然也是支持反向代理的,下面我們就來看看它的一些基本用法以及在使用過程中的一些技巧。

一、基本用法

在業務環境中,可能會將OpenResty(以后簡稱OR)作為反向代理,根據不同的location定位到不同的后端,在這樣的架構下,對應的反向代理配置可能是這樣的:

location /upstream_A {
    proxy_pass http://192.168.1.100:8080;
    proxy_connect_timeout 2s;
    ...
}
location /upstream_B {
    proxy_pass http://192.168.1.110:8080;
    proxy_connect_timeout 2s;
    ...
}

可以看到這部分的配置和Nginx并沒有太大差別,但是這樣的配置會有一些問題,比如我們需要切換后端服務器,將upstream_A這個location的流量打到192.168.1.120這個上游地址而不用修改配置或者重啟Nginx服務,大部分人可能會選擇通過域名的方式去定位上游比如用如下配置:

location /upstream_A {
    proxy_pass http://domain_for_upstream_A:8080;
    proxy_connect_timeout 2s;
    ...
}
location /upstream_B {
    proxy_pass http://domain_for_upstream_B:8080;
    proxy_connect_timeout 2s;
    ...
}

當需要做_上游切換_的時候,通過修改 /etc/host 文件來將域名定向到新的Ip,但不幸的是,Ngixn并不會使用/etc/host 而是使用命令resolver來指定DNS服務器,那么在OR里面有沒有一些高階的用法可以讓上游漂移變得簡單呢?答案是肯定的,下面就來看看更加方便的用法,以及里面的坑。

二、進階用法

上面呢我們講到如何使用OR(其實就用到了Nginx的配置啦)來完成反向代理,但是由于Ip或者域名寫死,而Nginx又不支持host,所以在做上游平滑遷移的時候不是很方便,所以我們可以通過在上游配置中用Nginx變量來代替上游的地址,變可以避免上述問題。

location /internet_prxoy {
    internal;
    set_by_lua $query_url 'return ngx.unescape_uri(ngx.var.arg_url);'    proxy_pass $query_url;    
}
location /upstream_A {
    content_by_lua '
        local redis_op   = require "lua.redis_op"
        local upstream_addr = redis_op.get_upstream_from_redis() -- 從redis中獲取上游地址
        local url  = 'http://'..  upstream_addr .. '/foo/bar'
        local res = ngx.location.capture('/internet_proxy',
            { args = {url = url}}
           )
           --容錯判斷
        ngx.print(res.body)
    ';
}

這樣,當請求訪問到/upstream_A的時候,會在redis當中讀取到上游服務器的真實地址并通過/internet_prxoy轉發到上游。

看到這里有人可能會問,為什么需要配置一個額外的跳轉location,而不直接在set_by_lua階段訪問redis并對Nginx變量進行賦值?

原因是函數get_upstream_from_redis會涉及到redis的訪問,而 lua-resty-redis 使用了 ngx.socket.tcp 這個函數,這個函數所支持的執行階段不包括_set_階段,需要我們需要一次跳轉,通過第一次location的content階段從redis中將數據讀取出來,在第二個location的set階段利用剛才所讀取的數據完成反向代理。

需要注意的是如果第一次location,(也就是上述代碼中的/upstream_A)的流量非常高,那么可以在redis的訪問函數,也就是上述代碼中的get_upstream_from_redis()函數中用shared.dict來做一次緩存,減少對redis的訪問量也是可行的。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!