[PATCH]upstream server directive support variable

flygoast flygoast at 126.com
Sun Jun 2 01:34:58 UTC 2013


Hi, guys


In my business, I need dynamicly  to find the backend ip address according to the request. However, I also want to use the upstream to take advantage of load balance. So I add the variable support in server directive. For sake of avoiding blocking the whole worker due to resolving domain, at present, only dotted decimal  IP address should be parsed in
the variables. Anyone can help to check or improve it? Thanks. 


The patch is based on 1.2.7.


diff -ruNp nginx-1.2.7/src/http/ngx_http_upstream.c nginx-1.2.7.m/src/http/ngx_http_upstream.c
--- nginx-1.2.7/src/http/ngx_http_upstream.c2013-02-11 22:39:49.000000000 +0800
+++ nginx-1.2.7.m/src/http/ngx_http_upstream.c2013-05-27 20:33:17.000000000 +0800
@@ -4220,8 +4220,9 @@ ngx_http_upstream_server(ngx_conf_t *cf,
     ngx_str_t                   *value, s;
     ngx_url_t                    u;
     ngx_int_t                    weight, max_fails;
-    ngx_uint_t                   i;
+    ngx_uint_t                   i, n;
     ngx_http_upstream_server_t  *us;
+    ngx_http_script_compile_t    sc;
 
     if (uscf->servers == NULL) {
         uscf->servers = ngx_array_create(cf->pool, 4,
@@ -4245,13 +4246,32 @@ ngx_http_upstream_server(ngx_conf_t *cf,
     u.url = value[1];
     u.default_port = 80;
 
-    if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
-        if (u.err) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "%s in upstream \"%V\"", u.err, &u.url);
+    n = ngx_http_script_variables_count(&value[1]);
+
+    if (n) {
+        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+        sc.cf = cf;
+        sc.source = &value[1];
+        sc.lengths = &us->proxy_lengths;
+        sc.values = &us->proxy_values;
+        sc.variables = n;
+        sc.complete_lengths = 1;
+        sc.complete_values = 1;
+
+        if (ngx_http_script_compile(&sc) != NGX_OK) {
+            return NGX_CONF_ERROR;
         }
 
-        return NGX_CONF_ERROR;
+    } else {
+        if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
+            if (u.err) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "%s in upstream \"%V\"", u.err, &u.url);
+            }
+    
+            return NGX_CONF_ERROR;
+        }
     }
 
     weight = 1;
@@ -4333,8 +4353,15 @@ ngx_http_upstream_server(ngx_conf_t *cf,
         goto invalid;
     }
 
-    us->addrs = u.addrs;
-    us->naddrs = u.naddrs;
+    if (n) {
+        us->addrs = NULL;
+        us->naddrs = 1;
+
+    } else {
+        us->addrs = u.addrs;
+        us->naddrs = u.naddrs;
+    }
+
     us->weight = weight;
     us->max_fails = max_fails;
     us->fail_timeout = fail_timeout;
diff -ruNp nginx-1.2.7/src/http/ngx_http_upstream.h nginx-1.2.7.m/src/http/ngx_http_upstream.h
--- nginx-1.2.7/src/http/ngx_http_upstream.h2012-02-13 19:01:58.000000000 +0800
+++ nginx-1.2.7.m/src/http/ngx_http_upstream.h2013-05-27 20:38:58.000000000 +0800
@@ -91,6 +91,9 @@ typedef struct {
     ngx_uint_t                       max_fails;
     time_t                           fail_timeout;
 
+    ngx_array_t                     *proxy_lengths;
+    ngx_array_t                     *proxy_values;
+
     unsigned                         down:1;
     unsigned                         backup:1;
 } ngx_http_upstream_server_t;
@@ -116,6 +119,8 @@ struct ngx_http_upstream_srv_conf_s {
     ngx_uint_t                       line;
     in_port_t                        port;
     in_port_t                        default_port;
+    ngx_uint_t                       variable_peer;
+    ngx_uint_t                       variable_backup;
 };
 
 
diff -ruNp nginx-1.2.7/src/http/ngx_http_upstream_round_robin.c nginx-1.2.7.m/src/http/ngx_http_upstream_round_robin.c
--- nginx-1.2.7/src/http/ngx_http_upstream_round_robin.c2013-02-11 22:56:14.000000000 +0800
+++ nginx-1.2.7.m/src/http/ngx_http_upstream_round_robin.c2013-05-27 20:59:49.000000000 +0800
@@ -78,9 +78,19 @@ ngx_http_upstream_init_round_robin(ngx_c
                     continue;
                 }
 
-                peers->peer[n].sockaddr = server[i].addrs[j].sockaddr;
-                peers->peer[n].socklen = server[i].addrs[j].socklen;
-                peers->peer[n].name = server[i].addrs[j].name;
+                if (server[i].addrs == NULL) {
+                    us->variable_peer++;
+                    peers->peer[n].sockaddr = NULL;
+                    peers->peer[n].socklen = 0;
+                    ngx_str_null(&peers->peer[n].name);
+                    peers->peer[n].server = &server[i];
+
+                } else {
+                    peers->peer[n].sockaddr = server[i].addrs[j].sockaddr;
+                    peers->peer[n].socklen = server[i].addrs[j].socklen;
+                    peers->peer[n].name = server[i].addrs[j].name;
+                }
+
                 peers->peer[n].max_fails = server[i].max_fails;
                 peers->peer[n].fail_timeout = server[i].fail_timeout;
                 peers->peer[n].down = server[i].down;
