This blog introduces some Nginx+Lua solutions used in company projects; OpenResty could achieve the same effects.
Total Traffic Limiting (Circuit Breaking) for an Interface
Some friends may think of Nginx’s built-in limit_req feature to limit access frequency. That approach is usually IP-based, meant to prevent users from maliciously flooding requests.
What I want to introduce here is another situation: the interface’s qps is already very high and the backend cannot accept more requests. At this point what’s needed is rate limiting for the entire interface.
localfunctionsafe_incr(dict, key, timeout) local ok local newval, err = dict:incr(key, 1) ifnot newval and err == "not found"then newval = 1 ok, err = dict:safe_add(key, newval, timeout) ifnot ok then if err == "exists"then newval, err = dict:incr(key, 1) elseif err == "no memory"then dict:add(key .. "|no memory", 0, timeout) end end end return newval end
For ordinary websites, https redirection is usually implemented with rewrite, like the configuration below:
1 2 3 4 5 6 7 8 9 10
server { listen80; ... return301 https://$server_name$request_uri; }
server { listen443; ... }
Such configuration only suits the outermost Nginx. If it’s not placed at the entry Nginx users access,
you’ll get a circular redirection problem like the one shown below.
So for multi-layer Nginx situations, the simplest solution is doing the https redirection at the first-layer Nginx and using http traffic internally.
But consider the following situation:
Moreover, for a PaaS platform, not all applications want forced https, and the first-layer Nginx isn’t controlled by us —
but it passes us a header like this indicating the request is https: X-Forwarded-Proto: https.
At this time a more suitable choice is adding request-method judgment in the platform’s own Nginx layer. Based on the header’s forwarded-proto, there are two ways to solve it in the middle layer:
server { listen80; add_header Strict-Transport-Security "max-age=31536000" always; # using lua makes the logic clearer rewrite_by_lua_block { local _request_uri = ngx.var.request_uri local _host = ngx.var.host if ngx.var.http_x_forwarded_proto == nil or ngx.var.http_x_forwarded_proto == 'http' then return ngx.redirect('https://'.._host.._request_uri, ngx.HTTP_MOVED_PERMANENTLY) end } // location xxx }
Since our project already used Nginx+Lua, we adopted the second solution directly. If you use plain Nginx, just use the if statement.