[Nginx] this is the most comprehensive article to achieve load balancing, flow limiting, caching, black-and-white list and gray-scale publishing!

Write in front

In< [high concurrency] the interviewer asked me how to use Nginx to limit the current, and I got the Offer easily! >In this article, we mainly introduced how to use Nginx for current limiting to avoid the system being overwhelmed by large flow. In addition, Nginx has many powerful functions, such as load balancing, caching, black-and-white lists, grayscale publishing, etc. Today, let's discuss these powerful functions supported by Nginx!

Nginx installation

Note: take CentOS 6.8 server as an example. Install Nginx as root.

1. installation dependent environment

yum -y install wget gcc-c++ ncurses ncurses-devel cmake make perl bison openssl openssl-devel gcc* libxml2 libxml2-devel curl-devel libjpeg* libpng* freetype* autoconf automake zlib* fiex* libxml* libmcrypt* libtool-ltdl-devel* libaio libaio-devel  bzr libtool

2. install openssl

wget https://www.openssl.org/source/openssl-1.0.2s.tar.gz
tar -zxvf openssl-1.0.2s.tar.gz
cd /usr/local/src/openssl-1.0.2s
./config --prefix=/usr/local/openssl-1.0.2s
make
make install

3. install pcre

wget https://ftp.pcre.org/pub/pcre/pcre-8.43.tar.gz
tar -zxvf pcre-8.43.tar.gz
cd /usr/local/src/pcre-8.43
./configure --prefix=/usr/local/pcre-8.43
make
make install

4. install zlib

wget https://sourceforge.net/projects/libpng/files/zlib/1.2.11/zlib-1.2.11.tar.gz
tar -zxvf zlib-1.2.11.tar.gz
cd /usr/local/src/zlib-1.2.11
./configure --prefix=/usr/local/zlib-1.2.11
make
make

5. install Nginx

wget http://nginx.org/download/nginx-1.17.2.tar.gz
tar -zxvf nginx-1.17.2.tar.gz
cd /usr/local/src/nginx-1.17.2
./configure --prefix=/usr/local/nginx-1.17.2 --with-openssl=/usr/local/src/openssl-1.0.2s --with-pcre=/usr/local/src/pcre-8.43 --with-zlib=/usr/local/src/zlib-1.2.11 --with-http_ssl_module
make
make install

It should be noted that when installing Nginx, the source code decompression directories of openssl, pcre and zlib are specified. The full path of the Nginx configuration file after installation is: /usr/local/Nginx-1.17.2/conf/Nginx Conf.

Nginx load balancing configuration

1. load balancing configuration

http {
       ......
    upstream real_server {
       server 192.168.103.100:2001 weight=1;  #Polling servers and access weights
       server 192.168.103.100:2002 weight=2;
    }
 
    server {
        listen  80;
 
        location / {
            proxy_pass http://real_server;
        }
    }
}

2. failed retry configuration

upstream real_server {
   server 192.168.103.100:2001 weight=1 max_fails=2 fail_timeout=60s;
   server 192.168.103.100:2002 weight=2 max_fails=2 fail_timeout=60s;
}

It means fail_timeout failed Max_ After failures requests, the upstream server is considered unavailable, and the service address is kicked out. Fail_ After the timeout time, the server will be added to the survival list again for retry.

Nginx current limiting configuration

1. configuration parameters

limit_req_zone instruction setting parameters

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
  • Limit_ Req_ The zone is defined in the http block, $binary_remote_addr means to save the binary form of the client IP address.
  • Zone defines the shared memory area for IP status and URL access frequency. zone=keyword identifies the name of the zone and the size of the zone followed by a colon. The status information of 16000 IP addresses is about 1MB, so the region in the example can store 160000 IP addresses.
  • Rate defines the maximum request rate. The rate in the example cannot exceed 10 requests per second.

2. set current limit

location / {
        limit_req zone=mylimit burst=20 nodelay;
        proxy_pass http://real_server;
}

