Openresty简单的动态修改upstream

1,217次阅读
没有评论

共计 2924 个字符,预计需要花费 8 分钟才能阅读完成。

Openresty简单的动态修改upstream

前面的文章曾提过动态修改代理,此处呢就记录下动态修改upstream,一个样例场景就是动态路由:根据一些请求特征(arg/header/cookie/ip等)将请求分流到不同upstream中

nginx动态修改proxy_pass

很久之前博主用nginx的reslover实现dns解析动态切换proxy_pass,使用该方式可以切任意一台后端,单仅仅是一台!此篇则要实现upstream后端组的切换,比如目前有两个upstream组

    upstream a_upstream {
                server 192.168.44.201:18081;
                server 192.168.44.202:18081;
    }
         
    upstream b_upstream {
                server 192.168.44.203:18081;
                server 192.168.44.204:18081;
    }

此时的location引流到a_upstream,如果要切流到b_upstream,那就需要更改proxy_pass指令内容并reload

        location / {
            proxy_next_upstream off;
            proxy_set_header    X-Real-IP           $remote_addr;
            proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
            proxy_set_header    Host                $host;
            proxy_http_version  1.1;
            proxy_set_header    Connection  "";
            proxy_pass          http://a_upstream;
        }

如果不想手动更改,则可以将proxy_pass指令值提取成变量如:proxy_pass http://$select_ups;在原生nginx中可以用set指令配合if做条件判断实现修改a_upstream,或者用map指令映射。

        location / {
                if ($remoter_addr ~ ^192.168.[0-9]{1,3}.[0-9]{1,3}$){
                   set $select_ups b_upstream;
                } 
                proxy_pass http://a_upstream;
        }

使用openresty的lua进行动态upstream处理

简单样例

此处则使用lua来做逻辑判断并选择upstream,此时就需要用到set_by_lua*指令

        location / {
            set_by_lua_block $select_ups {
                local iputils = require("resty.iputils")
                iputils.enable_lrucache()
                local internal_ips = {
                    "192.168.44.0/24",
                }
                local internal_list = iputils.parse_cidrs(internal_ips)
                local res, err = iputils.ip_in_cidrs(ngx.var.remote_addr, internal_list)
                if not res then
                    ngx.log(ngx.INFO, "ip is from internet: ", err)
                    return "a_upstream"
                    
                end
                return "b_upstream"
                }
            proxy_pass http://$select_ups;
        }

客户APP端自定义upstream

上面例子是根据请求特征自动分流,如果不想自动控制,想手动控制动态修改则可以修改判断逻辑,引入自定义变量进行判断:

  • 使用lua_shared_dict定义一个全局(所有worker进程)共享区域内存用于存储变量
  • 一个switch_ups接口,用于修改全局变量值
    lua_shared_dict ups_shm 1m;
    upstream a_upstream {
                server 192.168.44.201:18081;
                server 192.168.44.202:18081;
    }
         
    upstream b_upstream {
                server 192.168.44.203:18081;
                server 192.168.44.204:18081;
    }

    upstream c_upstream {
                server 192.168.44.205:18081;
                server 192.168.44.206:18081;
    }

switch_ups切换upstream接口

        location = /switch_ups {
             access_by_lua_file lua/ip_acl.lua;
             content_by_lua_block {
                    local ups = ngx.req.get_uri_args()["upstream"]
                    if ups == nil or ups == "" then
                        ngx.say("upstream is nil 1")
                        return nil
                    end
                    local myups_shm = ngx.shared.ups_shm
                    --- 此处以remote_addr为key,从而实现为每个client设置ups
                    local ups_src = myups_shm:get(ngx.var.remote_addr)
                    ngx.say("Current upstream is :", ups_src)
                    ngx.log(ngx.WARN, host, " change upstream from ", ups_src, " to ", ups)
                    local succ, err, forcible = myups_shm:set(ngx.var.remote_addr,  ups)
                    ngx.say(host, " change upstream from ", ups_src, " to ", ups)
            }
        }

代理location

        location / {
            set_by_lua_block $select_ups {
                local ups = ngx.shared.ups_shm:get(ngx.var.remote_addr)
                if ups ~= nil then
                    ngx.log(ngx.WARN, "get [", ups,"] from ngx.shared")
                    return a_upstream
                end
                return ups
            }
 
            proxy_next_upstream off;
            proxy_set_header    X-Real-IP           $remote_addr;
            proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
            proxy_set_header    Host                $host;
            proxy_http_version  1.1;
            proxy_set_header    Connection  "";
            proxy_pass          http://$my_upstream ;
        }

目前client可以根据remote_addr进行绑定upstream,从而实现自主选择upstream,若未配置,则走默认upstream

# 来自113.12.23.156的client
curl http://www.xadocker.cn/switch_ups?upstream=b_upstream

# 来自84.12.23.156的client
curl http://www.xadocker.cn/switch_ups?upstream=c_upstream

正文完
 
xadocker
版权声明:本站原创文章,由 xadocker 2021-11-20发表,共计2924字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)