@@ -136,9 +146,20 @@ ngx_http_upstream_init_round_robin(ngx_c
                     continue;
                 }
 
-                backup->peer[n].sockaddr = server[i].addrs[j].sockaddr;
-                backup->peer[n].socklen = server[i].addrs[j].socklen;
-                backup->peer[n].name = server[i].addrs[j].name;
+                if (server[i].addrs == NULL) {
+                    us->variable_backup++;
+                    backup->peer[n].sockaddr = NULL;
+                    backup->peer[n].socklen = 0;
+                    ngx_str_null(&backup->peer[n].name);
+                    backup->peer[n].server = &server[i];
+
+                } else {
+
+                    backup->peer[n].sockaddr = server[i].addrs[j].sockaddr;
+                    backup->peer[n].socklen = server[i].addrs[j].socklen;
+                    backup->peer[n].name = server[i].addrs[j].name;
+                }
+
                 backup->peer[n].weight = server[i].weight;
                 backup->peer[n].effective_weight = server[i].weight;
                 backup->peer[n].current_weight = 0;
@@ -228,6 +249,73 @@ ngx_http_upstream_cmp_servers(const void
 }
 
 
+static ngx_int_t
+ngx_http_upstream_get_round_robin_variable_peer(ngx_http_request_t *r,
+    ngx_http_upstream_rr_peers_t *peers, ngx_uint_t variable_cnt)
+{
+    ngx_uint_t                         i, j, n;
+    ngx_url_t                          url;
+    ngx_http_upstream_rr_peer_t       *peer;
+
+    n = peers->number;
+
+    for (i = 0, j = 0; j < variable_cnt && i < n; i++) {
+
+        peer = &peers->peer[i];
+
+        if (peer->server) {
+
+            peer->sockaddr = NULL;
+            peer->socklen = 0;
+            ngx_str_null(&peer->name);
+
+            if (ngx_http_script_run(r, &peer->name, 
+                                    peer->server->proxy_lengths->elts, 0,
+                                    peer->server->proxy_values->elts)
+                == NULL)
+            {
+                return NGX_ERROR;
+            }
+
+            ngx_memzero(&url, sizeof(ngx_url_t));
+            url.url = peer->name;
+            url.default_port = 80;
+            url.no_resolve = 1;
+
+            if (ngx_parse_url(r->pool, &url) != NGX_OK) {
+                if (url.err) {
+                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                                  "%s in upstream \"%V\"", url.err, &url.url);
+                }
+
+                return NGX_ERROR;
+            }
+
+            url.one_addr = 1;
+            if (url.no_port) {
+                url.port = url.default_port;
+            }
+
+            if (ngx_inet_resolve_host(r->pool, &url) != NGX_OK) {
+                if (url.err) {
+                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                                  "%s in upstream \"%V\"", url.err, &url.url);
+                }
+
+                return NGX_ERROR;
+            }
+
+            peer->sockaddr = url.addrs[0].sockaddr;
+            peer->socklen = url.addrs[0].socklen;
+
+            j++;
+        }
+    }
+
+    return NGX_OK;
+}
+
+
 ngx_int_t
 ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
     ngx_http_upstream_srv_conf_t *us)
@@ -251,6 +339,25 @@ ngx_http_upstream_init_round_robin_peer(
 
     n = rrp->peers->number;
 
+    if (us->variable_peer > 0) {
+        if (ngx_http_upstream_get_round_robin_variable_peer(r, rrp->peers,
+                                                            us->variable_peer)
+            == NGX_ERROR)
+        {
+            return NGX_ERROR;
+        }
+    }
+
+    if (us->variable_backup > 0) {
+        if (ngx_http_upstream_get_round_robin_variable_peer(r, 
+                                                            rrp->peers->next,
+                                                            us->variable_backup)
+            == NGX_ERROR)
+        {
+            return NGX_ERROR;
+        }
+    }
+
     if (rrp->peers->next && rrp->peers->next->number > n) {
         n = rrp->peers->next->number;
     }
diff -ruNp nginx-1.2.7/src/http/ngx_http_upstream_round_robin.h nginx-1.2.7.m/src/http/ngx_http_upstream_round_robin.h
--- nginx-1.2.7/src/http/ngx_http_upstream_round_robin.h2012-07-03 00:41:13.000000000 +0800
+++ nginx-1.2.7.m/src/http/ngx_http_upstream_round_robin.h2013-05-24 13:57:52.000000000 +0800
@@ -18,6 +18,7 @@ typedef struct {
     struct sockaddr                *sockaddr;
     socklen_t                       socklen;
     ngx_str_t                       name;
+    ngx_http_upstream_server_t     *server;
 
     ngx_int_t                       current_weight;
     ngx_int_t                       effective_weight;

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20130602/c7594ec5/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: nginx-1.2.7-upstream.patch
Type: application/octet-stream
Size: 9256 bytes
Desc: not available
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20130602/c7594ec5/attachment-0001.obj>


More information about the nginx-devel mailing list