burst queue size. nodelay does not limit the time between individual requests.

3. unlimited white list

geo $limit {
default              1;
192.168.2.0/24  0;
}
 
map $limit $limit_key {
1 $binary_remote_addr;
0 "";
}
 
limit_req_zone $limit_key zone=mylimit:10m rate=1r/s;
 
location / {
        limit_req zone=mylimit burst=1 nodelay;
        proxy_pass http://real_server;
}

In the above configuration, the IP access of the 192.168.2.0/24 network segment is not limited to current, and other current is limited.

The meaning of the numbers after IP:

  • 24 indicates subnet mask: 255.255.255.0
  • 16 indicates subnet mask: 255.255.0.0
  • 8 indicates subnet mask: 255.0.0.0

Nginx cache configuration

1. browser cache

expire for static resource cache

location ~*  .(jpg|jpeg|png|gif|ico|css|js)$ {
   expires 2d;
}

Expires and cache control are added to the Response Header,

Static resources include (general cache)

  • Common and unchanging images, such as logo, icon, etc
  • js, css static files
  • Downloadable content, media files

Negotiation cache (add_header ETag/Last-Modified value)

  • HTML file
  • Frequently replaced pictures
  • Frequently modified js and css files
  • Basically unchanged API interface

No cache required

  • User privacy and other sensitive data
  • Frequently changing api data interfaces

2. proxy layer cache

//Cache path. inactive indicates the cache time. After expiration, the cache will be cleaned up
proxy_cache_path /data/cache/nginx/ levels=1:2 keys_zone=cache:512m inactive = 1d max_size=8g;
 
location / {
    location ~ \.(htm|html)?$ {
        proxy_cache cache;
        proxy_cache_key    $uri$is_args$args;     //HASH with this variable value as KEY
        //The X-Cache field can be seen in the header of the HTTP response. The contents can include hit, miss, express, etc
        add_header X-Cache $upstream_cache_status;
        proxy_cache_valid 200 10m;
        proxy_cache_valid any 1m;
        proxy_pass  http://real_server;
        proxy_redirect     off;
    }
    location ~ .*\.(gif|jpg|jpeg|bmp|png|ico|txt|js|css)$ {
        root /data/webapps/edc;
        expires      3d;
        add_header Static Nginx-Proxy;
    }
}

Create a file directory on the local disk. According to the settings, the requested resources are cached in this directory in the form of K-V. the KEY needs to be defined by itself (the hash value of the url is used here). At the same time, you can specify the cache duration of a certain content as needed, such as 10 minutes for the cache with the status code of 200, 5 minutes for the cache with the status code of 301302, and 1 minute for all other content.
You can clean up the cache through the function of purger.

The browser cache should be disabled during AB test / personalization requirements.

Nginx blacklist

1. general configuration

location / {
    deny  192.168.1.1;
    deny 192.168.1.0/24;
    allow 10.1.1.0/16;
    allow 2001:0db8::/32;
    deny  all;
}

2. Lua+Redis dynamic blacklist (OpenResty)

Installation and operation

yum install yum-utils
yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
yum install openresty
yum install openresty-resty
 check
yum --disablerepo="*" --enablerepo="openresty" list available
 working
service openresty start

Configuration (/usr/local/openresty/nginx/conf/nginx.conf)

lua_shared_dict ip_blacklist 1m;
 
server {
    listen  80;
 
    location / {
        access_by_lua_file lua/ip_blacklist.lua;
        proxy_pass http://real_server;
    }
}

Lua script (ip_blacklist.lua)

local redis_host    = "192.168.1.132"
local redis_port    = 6379
local redis_pwd     = 123456
local redis_db = 2
 
-- connection timeout for redis in ms.
local redis_connection_timeout = 100
 
-- a set key for blacklist entries
local redis_key     = "ip_blacklist"
 
-- cache lookups for this many seconds
local cache_ttl     = 60
 
-- end configuration
 
local ip                = ngx.var.remote_addr
local ip_blacklist      = ngx.shared.ip_blacklist
local last_update_time  = ip_blacklist:get("last_update_time");
 
-- update ip_blacklist from Redis every cache_ttl seconds:
if last_update_time == nil or last_update_time < ( ngx.now() - cache_ttl ) then
 
  local redis = require "resty.redis";
  local red = redis:new();
 
  red:set_timeout(redis_connect_timeout);
 
  local ok, err = red:connect(redis_host, redis_port);
  if not ok then
    ngx.log(ngx.ERR, "Redis connection error while connect: " .. err);
  else
    local ok, err = red:auth(redis_pwd)
    if not ok then
      ngx.log(ngx.ERR, "Redis password error while auth: " .. err);
    else
        local new_ip_blacklist, err = red:smembers(redis_key);
        if err then
            ngx.log(ngx.ERR, "Redis read error while retrieving ip_blacklist: " .. err);
        else
        ngx.log(ngx.ERR, "Get data success:" .. new_ip_blacklist)
          -- replace the locally stored ip_blacklist with the updated values:
            ip_blacklist:flush_all();
          for index, banned_ip in ipairs(new_ip_blacklist) do
            ip_blacklist:set(banned_ip, true);
          end
          -- update time
          ip_blacklist:set("last_update_time", ngx.now());
      end
    end
  end
end
 
if ip_blacklist:get(ip) then
  ngx.log(ngx.ERR, "Banned IP detected and refused access: " .. ip);
  return ngx.exit(ngx.HTTP_FORBIDDEN);
end

Nginx grayscale Publishing

1. realize grayscale publishing according to cookies

Query the version value according to the Cookie. If the version value is v1, forward to host1, and v2, forward to host2. If they do not match, forward to the default configuration.

upstream host1 {
   server 192.168.2.46:2001 weight=1;  #Polling servers and access weights
   server 192.168.2.46:2002 weight=2;
}
 
upstream host2 {
   server 192.168.1.155:1111  max_fails=1 fail_timeout=60;
}
 
upstream default {
   server 192.168.1.153:1111  max_fails=1 fail_timeout=60;
}
 
map $COOKIE_version $group {
   ~*v1$ host1;
   ~*v2$ host2;
   default default;
}
 
lua_shared_dict ip_blacklist 1m;
 
server {
    listen  80;
 
    #set $group "default";
    #if ($http_cookie ~* "version=v1"){
    #    set $group host1;
    #}
    #if ($http_cookie ~* "version=v2"){
    #    set $group host2;
    #}
 
    location / {
        access_by_lua_file lua/ip_blacklist.lua;
        proxy_pass http://$group;
    }
}

2. realize gray-scale publishing according to the incoming IP

server {
  ...............
  set $group default;
  if ($remote_addr ~ "192.168.119.1") {
      set $group host1;
  }
  if ($remote_addr ~ "192.168.119.2") {
      set $group host2;
  }

3. more fine grained grayscale Publishing

Reference: https://github.com/sunshinelyz/ABTestingGateway

OK, let's stop here today! Don't forget to read and forward it to others, so that more people can see it, learn and progress together!!

Write at the end

If you think binghe's written well, please search on wechat and pay attention to the "binghe technology" wechat official account to learn from binghe about high concurrency, distribution, micro services, big data, Internet and cloud native technologies. The "binghe technology" wechat official account has updated a large number of technical topics, and each technical article is full of dry goods! Many readers have successfully switched to big factories by reading the wechat official account article of "ice river technology" and hanging interviewers; Many readers have also achieved a technological leap and become the technical backbone of the company! If you want to improve your ability, achieve a leap in technical ability, enter a large factory, get promoted and get a raise, then pay attention to the wechat official account of "ice river technology" and update the dry goods of super hard core technology every day, so that you will no longer be confused about how to improve your technical ability!

Tags: Nginx Cache Load Balance

Posted by ouch! on Mon, 30 May 2022 12:28:50 +0530